#ifndef EmcMap_HH
#define EmcMap_HH

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

#include "UtlPrintHex.hh"
#include "EmcPhysicalPad.hh"
#include "EmcReadoutPad.hh"


class EmcMap {

public:
  EmcMap() {
    reset();

    /*
    for(unsigned s(12);s<18;s+=5) {
      for(unsigned f(1);f<6;f++) {
	for(unsigned c(0);c<12;c++) {
	  for(unsigned m(0);m<18;m++) {
	    EmcReadoutPad r(s,f,c,m);

	    unsigned z(0);
	    if(s==12 && f==1) z=2;
	    if(s==12 && f==2) z=3;
	    if(s==12 && f==3) z=4;
	    if(s==12 && f==4) z=5;
	    if(s==12 && f==5) z=1;//!?
	    if(s==17 && f==1) z=6;
	    if(s==17 && f==2) z=7;
	    if(s==17 && f==3) z=8;
	    if(s==17 && f==4) z=9;
	    if(s==17 && f==5) z=0;//!?

	    unsigned x=3*(c%6)+(m%3);
	    unsigned y=6*(c/6)-(m/3)+5;
	    if((z%2)==1) y=11-y;
	    y+=6;

	    EmcPhysicalPad p(x,y,z);
	    map(p,r);
	  }
	}
      }
    }
    */
  }

  void reset() {
    memset(this,0xff,sizeof(EmcMap));
  }

  void map(EmcPhysicalPad p, EmcReadoutPad r) {
    assert(r.value()<22*8*12*18);
    assert(p.value()<18*18*30);

    _physical[r.value()]=p;
    _readout[p.value()]=r;
  }

  void map(EmcReadoutPad r, EmcPhysicalPad p) {
    map(p,r);
  }

  EmcPhysicalPad map(EmcReadoutPad r) const {
    assert(r.value()<22*8*12*18);
    return _physical[r.value()];
  }

  EmcReadoutPad map(EmcPhysicalPad p) const {
    assert(p.value()<18*18*30);
    return _readout[p.value()];
  }

  bool physical(EmcReadoutPad r) const {
    assert(r.value()<22*8*12*18);
    return _physical[r.value()].value()!=0xffff;
  }

  bool readout(EmcPhysicalPad p) const {
    assert(p.value()<18*18*30);
    return _readout[p.value()].value()!=0xffff;
  }

  std::ostream& print(std::ostream &o, std::string s="") const {
    o << s << "EmcMap::print()" << std::endl;

    for(unsigned z(0);z<30;z++) {
      for(unsigned y(0);y<18;y++) {
	for(unsigned x(0);x<18;x++) {
	  EmcPhysicalPad pp(x,y,z);
	  if(readout(pp)) {
	    o << s << " X,Y,Z " << std::setw(3) << x << std::setw(3) << y << std::setw(3) << z 
	      << " = S,F,C,M "
	      << std::setw(3) << _readout[18*(18*z+y)+x].slot()
	      << std::setw(3) << _readout[18*(18*z+y)+x].frontend()
	      << std::setw(3) << _readout[18*(18*z+y)+x].chip()
	      << std::setw(3) << _readout[18*(18*z+y)+x].channel() << std::endl;
	  }
	}
      }
    }

    return o;
  }

  /*
  bool write(std::string fileName) const {
    std::cout << "EmcMap::write()  Opening " << fileName << std::endl;
    std::ofstream o(fileName.c_str());
    return write(o);
  }

  bool write(std::ostream &o) const {
    for(unsigned i(0);i<18*18*30;i++) {
      o << std::setw(4) << i << " "
        << _pedestal[i] << " "
        << _linear[i] << " "
        << _quadratic[i] << " "
        << _threshold[i] << " " << std::endl;
    }
    return true;
  }
  */

  bool read(std::string fileName) {
    std::cout << "EmcMap::read()  Opening " << fileName << std::endl;
    std::ifstream i(fileName.c_str(),std::ios::in);
    if(!i) return false;
    return read(i);
  }

  bool read(std::istream &i) {
    reset();

    std::string comment;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;
    i >> comment;
    std::cout << "EmcMap::read()  " << comment << std::endl;

    unsigned s,f,b,l,a;
    i >> s;

    while(i) {
      assert(s<=21);
      i >> f >> b >> l >> a >> comment;
      assert(f<8 && b<2 && l<30 && a<2);

      // Check LH/RH PCB only in LH/RH connector; NEEDS CHECKING!!!
      if(a==0) assert(b!=(l%2));
      
      unsigned cLo(0),cHi(12);

      // If half PCB, then restrict channel range; NEEDS CHECKING!!!
      if(a==0) {
	if(b==0) cHi=6;
	else     cLo=6;
      }

      for(unsigned c(cLo);c<cHi;c++) {
	for(unsigned m(0);m<18;m++) {
	  EmcReadoutPad r(s,f,c,m);

	  // Calculate the local numbering on the PCB
	  unsigned x=3*(c%6)+(m%3);
	  unsigned y=6*(c/6)-(m/3)+5;

	  // Global y depends on which way up the PCB is
	  if((l%2)==1) y=6*a+5-y;

	  // Central alveoli are offset in y
	  y+=6*a;
	  
	  EmcPhysicalPad p(x,y,l);
	  map(p,r);
	}
      }

      if(!i) return false;

      i >> s;
    }

    //i.close();
    return true;
  }



private:
  EmcPhysicalPad _physical[22*8*12*18];
  EmcReadoutPad _readout[18*18*30];
};

#endif
