#ifndef MpsAnalysisPcbConfigurationScan_HH
#define MpsAnalysisPcbConfigurationScan_HH

#include <cassert>

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

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


class MpsAnalysisPcbConfigurationScan : public RcdUserRO {

public:
  MpsAnalysisPcbConfigurationScan() {
  }

  virtual ~MpsAnalysisPcbConfigurationScan() {
    endRoot();
  }

  bool record(const RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "MpsAnalysisPcbConfigurationScan::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }

    SubAccessor accessor(r);

    switch (r.recordType()) {
  
    case RcdHeader::runStart: {
      std::vector<const IlcRunStart*>
        vs(accessor.access<IlcRunStart>());
      assert(vs.size()==1);
      
      _runStart=*(vs[0]);
      if(doPrint(r.recordType(),1)) _runStart.print(std::cout) << std::endl;

      _pcbConfigurationScan=(_runStart.runType().type()==IlcRunType::mpsPcbConfigurationScan);
      if(_pcbConfigurationScan) {

	_nDacSteps=_runStart.runType().version()+1;

	std::ostringstream sFile;
	sFile << "MpsAnalysisPcbConfigurationScan" << std::setfill('0') << std::setw(6)
	      << vs[0]-> runNumber() << ".root";
	if(doPrint(r.recordType())) std::cout << "Creating ROOT file " << sFile.str() << std::endl;
	_rootFile = new TFile(sFile.str().c_str(),"RECREATE");
	
	for(unsigned region(0);region<4;region++) {
	  std::ostringstream slab;
	  slab << "Region" << region;
	  
	  std::ostringstream stit;
	  stit << "Region " << region << " Number of hits/BX";
	  
	  /*
	  _hRegion[region][0]=new TH1F((std::string("h")+slab.str()+"HOTS0").c_str(),(stit.str()+", HitOverride, Timestamp 0").c_str(),
				       _nDacSteps*32,0.0,_nDacSteps*32.0);
	  */

	  _hRegion[region][0]=new     TH2F((std::string("h")+slab.str()+"HOTS0").c_str(),(stit.str()+", HitOverride, Timestamp 0").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0,50,0.0,500.0);
	  _pRegion[region][0]=new TProfile((std::string("p")+slab.str()+"HOTS0").c_str(),(stit.str()+", HitOverride, Timestamp 1").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  _hRegion[region][1]=new     TH2F((std::string("h")+slab.str()+"HOTS1").c_str(),(stit.str()+", HitOverride, Timestamp 0").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0,50,0.0,500.0);
	  _pRegion[region][1]=new TProfile((std::string("p")+slab.str()+"HOTS1").c_str(),(stit.str()+", HitOverride, Timestamp 1").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  _hRegion[region][2]=new     TH2F((std::string("h")+slab.str()+"NMTS0").c_str(),(stit.str()+", Normal Mode, Timestamp 0").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0,50,0.0,500.0);
	  _pRegion[region][2]=new TProfile((std::string("p")+slab.str()+"NMTS0").c_str(),(stit.str()+", Normal Mode, Timestamp 1").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  _hRegion[region][3]=new     TH2F((std::string("h")+slab.str()+"NMTS1").c_str(),(stit.str()+", Normal Mode, Timestamp 0").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0,50,0.0,500.0);
	  _pRegion[region][3]=new TProfile((std::string("p")+slab.str()+"NMTS1").c_str(),(stit.str()+", Normal Mode, Timestamp 1").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	}

	_hTemp=new TH2F("hTemp","Temperature vs configuration number",
			_nDacSteps*64,0.0,_nDacSteps*64.0,50,25.0,30.0);
	_pTemp=new TProfile("pTemp","Temperature vs configuration number",
			    _nDacSteps*64,0.0,_nDacSteps*64.0);

	  
      } else {
	if(doPrint(r.recordType(),1)) std::cout << "Run type is not mpsPcbConfigurationScan" << std::endl;
      }

      break;
    }
      
    case RcdHeader::runEnd: {
      if(_pcbConfigurationScan) {
	std::vector<const IlcRunEnd*>
	  ve(accessor.access<IlcRunEnd>());
	assert(ve.size()==1);
	if(doPrint(r.recordType(),1)) ve[0]->print(std::cout) << std::endl;
      }
	
      endRoot();
      break;
    }
  
    case RcdHeader::configurationStart: {
      if(_pcbConfigurationScan) {
	std::vector<const IlcConfigurationStart*>
	  vs(accessor.access<IlcConfigurationStart>());
	assert(vs.size()==1);
	if(doPrint(r.recordType(),1)) vs[0]->print(std::cout) << std::endl;
	
	_configurationStart=*(vs[0]);
	
	std::vector<const MpsLocationData<MpsUsbDaqConfigurationData>* >
	  w(accessor.access< MpsLocationData<MpsUsbDaqConfigurationData> >());
	assert(w.size()==2);
	if(doPrint(r.recordType(),2)) w[1]->print() << std::endl;
	_usbDaqConfigurationData=*(w[1]->data());
	_hitOverride=_usbDaqConfigurationData.hitOverride();

	
	std::vector<const MpsLocationData<MpsPcb1ConfigurationData>* >
	  v(accessor.access< MpsLocationData<MpsPcb1ConfigurationData> >());
	assert(v.size()==2);
	if(doPrint(r.recordType(),2)) v[1]->print() << std::endl;
	_pcbConfigurationData=*(v[1]->data());
	_nDac=_configurationStart.configurationNumberInRun()/(2*_nDacSteps);

	if(_configurationStart.configurationNumberInRun()==0) {
	  for(unsigned dac(0);dac<32;dac++) {
	    for(unsigned region(0);region<4;region++) {
	      std::ostringstream slab;
	      slab << "Region" << region;
	      
	      std::ostringstream stit;
	      stit << "Region " << region << " Number of hits/BX";
	      
	      std::ostringstream snum;
	      snum << std::setfill('0') << std::setw(2) << dac;
	      
	      unsigned dacLo(_pcbConfigurationData.dac(dac)-(2048/(2*_nDacSteps)));
	      if(dac!=0) dacLo-=1024;
	      unsigned dacHi(dacLo+2048);
	      
	      _pRegionDac[region][dac][0][0]=new TProfile((slab.str()+"Dac"+snum.str()+"NMTS0").c_str(),(stit.str()+", DAC "+snum.str()+", Normal TS0").c_str(),
							    _nDacSteps,dacLo,dacHi);
	      _pRegionDac[region][dac][0][1]=new TProfile((slab.str()+"Dac"+snum.str()+"NMTS1").c_str(),(stit.str()+", DAC "+snum.str()+", Normal TS1").c_str(),
							    _nDacSteps,dacLo,dacHi);
	      _pRegionDac[region][dac][1][0]=new TProfile((slab.str()+"Dac"+snum.str()+"HOTS0").c_str(),(stit.str()+", DAC "+snum.str()+", HitO TS0").c_str(),
							    _nDacSteps,dacLo,dacHi);
	      _pRegionDac[region][dac][1][1]=new TProfile((slab.str()+"Dac"+snum.str()+"HOTS1").c_str(),(stit.str()+", DAC "+snum.str()+", HitO TS1").c_str(),
							    _nDacSteps,dacLo,dacHi);
	    }
	  }
	}
      }

      break;
    }
  
    case RcdHeader::configurationEnd: {
      if(_pcbConfigurationScan) {
	std::vector<const IlcConfigurationEnd*>
	  ve(accessor.access<IlcConfigurationEnd>());
	assert(ve.size()==1);
	if(doPrint(r.recordType(),1)) ve[0]->print(std::cout) << std::endl;
      }

      break;
    }
  
    case RcdHeader::slowReadout: {
      if(_pcbConfigurationScan) {
	std::vector<const MpsLocationData<MpsPcb1SlowReadoutData>* >
	  x(accessor.access< MpsLocationData<MpsPcb1SlowReadoutData> >());
	assert(x.size()==1);
	if(doPrint(r.recordType(),1)) x[0]->print(std::cout) << std::endl;
	_hTemp->Fill(_configurationStart.configurationNumberInRun(),x[0]->data()->celcius());
	_pTemp->Fill(_configurationStart.configurationNumberInRun(),x[0]->data()->celcius());
      }
      break;
    }
  
    case RcdHeader::bunchTrain: {
      if(_pcbConfigurationScan) {
	std::vector<const IlcBunchTrain*>
	  vb(accessor.access<IlcBunchTrain>());
	assert(vb.size()==1);
	if(doPrint(r.recordType())) vb[0]->print() << std::endl;
	
	std::vector<const MpsLocationData<MpsSensor1BunchTrainData>* >
	  v(accessor.access< MpsLocationData<MpsSensor1BunchTrainData> >());
	assert(v.size()==1);
	if(doPrint(r.recordType(),1)) v[0]->print(std::cout) << std::endl;
	
	for(unsigned region(0);region<4;region++) {
	  unsigned maxHits(19*168);
	  if(_usbDaqConfigurationData.spillCycleCount()<2) maxHits=7*(_usbDaqConfigurationData.spillCycleCount()+1)*168;
	  assert(v[0]->data()->numberOfRegionHits(region)<=maxHits);
	  
	  const MpsSensor1BunchTrainDatum *p(v[0]->data()->regionData(region));

	  unsigned nHi[2]={0,0};
	  unsigned nLo[2]={0,0};
	  
	  for(unsigned j(0);j<v[0]->data()->numberOfRegionHits(region);j++) {
	    if(p[j].timeStamp()<2) {
	      for(unsigned i(0);i<6;i++) {
		if(p[j].channel(i)) nHi[p[j].timeStamp()]++;
		else                nLo[p[j].timeStamp()]++;
	      }
	    } else {
	      p[j].print(std::cout, "ERROR ");
	    }
	  }
	  
	  if(doPrint(r.recordType(),2)) std::cout << "Region " << region << ", nhi lo " << nHi[0]+nHi[1] << ", " << nLo[0]+nLo[1] << " sum = "
						  << nHi[0]+nHi[1]+nLo[0]+nLo[1]
						  << ", hits " << v[0]->data()->numberOfRegionHits(region)
						  << ", x6 = " << 6*v[0]->data()->numberOfRegionHits(region) << std::endl;
	  
	  if((_configurationStart.configurationNumberInRun()%2)==0) {
	    _hRegion[region][0]->Fill(_configurationStart.configurationNumberInRun()/2  ,nHi[0]);
	    _pRegion[region][0]->Fill(_configurationStart.configurationNumberInRun()/2  ,nHi[0]);
	    _hRegion[region][1]->Fill(_configurationStart.configurationNumberInRun()/2+1,nHi[1]);
	    _pRegion[region][1]->Fill(_configurationStart.configurationNumberInRun()/2+1,nHi[1]);
	  } else {
	    _hRegion[region][2]->Fill(_configurationStart.configurationNumberInRun()/2  ,nHi[0]);
	    _pRegion[region][2]->Fill(_configurationStart.configurationNumberInRun()/2  ,nHi[0]);
	    _hRegion[region][3]->Fill(_configurationStart.configurationNumberInRun()/2+1,nHi[1]);
	    _pRegion[region][3]->Fill(_configurationStart.configurationNumberInRun()/2+1,nHi[1]);
	  }
	  
	  unsigned ho(0);
	  if(_hitOverride) ho=1;
	  _pRegionDac[region][_nDac][ho][0]->Fill(_pcbConfigurationData.dac(_nDac),nHi[0]);
	  _pRegionDac[region][_nDac][ho][1]->Fill(_pcbConfigurationData.dac(_nDac),nHi[1]);
	}
	
	break;
      }
    }
      
  
    default: {
      break;
    }
    };

    return true;
  }

  void endRoot() {
    if(_rootFile!=0) {
      _rootFile->Write();
      _rootFile->Close();
      delete _rootFile;
      _rootFile=0;
    }
  }


private:
  IlcRunStart _runStart;
  IlcConfigurationStart _configurationStart;

  bool _pcbConfigurationScan;
  unsigned _nDacSteps;

  MpsUsbDaqConfigurationData _usbDaqConfigurationData;
  MpsPcb1ConfigurationData _pcbConfigurationData;
  bool _hitOverride;
  unsigned _nDac;

  TFile* _rootFile;
  TH2F *_hRegion[4][4];
  TProfile *_pRegion[4][4];
  TProfile *_pRegionDac[4][32][2][2];
  TH2F *_hTemp;
  TProfile *_pTemp;
};

#endif
