#ifndef MpsAnalysisBeamThresholdScan_HH
#define MpsAnalysisBeamThresholdScan_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"
#include "MpsSensor1HitLists.hh"


class MpsAnalysisBeamThresholdScan : public MpsAnalysisBase {

public:
  MpsAnalysisBeamThresholdScan() :
    MpsAnalysisBase("MpsAnalysisBeamThresholdScan") {
  }

  virtual ~MpsAnalysisBeamThresholdScan() {
    endRoot();
  }

  virtual bool mpsAnalysisValidRun(IlcRunType::Type t) const {
    return t==IlcRunType::mpsBeam    || t==IlcRunType::mpsBeamThresholdScan ||
           t==IlcRunType::mpsCosmics || t==IlcRunType::mpsCosmicsThresholdScan;
  }

  bool runStart(const RcdRecord &r) {
    _hX[0]=new TH2F("Sensors01X","Sensor 0 vs 1 X",168,0.0,168.0,168,0.0,168.0);
    _hX[1]=new TH2F("Sensors02X","Sensor 0 vs 2 X",168,0.0,168.0,168,0.0,168.0);
    _hX[2]=new TH2F("Sensors03X","Sensor 0 vs 3 X",168,0.0,168.0,168,0.0,168.0);
    _hX[3]=new TH2F("Sensors12X","Sensor 1 vs 2 X",168,0.0,168.0,168,0.0,168.0);
    _hX[4]=new TH2F("Sensors13X","Sensor 1 vs 3 X",168,0.0,168.0,168,0.0,168.0);
    _hX[5]=new TH2F("Sensors23X","Sensor 2 vs 3 X",168,0.0,168.0,168,0.0,168.0);

    _hXd[0]=new TH1F("Sensors01Xd","Sensor 0-1 X",100,-50.0,50.0);
    _hXd[1]=new TH1F("Sensors02Xd","Sensor 0-2 X",100,-50.0,50.0);
    _hXd[2]=new TH1F("Sensors03Xd","Sensor 0-3 X",100,-50.0,50.0);
    _hXd[3]=new TH1F("Sensors12Xd","Sensor 1-2 X",100,-50.0,50.0);
    _hXd[4]=new TH1F("Sensors13Xd","Sensor 1-3 X",100,-50.0,50.0);
    _hXd[5]=new TH1F("Sensors23Xd","Sensor 2-3 X",100,-50.0,50.0);

    _hY[0]=new TH2F("Sensors01Y","Sensor 0 vs 1 Y",168,0.0,168.0,168,0.0,168.0);
    _hY[1]=new TH2F("Sensors02Y","Sensor 0 vs 2 Y",168,0.0,168.0,168,0.0,168.0);
    _hY[2]=new TH2F("Sensors03Y","Sensor 0 vs 3 Y",168,0.0,168.0,168,0.0,168.0);
    _hY[3]=new TH2F("Sensors12Y","Sensor 1 vs 2 Y",168,0.0,168.0,168,0.0,168.0);
    _hY[4]=new TH2F("Sensors13Y","Sensor 1 vs 3 Y",168,0.0,168.0,168,0.0,168.0);
    _hY[5]=new TH2F("Sensors23Y","Sensor 2 vs 3 Y",168,0.0,168.0,168,0.0,168.0);

    _hYd[0]=new TH1F("Sensors01Yd","Sensor 0-1 Y",100,-50.0,50.0);
    _hYd[1]=new TH1F("Sensors02Yd","Sensor 0-2 Y",100,-50.0,50.0);
    _hYd[2]=new TH1F("Sensors03Yd","Sensor 0-3 Y",100,-50.0,50.0);
    _hYd[3]=new TH1F("Sensors12Yd","Sensor 1-2 Y",100,-50.0,50.0);
    _hYd[4]=new TH1F("Sensors13Yd","Sensor 1-3 Y",100,-50.0,50.0);
    _hYd[5]=new TH1F("Sensors23Yd","Sensor 2-3 Y",100,-50.0,50.0);

    _hT[0]=new TH2F("Sensors01T","Sensor 0 vs 1 T",80,0.0,8000.0,80,0.0,8000.0);
    _hT[1]=new TH2F("Sensors02T","Sensor 0 vs 2 T",80,0.0,8000.0,80,0.0,8000.0);
    _hT[2]=new TH2F("Sensors03T","Sensor 0 vs 3 T",80,0.0,8000.0,80,0.0,8000.0);
    _hT[3]=new TH2F("Sensors12T","Sensor 1 vs 2 T",80,0.0,8000.0,80,0.0,8000.0);
    _hT[4]=new TH2F("Sensors13T","Sensor 1 vs 3 T",80,0.0,8000.0,80,0.0,8000.0);
    _hT[5]=new TH2F("Sensors23T","Sensor 2 vs 3 T",80,0.0,8000.0,80,0.0,8000.0);

    _hTd[0]=new TH1F("Sensors01Td","Sensor 0-1 T",100,-50.0,50.0);
    _hTd[1]=new TH1F("Sensors02Td","Sensor 0-2 T",100,-50.0,50.0);
    _hTd[2]=new TH1F("Sensors03Td","Sensor 0-3 T",100,-50.0,50.0);
    _hTd[3]=new TH1F("Sensors12Td","Sensor 1-2 T",100,-50.0,50.0);
    _hTd[4]=new TH1F("Sensors13Td","Sensor 1-3 T",100,-50.0,50.0);
    _hTd[5]=new TH1F("Sensors23Td","Sensor 2-3 T",100,-50.0,50.0);

    for(unsigned s(0);s<4;s++) {
      for(unsigned x(0);x<168;x++) {
	for(unsigned y(0);y<168;y++) {
	  _hitCount[s][x][y]=0;
	}
      }
    }

    _hHitCount[0]=new TH2F("HitCountSensor0","Sensor 0 Hit counts",168,0.0,168.0,168,0.0,168.0);
    _hHitCount[1]=new TH2F("HitCountSensor1","Sensor 1 Hit counts",168,0.0,168.0,168,0.0,168.0);
    _hHitCount[2]=new TH2F("HitCountSensor2","Sensor 2 Hit counts",168,0.0,168.0,168,0.0,168.0);
    _hHitCount[3]=new TH2F("HitCountSensor3","Sensor 3 Hit counts",168,0.0,168.0,168,0.0,168.0);

    _hHitNumber[0]=new TH1F("HitNumberSensor0","Sensor 0 Number of hits/pixel",100,0.0,100.0);
    _hHitNumber[1]=new TH1F("HitNumberSensor1","Sensor 1 Number of hits/pixel",100,0.0,100.0);
    _hHitNumber[2]=new TH1F("HitNumberSensor2","Sensor 2 Number of hits/pixel",100,0.0,100.0);
    _hHitNumber[3]=new TH1F("HitNumberSensor3","Sensor 3 Number of hits/pixel",100,0.0,100.0);


    /*
      std::ostringstream slab;
      slab << "Pmt";

      std::ostringstream stit;
      stit << _runTitle << ", PMT ";

      _PmtHits[0]=new HstCfgScan("Pmt0Hits",
				 "Number of PMT 0 hits",
				 100,0.0,100.0);
      
      _PmtHits[1]=new HstCfgScan("Pmt1Hits",
				 "Number of PMT 1 hits",
				 100,0.0,100.0);

      _PmtHits[2]=new HstCfgScan("PmtCHits",
				 "Number of PMT coincidences",
				 100,0.0,100.0);

      _3Hits=new HstCfgScan((slab.str()+"3Hits").c_str(),
			 (stit.str()+", Number of 3-hits").c_str(),
			    20,0.0,20.0);

      _4Hits=new HstCfgScan((slab.str()+"4Hits").c_str(),
			 (stit.str()+", Number of 4-hits").c_str(),
			    20,0.0,20.0);

      _PmtHits[0]->runStart(_runStart.runNumber());
      _PmtHits[1]->runStart(_runStart.runNumber());
      _PmtHits[2]->runStart(_runStart.runNumber());
      _3Hits->runStart(_runStart.runNumber());
      _4Hits->runStart(_runStart.runNumber());
    */
    return true;
  }

  bool runEnd(const RcdRecord &r) {
    endRoot();
    return true;
  }

  bool configurationStart(const RcdRecord &r) {
    /*
    _PmtHits[0]->configurationStart();
    _PmtHits[1]->configurationStart();
    _PmtHits[2]->configurationStart();
    _3Hits->configurationStart();
    _4Hits->configurationStart();
    */

    _skipCfg=false;
    for(unsigned s(0);s<_vLocation.size();s++) {
      if(_runStart.runNumber()==490043 && _vPcbConfigurationData[s].shaperThresholdValue()!=150) _skipCfg=true;
      if(_runStart.runNumber()==490084 && _vPcbConfigurationData[s].shaperThresholdValue()!=120) _skipCfg=true;
    }

    if(_skipCfg) std::cout << "Configuration " << _configurationStart.configurationNumberInRun() << " will be skipped" << std::endl;
    else         std::cout << "Configuration " << _configurationStart.configurationNumberInRun() << " will not be skipped" << std::endl;

    return true;
  }
  
  bool bunchTrain(const RcdRecord &r) {
    if(!_skipCfg) {

    SubAccessor accessor(r);

    bool goodHit[4][168][168];
    for(unsigned s(0);s<4;s++) {
      for(unsigned x(0);x<168;x++) {
	for(unsigned y(0);y<168;y++) {
	  goodHit[s][x][y]=false;
	}
      }
    }
    
    std::vector<const MpsLocationData<MpsSensor1BunchTrainData>* >
      w(accessor.access< MpsLocationData<MpsSensor1BunchTrainData> >());
    
    unsigned combo(0);
    //_hBnt[0].push_back(new TH1F(_bntLabel.c_str(),_bntTitle.c_str(),8000,0.0,8000.0));
    
    for(unsigned s0(0);s0<w.size();s0++) {
      if(doPrint(r.recordType(),1)) {
	w[s0]->print(std::cout," ") << std::endl;
      }
      assert(!w[s0]->usbDaqMaster());
      if(!w[s0]->usbDaqMaster()) {
	
	for(unsigned s1(s0+1);s1<w.size();s1++) {
	  assert(!w[s1]->usbDaqMaster());
	  if(!w[s1]->usbDaqMaster()) {
	    
	    for(unsigned region0(0);region0<4;region0++) {
	      const MpsSensor1BunchTrainDatum *p0(w[s0]->data()->regionData(region0));
	      for(unsigned j0(0);j0<w[s0]->data()->numberOfRegionHits(region0);j0++) {
		if(p0[j0].row()<168 && p0[j0].group()<7) {
		  int t0(p0[j0].timeStamp());
		  int y0(p0[j0].row());
		  if(_runStart.runNumber()==490043 && (s0==1 || s0==3)) y0=167-y0;
		  if(_runStart.runNumber()==490084 && (s0==1 || s0==3)) y0=167-y0;
		  
		  for(unsigned c0(0);c0<6;c0++) {
		    if(p0[j0].channel(c0)) {
		      int x0(42*region0+6*p0[j0].group()+c0);
		      if(_runStart.runNumber()==490043 && (s0==1 || s0==3)) x0=167-x0;
		      if(_runStart.runNumber()==490084 && (s0==1 || s0==3)) x0=167-x0;
		      
		      //if(combo==0) _hBnt[0][_hBnt[0].size()-1]->Fill(t0);
		      
		      for(unsigned region1(0);region1<4;region1++) {
			const MpsSensor1BunchTrainDatum *p1(w[s1]->data()->regionData(region1));
			for(unsigned j1(0);j1<w[s1]->data()->numberOfRegionHits(region1);j1++) {
			  if(p1[j1].row()<168 && p1[j1].group()<7) {
			    int t1(p1[j1].timeStamp());
			    int y1(p1[j1].row());
			    if(_runStart.runNumber()==490043 && (s1==1 || s1==3)) y1=167-y1;
			    if(_runStart.runNumber()==490084 && (s1==1 || s1==3)) y1=167-y1;
			    
			    int dy(y0-y1);
			    int dt(t0-t1);


			    dt+=10; // BACKGROUND!!!!


			    //if(dy>-100 && dy<100 && dt>-100 && dt<100) {
			    if(true) {
			      
			      for(unsigned c1(0);c1<6;c1++) {
				if(p1[j1].channel(c1)) {
				  int x1(42*region1+6*p1[j1].group()+c1);
				  if(_runStart.runNumber()==490043 && (s1==1 || s1==3)) x1=167-x1;
				  if(_runStart.runNumber()==490084 && (s1==1 || s1==3)) x1=167-x1;
				  
				  int dx(x0-x1);
				  
				  if(dy>-10 && dy<10 && dt>-1 && dt<1) {
				    _hX[combo]->Fill(x0,x1);
				    _hXd[combo]->Fill(dx);
				  }
				  if(dx>-10 && dx<10 && dt>-1 && dt<1) {
				    _hY[combo]->Fill(y0,y1);
				    _hYd[combo]->Fill(dy);
				  }
				  if(dx>-10 && dx<10 && dy>-10 && dy<10) {
				    _hT[combo]->Fill(t0,t1);
				    _hTd[combo]->Fill(dt);
				  }
				  
				  if(dx>-10 && dx<10 && dy>-10 && dy<10 && dt>-1 && dt<1) {
				    goodHit[s0][x0][y0]=true;
				    goodHit[s1][x1][y1]=true;
				  }
				}
			      }
			    }
			  }
			}
		      }
		    }
		  }
		}
	      }
	    }

	    combo++;
	  }
	}
      }
    }


    for(unsigned s(0);s<4;s++) {
      unsigned perSensor(0);
      for(unsigned x(0);x<168;x++) {
	for(unsigned y(0);y<168;y++) {
	  if(goodHit[s][x][y]) {
	    _hitCount[s][x][y]++;
	    perSensor++;
	  }
	}
      }
      //if(perSensor>1) std::cout << "Per sensor " << s << " = " << perSensor << std::endl;
    }

    /*
    unsigned n3(0),n4(0);
    for(unsigned t(0);t<8000;t++) {
      unsigned n(0);
      for(unsigned s(0);s<4;s++) {
	if(times[s][t]>0) n++;
      }
      if(n==3) n3++;
      if(n==4) n4++;
    }
    
    _3Hits->Fill(n3);
    _4Hits->Fill(n4);
    */

    /*
    unsigned np[3]={0,0,0};
    std::vector<const MpsLocationData<MpsUsbDaqBunchTrainData>* >
      v(accessor.access< MpsLocationData<MpsUsbDaqBunchTrainData> >());

    _hBnt[1].push_back(new TH1F((_bntLabel+"PMT").c_str(),(_bntTitle+", PMTs").c_str(),8000,0.0,8000.0));

    for(unsigned s(0);s<v.size();s++) {
      if(doPrint(r.recordType(),1)) v[s]->print(std::cout) << std::endl;

      const MpsUsbDaqBunchTrainDatum *q(v[s]->data()->data());
      for(unsigned k(0);k<v[s]->data()->numberOfTags();k++) {

	_hBnt[1][_hBnt[1].size()-1]->Fill(q[k].timeStamp(),q[k].channels());

	if(q[k].channel(0)) np[0]++;
	if(q[k].channel(1)) np[1]++;
	if(q[k].channel(0) && q[k].channel(1)) np[2]++;
      }
    }
    _PmtHits[0]->Fill(np[0]);
    _PmtHits[1]->Fill(np[1]);
    _PmtHits[2]->Fill(np[2]);
    */

    }
    return true;
  }

  void endRoot() {
    if(_rootFile!=0) {
      _rootFile->cd();

      std::ofstream fout("MpsAnalysisBeamThresholdScan.txt");
      for(unsigned s(0);s<4;s++) {
	for(unsigned x(0);x<168;x++) {
	  for(unsigned y(0);y<168;y++) {
	    if(_hitCount[s][x][y]>0) fout << s << " " << x << " " << y << " "
					  << _hitCount[s][x][y] << std::endl;
	    _hHitCount[s]->Fill(x,y,_hitCount[s][x][y]);
	    _hHitNumber[s]->Fill(_hitCount[s][x][y]);
	  }
	}
      }
      fout.close();

      /*
      _PmtHits[0]->runEnd();
      _PmtHits[1]->runEnd();
      _PmtHits[2]->runEnd();
      _3Hits->runEnd();
      _4Hits->runEnd();
      */
      MpsAnalysisBase::endRoot();
    }
  }


private:
  TH2F *_hX[6];
  TH1F *_hXd[6];
  TH2F *_hY[6];
  TH1F *_hYd[6];
  TH2F *_hT[6];
  TH1F *_hTd[6];

  unsigned _hitCount[4][168][168];
  TH2F *_hHitCount[4];
  TH1F *_hHitNumber[4];

  bool _skipCfg;

  /*
  HstCfgScan *_PmtHits[3];
  HstCfgScan *_3Hits;
  HstCfgScan *_4Hits;
  std::vector<TH1F*> _hBnt[2];
  */
};

#endif
