#ifndef MpsAnalysis_HH
#define MpsAnalysis_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 MpsAnalysis : public RcdUserRO {

public:
  MpsAnalysis() {
  }

  virtual ~MpsAnalysis() {
    endRoot();
  }

  bool record(const RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "MpsAnalysis::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())) _runStart.print(std::cout) << std::endl;

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

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

	std::ostringstream sFile;
	sFile << "MpsAnalysisPcbConfigurationTest" << 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";
	  
	  std::cout << slab.str() << ", " << stit.str() << std::endl;
	  
	  _pRegion[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);

	  _pRegion[region][0]=new TProfile((slab.str()+"HOTS0").c_str(),(stit.str()+", HitOverride, Timestamp 0").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  _pRegion[region][1]=new TProfile((slab.str()+"HOTS1").c_str(),(stit.str()+", HitOverride, Timestamp 1").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  _pRegion[region][2]=new TProfile((slab.str()+"NMTS0").c_str(),(stit.str()+", Normal Mode, Timestamp 0").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  _pRegion[region][3]=new TProfile((slab.str()+"NMTS1").c_str(),(stit.str()+", Normal Mode, Timestamp 1").c_str(),
					   _nDacSteps*32,0.0,_nDacSteps*32.0);
	  
	  for(unsigned dac(0);dac<32;dac++) {
	    std::ostringstream snum;
	    snum << std::setfill('0') << std::setw(2) << dac;
	    
	    _pRegionDac[region][dac][0]=new TProfile((slab.str()+"Dac"+snum.str()+"Hi").c_str(),(stit.str()+", DAC "+snum.str()+", Hi").c_str(),
						     _nDacSteps,0.0,_nDacSteps);
	    _pRegionDac[region][dac][1]=new TProfile((slab.str()+"Dac"+snum.str()+"Lo").c_str(),(stit.str()+", DAC "+snum.str()+", Lo").c_str(),
						     _nDacSteps,0.0,_nDacSteps);
	  }
	}

      } else {
	if(doPrint(r.recordType())) 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())) 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())) 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())) 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())) v[1]->print() << std::endl;
	_pcbConfigurationData=*(v[1]->data());
	_nDac=_configurationStart.configurationNumberInRun()/(2*_nDacSteps);
      }

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

      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[iDatum].timeStamp()<2) {
	      for(unsigned i(0);i<6;i++) {
		if(p[iDatum].channel(i)) nHi[p[iDatum].timeStamp()]++;
		else                     nLo[p[iDatum].timeStamp()]++;
	      }
	    }
	    iDatum++;
	  }
	  
	  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) {
	    _pRegion[region][0]->Fill(_configurationStart.configurationNumberInRun()/2  ,nHi[0]);
	    _pRegion[region][1]->Fill(_configurationStart.configurationNumberInRun()/2+1,nHi[1]);
	  } else {
	    _pRegion[region][2]->Fill(_configurationStart.configurationNumberInRun()/2  ,nHi[0]);
	    _pRegion[region][3]->Fill(_configurationStart.configurationNumberInRun()/2+1,nHi[1]);
	  }
	  
	  _pRegionDac[region][_configurationStart.configurationNumberInRun()/_nDacSteps][0]->Fill(_configurationStart.configurationNumberInRun()%_nDacSteps,0.5*(nHi[0]+nHi[1]));
	  _pRegionDac[region][_configurationStart.configurationNumberInRun()/_nDacSteps][1]->Fill(_configurationStart.configurationNumberInRun()%_nDacSteps,0.5*(nLo[0]+nLo[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;
  TH1F *_hRegion[4][4];
  TProfile *_pRegion[4][4];
  TProfile *_pRegionDac[4][32][2];
};

#endif
