#ifndef MpsAnalysisLaser_HH
#define MpsAnalysisLaser_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 MpsAnalysisLaser : public MpsAnalysisBase {

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


  virtual ~MpsAnalysisLaser() {
    endRoot();
  }

  virtual bool mpsAnalysisValidRun(IlcRunType::Type t) const {
    return (t==IlcRunType::mpsLaserPosition ||
	    t==IlcRunType::mpsLaserPositionScan ||
	    t==IlcRunType::mpsLaserThreshold ||
	    t==IlcRunType::mpsLaserThresholdScan);
  }

  bool runStart(const RcdRecord &r) {
    _position=(_runStart.runType().type()==IlcRunType::mpsLaserPosition ||
	       _runStart.runType().type()==IlcRunType::mpsLaserPositionScan);

    SubAccessor accessor(r);

    std::vector<const MpsLaserRunData*>
      v(accessor.access<MpsLaserRunData>());
    assert(v.size()==1);
    if(doPrint(r.recordType(),1)) v[0]->print(std::cout) << 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);
    _hTChn=new TH1F("hTime","Channels of tags",
		    16,0.0,16.0);

    return true;
  }  

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

    std::vector<const MpsLaserConfigurationData*>
      v(accessor.access<MpsLaserConfigurationData>());
    assert(v.size()==1);
    if(doPrint(r.recordType(),1)) v[0]->print(std::cout) << std::endl;


    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(_position) {
	  if(_vThreshold[region][i]==(65536*v[0]->stageY()+v[0]->stageX())) _nHist[region]=i;
	} else {
	  if(_vThreshold[region][i]==_vPcbConfigurationData[0].regionThresholdValue(region)) _nHist[region]=i;
	}	
      }

      if(_nHist[region]==_vThreshold[region].size()) {
	if(_position) {
	  std::cout << "New position for region " << region << " found = "
		    << v[0]->stageX() << ", " << v[0]->stageY() << std::endl;
	  _vThreshold[region].push_back(65536*v[0]->stageY()+v[0]->stageX());
	} else {
	  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;
	if(_position) {
	  stit << _runTitle << ", Region " << region << ", Position "
	       << v[0]->stageX() << ", " << v[0]->stageY();
	} else {
	  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());
      for(unsigned c(0);c<16;c++) {
	if(q[k].channel(c)) _hTChn->Fill(c);
      }
    }
    
    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 goodHit(false);
	q=w[0]->data()->data();
	for(unsigned k(0);k<w[0]->data()->numberOfTags();k++) {

	  int diff((int)(p[j].timeStamp())-(int)(q[k].timeStamp()));
	  _vHDiff[0][region][_nHist[region]]->Fill(diff);
	      
	  if(diff>1 && diff<5) {
	    goodHit=true;
	  }
	}
      }
    }

    return true;
  }
  

private:
  bool _position;

  TH1F* _hTNum;
  TH1F* _hTime;
  TH1F* _hTChn;

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

  std::vector<TH1F*> _vHDiff[3][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
