#ifndef HstCosmicScan_HH
#define HstCosmicScan_HH

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

#include "TROOT.h"
#include "TStyle.h"
#include "TCanvas.h"
#include "TF1.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TPostScript.h"

#include "UtlRollingAverage.hh"
#include "HstBase.hh"
#include "HstTGraphErrors.hh"

#include "EmcEventEnergy.hh"
#include "CrcFeEventData.hh"
#include "CrcLocationData.hh"
#include "BmlHodEventData.hh"
#include "HodTrack.hh"
#include "DaqEvent.hh"
#include "SubAccessor.hh"

Double_t DoubleG(Double_t *x, Double_t *par) {

  double mean0=par[2];
  double mean1=par[2]+par[0];
  double sigma0=par[0]/par[1];
  double sigma1=par[3];
  double norm0=par[4];
  double norm1=par[5];

  return norm0*exp(-0.5*(x[0]-mean0)*(x[0]-mean0)/(sigma0*sigma0))
        +norm1*exp(-0.5*(x[0]-mean1)*(x[0]-mean1)/(sigma1*sigma1));
}

Double_t crrc(Double_t *x, Double_t *par) {
  Double_t t=32.0;
  Double_t y=(x[0]-par[0])/t;
  if(y<-1.0) return 0.0;
  return par[1]*(y+1.0)*exp(-y);
}

class HstCosmicScan : public HstBase {

public:
  HstCosmicScan(unsigned c, double x, double y, bool i=true) :
    HstBase(i), _firstRecordTime(0), _chipMask(c), _deltax(x), _deltay(y) {

    gStyle->SetOptFit(1);

    TH1D *p(0);
    for(unsigned z(0);z<14;z++) {
      for(unsigned h(1);h<30;h+=4) {
	std::ostringstream sout;
	sout << "Layer " << z << " HOLD " << h << " ADC values for neighbouring hits";
	p=hist1(sout.str(),100,-50.0,150.0);
      }

      std::ostringstream sout2;
      sout2 << "Layer " << z;
      _summaryc[z][0].SetTitle((sout2.str()+" Fit Signal vs HOLD").c_str());
      _summaryc[z][1].SetTitle((sout2.str()+" Fit Signal/Noise vs HOLD").c_str());
    }

    p=hist1("Record Types",20,0.0,20.0);

    //TH2D *q(0);
    //q=hist2("Hodoscope interpolation",140,-15.0,55.0,82,0.0,41.0);


    /*
    _summarycc[0].SetTitle("Fit Signal vs 18*Chip+Chan");
    _summarycc[1].SetTitle("Fit Signal/Noise vs 18*Chip+Chan");

    for(unsigned chip(0);chip<12;chip++) {
      ostringstream sout;
      sout << "Chip " << chip << ", ADC values for close good tracks";
      _histc[chip]=new TH1D(sout.str().c_str(),sout.str().c_str(),
			    100,-50.0,150.0);

      for(unsigned chan(0);chan<18;chan++) {
	ostringstream sout;
	sout << "Chip " << chip << ", Channel " << chan << ", ";

	std::string s(sout.str()+"ADC values for close good tracks");
	_histcc[chip][chan]=new TH1D(s.c_str(),s.c_str(),100,-50.0,150.0);

	std::string g(sout.str()+" Pedestal vs Time (Days)");
	_graph[chip][chan][0].SetTitle(g.c_str());
	_graph[chip][chan][0].SetMarkerColor(1);
	_graph[chip][chan][0].SetMarkerStyle(20);

	std::string n(sout.str()+" Noise vs Time (Days)");
	_graph[chip][chan][1].SetTitle(n.c_str());
	_graph[chip][chan][1].SetMarkerColor(1);
	_graph[chip][chan][1].SetMarkerStyle(20);
      }
    }

    _nAdc=0;
    */

  }

  virtual ~HstCosmicScan() {
  }

  bool record(const RcdRecord &r) {
    return false;
  }

  bool record(const RcdRecord &r, const EmcEventEnergy en) {
    _hist1Vector[80]->Fill(r.recordType());

    SubAccessor accessor(r);

    if(r.recordType()==RcdHeader::configurationStart) {
      std::vector<const CrcLocationData<EmcFeConfigurationData>*>
	vc(accessor.extract< CrcLocationData<EmcFeConfigurationData> >());
      
      for(unsigned i(0);i<vc.size();i++) {
	//cout << "FE Configuration ";
	//vc[i]->print(cout);
	//cout << " HOLD start = " << vc[i]->data()->holdStart() << endl;

	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe6)
	  _hold[0]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe1)
	  _hold[1]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe2)
	  _hold[2]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe3)
	  _hold[3]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe4)
	  _hold[4]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe5)
	  _hold[5]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe6)
	  _hold[6]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==12 && vc[i]->crcComponent()==CrcLocation::fe7)
	  _hold[7]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe0)
	  _hold[8]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe1)
	  _hold[9]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe2)
	  _hold[10]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe3)
	  _hold[11]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe4)
	  _hold[12]=vc[i]->data()->holdStart();
	if(vc[i]->slotNumber()==17 && vc[i]->crcComponent()==CrcLocation::fe5)
	  _hold[13]=vc[i]->data()->holdStart();

      }

      std::cout << "Layer HOLDs =";
      for(unsigned z(0);z<14;z++) std::cout << " " << _hold[z];
      std::cout << std::endl;

      return true;
    }

    if(r.recordType()!=RcdHeader::event) return true;

    for(unsigned x(0);x<18;x++) {
      for(unsigned y(6);y<18;y++) {
	for(unsigned z(0);z<14;z++) {
	  unsigned zn(z+1);
	  if((z%2)==1) zn=z-1;
	  //if(_hold[zn]==5) {
	  if(_hold[zn]==10) {
	    if(en.energy(EmcPhysicalPad(x,y,zn))>30.0) {
	      //cout << "Hit at X,Y,Z = " << x << "," << y << "," << zn
	      // << " = " << en.energy(EmcPhysicalPad(x,y,zn)) 
	      // << " and hit at Z = " << z << " = " 
	      // << en.energy(EmcPhysicalPad(x,y,z)) << endl;
	      _hist1Vector[8*z+(_hold[z]-1)/4]->Fill(en.energy(EmcPhysicalPad(x,y,z)));
	    }
	  }
	}
      }
    }

    return true;
  }

  bool update() {
    std::cout << "Updating..." << std::endl;

    TF1 *func = new TF1("DoubleG",DoubleG,-50,150,6);
    TF1 *fund = new TF1("CRRC",crrc,0,100,2);

    for(unsigned z(0);z<14;z++) {
      for(unsigned h(0);h<8;h++) {
	Double_t par[6]={50.0,8.0,0.0,10.0,25.0,25.0};
	func->SetParameters(par);
	_hist1Vector[8*z+h]->Fit("DoubleG","Q",0,-20.0,70.0);
	double *p(func->GetParameters());       
	double *e(func->GetParErrors());        
	_summaryc[z][0].AddPoint(1+4*h,p[0],0,e[0]);
	_summaryc[z][1].AddPoint(1+4*h,p[1],0,e[1]);
      }	

      Double_t pas[2]={0.0,50.0};
      fund->SetParameters(pas);
      _summaryc[z][0].Fit("CRRC","",0,0.0,30.0);
      
      Double_t pat[2]={0.0,9.0};
      fund->SetParameters(pat);
      _summaryc[z][1].Fit("CRRC","",0,0.0,30.0);
    }

    for(unsigned i(0);i<_canvas1Vector.size();i++) {
      _canvas1Vector[i]->cd();
      _hist1Vector[i]->Draw();
      _canvas1Vector[i]->Update();
    }

    for(unsigned i(0);i<_canvas2Vector.size();i++) {
      _canvas2Vector[i]->cd();
      _hist2Vector[i]->Draw("box");
      _canvas2Vector[i]->Update();
    }

    TCanvas c("HC","HC",0,0,600,400);
    c.cd();

    /*
    c.Clear();
    c.Divide(4,3);
    for(unsigned chip(0);chip<12;chip++) {
      c.cd(chip+1);
      _histc[chip]->Draw();
    }      
    c.Update();

    for(unsigned chip(0);chip<12;chip++) {
      c.Clear();
      c.Divide(6,3);
      for(unsigned chan(0);chan<18;chan++) {
	c.cd(chan+1);
	_histcc[chip][chan]->Draw();
      }
      c.Update();
    }      

    for(unsigned chip(0);chip<12;chip++) {
      c.Clear();
      c.Divide(6,3);
      for(unsigned chan(0);chan<18;chan++) {
	c.cd(chan+1);
	_graph[chip][chan][0].Draw("AP");
      }
      c.Update();

      c.Clear();
      c.Divide(6,3);
      for(unsigned chan(0);chan<18;chan++) {
	c.cd(chan+1);
	_graph[chip][chan][1].Draw("AP");
      }
      c.Update();
    }
    */

    for(unsigned z(0);z<14;z++) {    
      c.Clear();
      c.Divide(1,2);
      c.cd(1);
      _summaryc[z][0].Draw("AP");
      c.cd(2);
      _summaryc[z][1].Draw("AP");
      c.Update();
    }

    /*
    c.Clear();
    c.Divide(1,2);
    c.cd(1);
    _summarycc[0].Draw("AP");
    c.cd(2);
    _summarycc[1].Draw("AP");
    c.Update();
    */

    return true;
  }

  bool postscript(std::string file) {
    std::cout << "HstCosmicScan::postscript()  Writing to file "
	      << file << std::endl;

    TPostScript ps(file.c_str(),112);
    update();
    ps.Close();

    return true;
  }

private:
  TH1D* hist1(std::string t, unsigned n, double l, double h) {
    unsigned num(_hist1Vector.size());
    std::ostringstream oss;
    oss << num;

    _canvas1Vector.push_back(new TCanvas((std::string("Canvas1[")+oss.str()+std::string("]")).c_str(),
					 (t+" canvas").c_str(),10+10*num,10+10*num,600,400));
    _hist1Vector.push_back(new TH1D((std::string("TH1D[")+oss.str()+std::string("]")).c_str(),
				    t.c_str(),n,l,h));
    return _hist1Vector[num];
  }
  TH2D* hist2(std::string t, unsigned nx, double lx, double hx, unsigned ny, double ly, double hy) {
    unsigned num(_hist2Vector.size());
    std::ostringstream oss;
    oss << num;

    _canvas2Vector.push_back(new TCanvas((std::string("Canvas2[")+oss.str()+std::string("]")).c_str(),
					 (t+" canvas").c_str(),500+10*num,10+10*num,600,400));
    _hist2Vector.push_back(new TH2D((std::string("TH2D[")+oss.str()+std::string("]")).c_str(),
				    t.c_str(),nx,lx,hx,ny,ly,hy));
    return _hist2Vector[num];
  }

  std::vector<TCanvas*> _canvas1Vector;
  std::vector<TCanvas*> _canvas2Vector;
  std::vector<TPad*> _pad1Vector;
  std::vector<TH1D*> _hist1Vector;
  std::vector<TH2D*> _hist2Vector;
  TH1D *_histc[12];
  TH1D *_histcc[12][18];

  unsigned _firstRecordTime,_pTime;
  UtlRollingAverage _average[12][18];
  UtlRollingAverage _pedestal[12][18];
  HstTGraphErrors _graph[12][18][2];
  HstTGraphErrors _summaryc[14][2];
  HstTGraphErrors _summarycc[2];

  const unsigned _chipMask;
  const double _deltax,_deltay;
  

  unsigned _hold[14];


  unsigned _nAdc;
  int _adc[12][18][100];
  double _ped[12][18];
};

#endif
