#ifndef MpsAnalysisHitOverride_HH
#define MpsAnalysisHitOverride_HH

#include <cassert>

#include "TFile.h"
#include "TF1.h"
#include "TH1F.h"
#include "TH2F.h"
#include "TProfile.h"

#include "RcdUserRO.hh"
#include "SubAccessor.hh"

#include "MpsAnalysisBase.hh"


class MpsAnalysisHitOverride : public MpsAnalysisBase {
  
public:
  MpsAnalysisHitOverride() : MpsAnalysisBase("MpsAnalysisHitOverride"),
			     _print(false) {

    // Zero all the counters
    for(unsigned s(0);s<4;s++) {
      for(unsigned i(0);i<4;i++) {
	_checkTotal[s][i]=0;
	for(unsigned j(0);j<32;j++) {
	  for(unsigned k(0);k<4;k++) {
	    _check[s][i][j][k]=0;
	  }
	}
	_zeroCheck[s][i]=0;
      }
    }
  }

  virtual ~MpsAnalysisHitOverride() {
    endRoot();
  }

  virtual bool mpsAnalysisValidRun(IlcRunType::Type t) const {
    return t==IlcRunType::mpsHitOverride;
  }

  bool runStart(const RcdRecord &r) {

    // Loop over sensors
    for(unsigned i(0);i<_vLocation.size();i++) {

      // Loop over regions
      for(unsigned region(0);region<4;region++) {

	std::ostringstream slab;
	slab << _sensorLabel[i] << "Region" << region;
	
	std::ostringstream stit;
	stit << _sensorTitle[i] << ", Region " << region << " Fraction of Bit Errors";
	
	_hRegion[i][region]=new TH2F(slab.str().c_str(),stit.str().c_str(),
				     8,0.0,8.0,
				     64,0.0,64.0);
      }
    }

    return true;
  }
  
  bool configurationStart(const RcdRecord &r) {
      
    _dependentValue=_configurationStart.configurationNumberInRun();
    std::cout << "Cfg " << _configurationStart.configurationNumberInRun()
	      << " dependent value = " << _dependentValue << std::endl;
    
    return true;
  }
  
  bool configurationEnd(const RcdRecord &r) {

    // Loop over sensors
    for(unsigned s(0);s<_vLocation.size();s++) {

      std::ostringstream sout;
      sout << "BitErrors" << _runLabel << _sensorLabel[s] << _cfgLabel << ".txt";
      
      std::ofstream fout(sout.str().c_str());
      fout << "1->1        1->0        0->0        0->1" << std::endl;
      
      double fraction;
      for(unsigned i(0);i<4;i++) {
	for(unsigned j(0);j<32;j++) {
	  if(j==0) fout << "Region " << i << " Bit " << std::setw(2) << j;
	  else     fout << "         Bit " << std::setw(2) << j;
	  
	  fout << std::setw(12) << _check[s][i][j][0] << std::setw(12) << _check[s][i][j][1];
	  if(_check[s][i][j][0]+_check[s][i][j][1]>0) fraction=(double)_check[s][i][j][1]/(double)(_check[s][i][j][0]+_check[s][i][j][1]);
	else                                  fraction=0.0;
	  fout << std::setw(12) << fraction;
	  
	  _hRegion[s][i]->Fill(_dependentValue,j   ,fraction);
	  
	  fout << std::setw(12) << _check[s][i][j][2] << std::setw(12) << _check[s][i][j][3];
	  if(_check[s][i][j][2]+_check[s][i][j][3]>0) fraction=(double)_check[s][i][j][3]/(double)(_check[s][i][j][2]+_check[s][i][j][3]);
	  else                                  fraction=0.0;
	  fout << std::setw(12) << fraction;
	  
	  _hRegion[s][i]->Fill(_dependentValue,j+32,fraction);
	  
	  fout << std::endl;
	}
	fout << " Number of zero channel hits " << std::setw(10)
	     << _zeroCheck[s][i] << std::endl << std::endl;
      }
      
      fout << " Total numbers of errors ";
      for(unsigned i(0);i<4;i++) {
	fout << std::setw(12) << _checkTotal[s][i];
      }
      fout << std::endl;
      
      for(unsigned i(0);i<4;i++) {
	_checkTotal[s][i]=0;
	for(unsigned j(0);j<32;j++) {
	  for(unsigned k(0);k<4;k++) {
	    _check[s][i][j][k]=0;
	  }
	}
	_zeroCheck[s][i]=0;
      }

      fout.close();
    }

    return true;
  }

  bool bunchTrain(const RcdRecord &r) {
    SubAccessor accessor(r);
    
    std::vector<const MpsLocationData<MpsSensor1BunchTrainData>* >
      v(accessor.access< MpsLocationData<MpsSensor1BunchTrainData> >());
    
    //unsigned groups[7]={5,2,3,4,7,1,6};
    //unsigned groups[7]={6,5,2,3,4,0,1};
    //unsigned groups[7]={5,4,3,2,1,0,6};
    unsigned groups[7]={4,3,2,1,0,6,5};
    
    for(unsigned i(0);i<v.size();i++) {
      //if(_print) v[i]->print(std::cout) << std::endl;
      
      unsigned iDatum(0);
      const MpsSensor1BunchTrainDatum *p(v[i]->data()->data());
      const UtlPack *u((const UtlPack*)p);
      
	for(unsigned region(0);region<4;region++) {
	  assert(v[i]->data()->numberOfRegionHits(region)<=19*168);
	  
	  for(unsigned j(0);j<v[i]->data()->numberOfRegionHits(region);j++) {
	    
	    // Set up the expected value
	    MpsSensor1BunchTrainDatum datum(0);
	    UtlPack &uatum(*((UtlPack*)(&datum)));
	    //unsigned &ustum(*((unsigned*)(&datum)));
	    
	    // Set "first datum" bit
	    if(j==0) datum.firstRegionDatum(true);

	    // Set row
	    datum.row(167-(j/19)); // V1.0
	    if(v[i]->sensorV11()) datum.row((167-(j/19))%84); // V1.1
	    //if(region==1 && (j/19)>83) uatum.bit(28,false);

	    //datum.row(p[iDatum].row());
	    //ustum>>=1;

	    // Set group
	    //if(groups[(j%19)%7]>0) datum.group(groups[(j%19)%7]);
	    //else                   datum.muxAddress(0);
	    datum.group(groups[(j%19)%7]);
	    
	    //bool zeroChannel(region>1 && (j%19)>12);
	    //if(!zeroChannel) uatum.bits(16,21,0x3f); // Assume all bits are one
	    //if(!zeroChannel) uatum.bits(16,21,p[iDatum].channels());// Ignor bits!
	    uatum.bits(16,21,0x3f); // Assume all bits are one
	    //uatum.bits(16,21,p[iDatum].channels());// Ignor bits!
	    
	    //if(region==1 && p[iDatum].channel(4)) uatum.bits(16,21,0x3d);


	    
	    datum.timeStamp(0);
	    if((j%19)<12) datum.timeStamp(1);
	    if((j%19)<5) datum.timeStamp(2);
	    /*
	      datum.timeStamp(5461);
	    if((j%19)<12) datum.timeStamp(5462);
	    if((j%19)<5) datum.timeStamp(5463);
	    */
	    
	    // Catch all-channels-zero error separately
	    //if(zeroChannel) _zeroCheck[region]++;
	    
	    /*
	    if((j%19)==0) 
	      std::cout << "Rows: " << std::setw(3) << j/19 << " "
			<< printHex((unsigned char)(datum.rowGray()&0xff)) << " "
			<< printHex((unsigned char)(p[iDatum].rowGray()&0xff)) << std::endl;
	    */

	    // Compare bit for bit with observed value
	    for(unsigned b(0);b<32;b++) {
	      if( uatum.bit(b) &&  u[iDatum].bit(b))  _check[i][region][b][0]++;
	      if( uatum.bit(b) && !u[iDatum].bit(b)) {_check[i][region][b][1]++;_checkTotal[i][region]++;}
	      if(!uatum.bit(b) && !u[iDatum].bit(b))  _check[i][region][b][2]++;
	      if(!uatum.bit(b) &&  u[iDatum].bit(b)) {_check[i][region][b][3]++;_checkTotal[i][region]++;}
	    }
	    
	    // If they differ at all, print out
	    if(_print || uatum!=u[iDatum]) {
	      std::cout << "Region " << region << ", hit " << j << std::endl;
	      std::cout << "Expected " << printHex(uatum) << std::endl;
	      std::cout << "Observed " << printHex(u[iDatum]) << std::endl;
	      datum.print(std::cout,"Expected ");
	      p[iDatum].print(std::cout,"Observed ") << std::endl;
	    }
	  
	    iDatum++;
	  }
	}
      }

    return true;
  }

private:
  bool _print;

  int _dependentValue;

  unsigned _check[4][4][32][4];
  unsigned _checkTotal[4][4];
  unsigned _zeroCheck[4][4];

  TH2F *_hRegion[4][4];
};

#endif
