#ifndef MpsAnalysisSource_HH
#define MpsAnalysisSource_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 "MpsSensor1HitLists.hh"

#include "MpsAnalysisBase.hh"


class MpsAnalysisSource : public MpsAnalysisBase {

public:
  MpsAnalysisSource() : MpsAnalysisBase("MpsAnalysisSource"),
			_wOld((const MpsLocationData<MpsUsbDaqBunchTrainData>*)_buffer) {
  }


  virtual ~MpsAnalysisSource() {
    endRoot();
  }

  virtual bool mpsAnalysisValidRun(IlcRunType::Type t) const {
    return (t==IlcRunType::mpsSource || t==IlcRunType::mpsSourceThresholdScan);
  }

  bool runStart(const RcdRecord &r) {
    std::ifstream fin("badOld.txt");
    unsigned reg,row,grp;
    while(fin) {
      fin >> reg >> row >> grp;
      if(fin) {
	_vBadRow[reg].push_back(row);
	_vBadGrp[reg].push_back(grp);
      }
    }

    for(unsigned region(0);region<4;region++) {
      std::cout << "Region " << region << ", number of bad posns = " << _vBadRow[region].size() << std::endl;
    }

    _hTNum=new TH1F("hTNum","Number of tags",
		    100,0.0,100.0);
    _hTime=new TH1F("hTime","Timestamps of tags",
		    8200,0.0,8200.0);

    return true;
  }  

  bool configurationStart(const RcdRecord &r) {
    SubAccessor accessor(r);

    for(unsigned region(0);region<4;region++) {
      _nHist[region]=_vThreshold[region].size();

      for(unsigned i(0);i<_vThreshold[region].size();i++) {
	//std::cout << "Existing threshold value " << i << " for region " << region << " = "
	//	  << _vThreshold[region][i] << std::endl;
	if(_vThreshold[region][i]==_vPcbConfigurationData[0].regionThresholdValue(region)) _nHist[region]=i;
      }

      if(_nHist[region]==_vThreshold[region].size()) {
	std::cout << "New threshold value for region " << region << " found = "
		  << _vPcbConfigurationData[0].regionThresholdValue(region) << std::endl;

	_vThreshold[region].push_back(_vPcbConfigurationData[0].regionThresholdValue(region));

	std::ostringstream slab;
	slab << _cfgLabel << "Region" << region;
	
	std::ostringstream stit;
	stit << _runTitle << ", Region " << region << ", Threshold "
	     << _vPcbConfigurationData[0].regionThresholdValue(region);
	
	_vHDiff[0][region].push_back(new TH1F((slab.str()+"DiffInt").c_str(),
					      (stit.str()+", Timestamp difference").c_str(),
					      16000,-8000.0,8000.0));
	_vHDiff[1][region].push_back(new TH1F((slab.str()+"DiffOut").c_str(),
					      (stit.str()+", Timestamp difference to previous bunch train").c_str(),
					      16000,-8000.0,8000.0));
	_vHDiff[2][region].push_back(new TH1F((slab.str()+"DiffRnd").c_str(),
					      (stit.str()+", Timestamp difference to random times").c_str(),
					      16000,-8000.0,8000.0));

	_vHRows[region].push_back(new TH1F((slab.str()+"Rows").c_str(),
					   (stit.str()+", All hit rows").c_str(),
					   168,0.0,168.0));
	_vHRwgd[0][region].push_back(new TH1F((slab.str()+"RwgdInt").c_str(),
					      (stit.str()+", Good hit rows in time").c_str(),
					      168,0.0,168.0));
	_vHRwgd[1][region].push_back(new TH1F((slab.str()+"RwgdOut").c_str(),
					      (stit.str()+", Good hit rows out of time").c_str(),
					      168,0.0,168.0));
	_vHRwgd[2][region].push_back(new TH1F((slab.str()+"RwgdRnd").c_str(),
					      (stit.str()+", Good hit rows random time").c_str(),
					      168,0.0,168.0));
	
	_vHGrup[region].push_back(new TH1F((slab.str()+"Grup").c_str(),
					   (stit.str()+", All hit groups").c_str(),
					   7,0.0,7.0));
	_vHGrgd[0][region].push_back(new TH1F((slab.str()+"GrgdInt").c_str(),
					      (stit.str()+", Good hit groups in time").c_str(),
					      7,0.0,7.0));
	_vHGrgd[1][region].push_back(new TH1F((slab.str()+"GrgdOut").c_str(),
					      (stit.str()+", Good hit groups out of time").c_str(),
					      7,0.0,7.0));
	_vHGrgd[2][region].push_back(new TH1F((slab.str()+"GrgdRnd").c_str(),(stit.str()+", Good hit groups random time").c_str(),
					      7,0.0,7.0));
	
	_vHPosn[region].push_back(new TH1F((slab.str()+"Posn").c_str(),
					   (stit.str()+", All hit positions").c_str(),
					   168*7,0.0,168*7.0));
	_vHPsgd[0][region].push_back(new TH1F((slab.str()+"PsgdInt").c_str(),
					      (stit.str()+", Good hit positions in time").c_str(),
					      168*7,0.0,168*7.0));
	_vHPsgd[1][region].push_back(new TH1F((slab.str()+"PsgdOut").c_str(),
					      (stit.str()+", Good hit positions out of time").c_str(),
					      168*7,0.0,168*7.0));
	_vHPsgd[2][region].push_back(new TH1F((slab.str()+"PsgdRnd").c_str(),
					      (stit.str()+", Good hit positions random time").c_str(),
					      168*7,0.0,168*7.0));

	_vHThit[region].push_back(new TH1F((slab.str()+"Thit").c_str(),
					   (stit.str()+", All hit timestamps").c_str(),
					   8200,0.0,8200.0));
	_vHThgd[0][region].push_back(new TH1F((slab.str()+"ThgdInt").c_str(),
					      (stit.str()+", Good hit timestamps in time").c_str(),
					      8200,0.0,8200.0));
	_vHThgd[1][region].push_back(new TH1F((slab.str()+"ThgdOut").c_str(),
					      (stit.str()+", Good hit timestamps out of time").c_str(),
					      8200,0.0,8200.0));
	_vHThgd[2][region].push_back(new TH1F((slab.str()+"ThgdRnd").c_str(),
					      (stit.str()+", Good hit timestamps random time").c_str(),
					      8200,0.0,8200.0));
      }
    }

    return true;
  }

  bool bunchTrain(const RcdRecord &r) {
    SubAccessor accessor(r);
    
    std::vector<const MpsLocationData<MpsUsbDaqBunchTrainData>* >
      w(accessor.access< MpsLocationData<MpsUsbDaqBunchTrainData> >());
    assert(w.size()==1);
    if(doPrint(r.recordType(),1)) w[0]->print(std::cout) << std::endl;
    
    _hTNum->Fill(w[0]->data()->numberOfTags());
    
    const MpsUsbDaqBunchTrainDatum *q(w[0]->data()->data());
    for(unsigned k(0);k<w[0]->data()->numberOfTags();k++) {
      _hTime->Fill(q[k].timeStamp());

      //if(q[k].timeStamp()==0) {
      //  vb[0]->print(std::cout,"ZERO ");
      //  q[k].print(std::cout,"ZERO ") << std::endl;
      //}
    }
    
    
    if(_bunchTrain.bunchTrainNumberInConfiguration()>0) {
      
      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++) {
	const MpsSensor1BunchTrainDatum *p(v[0]->data()->regionData(region));
	for(unsigned j(0);j<v[0]->data()->numberOfRegionHits(region);j++) {
	  
	  bool badCh(false);
	  for(unsigned i(0);i<_vBadRow[region].size() && !badCh;i++) {
	    badCh=(_vBadRow[region][i]==p[j].row() && _vBadGrp[region][i]==p[j].group());
	  }
	  
	  //if(p[j].timeStamp()>19 && p[j].row()==50) {
	  //if(region<2 || p[j].timeStamp()>0) { // Exclude bad ones
	  //if(!badCh && p[j].timeStamp()>499) {
	  if(!badCh && p[j].timeStamp()>499) {
	  //if(true) {
	    
	    
	    
	    
	    
	    bool goodHit[3]={false,false,false};
	    
	    q=w[0]->data()->data();
	    for(unsigned k(0);k<w[0]->data()->numberOfTags();k++) {
	      //if(q[k].timeStamp()>0) {
	      if(true) {
		
		int diff((int)(p[j].timeStamp())-(int)(q[k].timeStamp()));
		_vHDiff[0][region][_nHist[region]]->Fill(diff);
		//_vHDiff2[region][_nHist[region]]->Fill(diff,p[j].timeStamp()+q[k].timeStamp());
		
		if(diff>1 && diff<5) {
		  goodHit[0]=true;
		  if(doPrint(r.recordType(),1)) {
		    q[k].print(std::cout,"DIFF ");
		    p[j].print(std::cout,"DIFF ") << std::endl;
		  }
		}
	      }
	    }
	    
	    
	    q=_wOld->data()->data();
	    for(unsigned k(0);k<_wOld->data()->numberOfTags();k++) {
	      //if(q[k].timeStamp()>0) {
	      if(true) {
		
		int diff((int)p[j].timeStamp()-(int)q[k].timeStamp());
		_vHDiff[1][region][_nHist[region]]->Fill(diff);
		
		if(diff>1 && diff<5) {
		  goodHit[1]=true;
		}
	      }
	    }
	    
	    
	    q=w[0]->data()->data();
	    for(unsigned k(0);k<w[0]->data()->numberOfTags();k++) {
	      //if(q[k].timeStamp()>0) {
	      if(true) {
		
		for(unsigned r(0);r<16;r++) {
		  int diff((int)p[j].timeStamp()-(int)(rand()%(_vUsbDaqConfigurationData[0].spillCycleCount()+1)));
		  _vHDiff[2][region][_nHist[region]]->Fill(diff,1.0/16.0);
		  
		  if(r==0) {
		    if(diff>1 && diff<5) {
		      goodHit[2]=true;
		    }
		  }
		}
	      }
	    }
	    
	    
	    _vHThit[region][_nHist[region]]->Fill(p[j].timeStamp());
	    _vHRows[region][_nHist[region]]->Fill(p[j].row());
	    _vHGrup[region][_nHist[region]]->Fill(p[j].group());
	    _vHPosn[region][_nHist[region]]->Fill(p[j].row()+168*p[j].group());
	    
	    for(unsigned r(0);r<3;r++) {
	      if(goodHit[r]) {
		_vHThgd[r][region][_nHist[region]]->Fill(p[j].timeStamp());
		_vHRwgd[r][region][_nHist[region]]->Fill(p[j].row());
		_vHGrgd[r][region][_nHist[region]]->Fill(p[j].group());
		_vHPsgd[r][region][_nHist[region]]->Fill(p[j].row()+168*p[j].group());
	      }
	    }
	  }
	}
      }
    }
    
    memcpy(_buffer,w[0],sizeof(MpsLocationData<MpsUsbDaqBunchTrainData>)+4*w[0]->data()->numberOfTags());
    return true;
  }
  

  void endRoot() {
    if(_rootFile!=0) {
      std::ofstream fout("bad.txt");
      for(unsigned region(0);region<4;region++) {
	double ent(_vHPosn[region][0]->GetEntries());
	for(unsigned i(0);i<7*168;i++) {
	  if(_vHPosn[region][0]->GetBinContent(i+1)>0.005*ent) {
	    std::cout << "Region " << region << ", posn " << i
		      << " hits = " << _vHPosn[region][0]->GetBinContent(i+1)
		      << ", ent = " << ent << std::endl;
	    fout << region << " " << i%168 << " " << i/168 << std::endl;
	  }
	}      
      }
      fout.close();

      MpsAnalysisBase::endRoot();
    }
  }


private:
  unsigned char _buffer[4*1024];
  const MpsLocationData<MpsUsbDaqBunchTrainData>* _wOld;

  std::vector<unsigned> _vBadRow[4];
  std::vector<unsigned> _vBadGrp[4];

  TH1F* _hTNum;
  TH1F* _hTime;

  unsigned _nHist[4];
  std::vector<int> _vThreshold[4];

  std::vector<TH1F*> _vHDiff[3][4];
  //std::vector<TH1F*> _vHDiff2[4];
  std::vector<TH1F*> _vHRows[4];
  std::vector<TH1F*> _vHRwgd[3][4];
  std::vector<TH1F*> _vHGrup[4];
  std::vector<TH1F*> _vHGrgd[3][4];
  std::vector<TH1F*> _vHPosn[4];
  std::vector<TH1F*> _vHPsgd[3][4];
  std::vector<TH1F*> _vHThit[4];
  std::vector<TH1F*> _vHThgd[3][4];
};

#endif
