#ifndef HstDch_HH
#define HstDch_HH

#include <cassert>

#include "TH1F.h"
#include "TH2F.h"
#include "TProfile.h"
#include "TRandom.h"

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


class HstDch : public RcdUserRO {

public:
  HstDch(unsigned i) : _inputTrg(i) {

    // TRG histograms
    _beHist=new TH2F("HstBeHistory","BeTrg history",
		     253,0.0,253.0,32,0.0,32.0);
    
    for(unsigned i(0);i<32;i++) {
      std::ostringstream sout;
      sout << std::setw(2) << std::setfill('0') << i;
      
      _beiHist[i]=new TH1F((std::string("HstBeInput")+sout.str()).c_str(),
			   (std::string("BeTrg history for input ")+sout.str()).c_str(),
			   253,0.0,253.0);
    }


    // DCH histograms
    _dnoHist[0][0]=new TH1F("HstDchScTrgTdc0Words",
			    "TDC0, scintillator trigger, number of words",
			    100,0.0,100.0);
      
    _dnoHist[0][1]=new TH1F("HstDchScTrgTdc1Words",
			    "TDC1, scintillator trigger, number of words",
			    100,0.0,100.0);
      
    _dnoHist[1][0]=new TH1F("HstDchSwTrgTdc0Words",
			    "TDC0, software trigger, number of words",
			    100,0.0,100.0);
      
    _dnoHist[1][1]=new TH1F("HstDchSwTrgTdc1Words",
			    "TDC1, software trigger, number of words",
			    100,0.0,100.0);
    

    for(unsigned i(0);i<8;i++) {
      std::ostringstream sout;
      sout << i;

      _dchHist[0][0][i]=new TH1F((std::string("HstDchScTrgTdc0Dch")+sout.str()).c_str(),
				 (std::string("TDC0, Ch")+sout.str()+", Scintillator trigger times;Time (0.78ns units);Events").c_str(),
				 100,0.0,1000.0);
      
      _dchHist[0][1][i]=new TH1F((std::string("HstDchScTrgTdc1Dch")+sout.str()).c_str(),
				 (std::string("TDC1, Ch")+sout.str()+", Scintillator trigger times;Time (0.78ns units);Events").c_str(),
				 100,0.0,1000.0);
      
      _dchHist[1][0][i]=new TH1F((std::string("HstDchSwTrgTdc0Dch")+sout.str()).c_str(),
				 (std::string("TDC0, Ch")+sout.str()+", Software trigger times;Time (0.78ns units);Events").c_str(),
				 100,0.0,1000.0);
      
      _dchHist[1][1][i]=new TH1F((std::string("HstDchSwTrgTdc1Dch")+sout.str()).c_str(),
				 (std::string("TDC1, Ch")+sout.str()+", Software trigger times;Time (0.78ns units);Events").c_str(),
				 100,0.0,1000.0);
      
      _ddtHist[0][0][i]=new TH1F((std::string("HstDchScTrgTdc0Dch")+sout.str()+"Dt").c_str(),
				 (std::string("TDC0, Ch")+sout.str()+", Scintillator trigger d-times;Time (0.78ns units);Events").c_str(),
				 100,0.0,100.0);
      
      _ddtHist[0][1][i]=new TH1F((std::string("HstDchScTrgTdc1Dch")+sout.str()+"Dt").c_str(),
				 (std::string("TDC1, Ch")+sout.str()+", Scintillator trigger d-times;Time (0.78ns units);Events").c_str(),
				 100,0.0,100.0);
      
      _ddtHist[1][0][i]=new TH1F((std::string("HstDchSwTrgTdc0Dch")+sout.str()+"Dt").c_str(),
				 (std::string("TDC0, Ch")+sout.str()+", Software trigger d-times;Time (0.78ns units);Events").c_str(),
				 100,0.0,100.0);
      
      _ddtHist[1][1][i]=new TH1F((std::string("HstDchSwTrgTdc1Dch")+sout.str()+"Dt").c_str(),
				 (std::string("TDC1, Ch")+sout.str()+", Software trigger d-times;Time (0.78ns units);Events").c_str(),
				 100,0.0,100.0);
      
      _dccHist[0][i]=new TH2F((std::string("HstDchScTrgTdc0Dch0vsTdc0Dch")+sout.str()).c_str(),
			      (std::string("TDC0, Ch 0 vs TDC0, Ch")+sout.str()+", Software trigger times;Time (0.78ns units);Time (0.78ns units)").c_str(),
			      100,0.0,1000.0,100,0.0,1000.0);
      _dccHist[1][i]=new TH2F((std::string("HstDchScTrgTdc0Dch0vsTdc1Dch")+sout.str()).c_str(),
			      (std::string("TDC0, Ch 0 vs TDC1, Ch")+sout.str()+", Software trigger times;Time (0.78ns units);Time (0.78ns units)").c_str(),
			      100,0.0,1000.0,100,0.0,1000.0);
    }


    // Counters for scintillator and software triggers
    _trgCount[0]=0;
    _trgCount[1]=0;
  }

  virtual ~HstDch() {
    std::cout << std::endl << "Number of scintillator triggers = "
	      << std::setw(6) << _trgCount[0]
	      << std::endl << "Number of software     triggers = "
	      << std::setw(6) << _trgCount[1]
	      << std::endl << "Number of total        triggers = "
	      << std::setw(6) << _trgCount[0]+_trgCount[1]
	      << std::endl << std::endl;
  }


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

    SubAccessor accessor(r);
	
    if(r.recordType()==RcdHeader::event) {
      std::vector<const CrcLocationData<CrcVlinkEventData>* >
	v(accessor.access< CrcLocationData<CrcVlinkEventData> >());
      
      for(unsigned i(0);i<v.size();i++) {
	const CrcVlinkTrgData *td(v[i]->data()->trgData());
	if(td!=0) {
	  
	  bool scintillatorTrg(false);

	  const UtlPack *u((const UtlPack*)td->data());
	  for(unsigned j(0);j<253;j++) {
	    for(unsigned k(0);k<32;k++) {
	      if(u[j].bit(k)) {
		_beHist->Fill(j,k);
		_beiHist[k]->Fill(j);
	      }
	    }

	    if(j>230 && j<247 && u[j].bit(_inputTrg)) scintillatorTrg=true;
	  }

	  if(scintillatorTrg) _trgCount[0]++;
	  else                _trgCount[1]++;
	  
	  std::vector<const BmlLocationData<BmlCaen767EventData>*>
	    w(accessor.access< BmlLocationData<BmlCaen767EventData> >());
	  
	  std::vector<const BmlCaen767EventDatum*> vCh[2][8];

	  // Sort data by channel
	  for(unsigned j(0);j<w.size() && j<2;j++) {
	    for(unsigned k(0);k<8;k++) {
	      vCh[j][k]=w[j]->data()->channelData(k);
	    }
	  }
	  
	  // Loop over TDCs
	  for(unsigned j(0);j<2;j++) {

	    // Get trigger fiducial time
	    unsigned trgFid(0);
	    for(unsigned l(0);l<vCh[j][6].size() && trgFid==0;l++) {
	      if(vCh[j][6][l]->leadingEdge()) trgFid=vCh[j][6][l]->time();
	    }

	    // Get first leading edge of channel 0 for this TDC
	    unsigned chn0(999999);
	    for(unsigned l(0);l<vCh[j][0].size() && chn0==999999;l++) {
	      if(vCh[j][0][l]->leadingEdge()) chn0=vCh[j][0][l]->time();
	    }

	    for(unsigned k(0);k<8;k++) {
	      for(unsigned l(0);l<vCh[j][k].size();l++) {
		if(!vCh[j][k][l]->startTime()) {
		  unsigned chn(vCh[j][k][l]->channelNumber());

		  // Leading edge
		  if(vCh[j][k][l]->leadingEdge()) {
		    if(scintillatorTrg) {
		      _dchHist[0][j][chn]->Fill(vCh[j][k][l]->time());
		      _dccHist[j][chn]->Fill(vCh[j][k][l]->time(),chn0);
		      
		    } else {
		      _dchHist[1][j][chn]->Fill(vCh[j][k][l]->time());
		    }
		    
		    // Falling edge; assume previous corresponds to leading
		  } else {
		    if(l>0 && vCh[j][k][l-1]->leadingEdge()) {
		      if(scintillatorTrg) {
			_ddtHist[0][j][chn]->Fill(vCh[j][k][l]->time()-vCh[j][k][l-1]->time());
		      } else {
			_ddtHist[1][j][chn]->Fill(vCh[j][k][l]->time()-vCh[j][k][l-1]->time());
		      }
		    }
		  }
		}
	      }
	    }
	  }
	}
      }
    }

    return true;
  }

private:
  const unsigned _inputTrg;
  unsigned _trgCount[2];

  TH2F* _beHist;
  TH1F* _beiHist[32];

  TH1F* _dnoHist[2][2];
  TH1F* _dchHist[2][2][8];
  TH1F* _ddtHist[2][2][8];
  TH2F* _dccHist[2][8];
};

#endif
