#ifndef HstPartCrcScanPed_HH
#define HstPartCrcScanPed_HH 1

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

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

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

#include "UtlAverage.hh"
#include "RcdRecord.hh"
#include "CrcLocationData.hh"
#include "CrcVlinkEventData.hh"
#include "DaqEvent.hh"
#include "SubAccessor.hh"


class HstPartCrcScanPed : public HstBase {

public:
  HstPartCrcScanPed(bool i=true) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    _SLOT = 0;
    _FE = 0;
    _chip = 0;
  }

  HstPartCrcScanPed(bool i,unsigned FE, unsigned chip, string pedFileName, bool createPed = false) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    _SLOT = 0;
    _FE = FE;
    _chip = chip;
    _createPed = createPed;
    _pedFileName = pedFileName;
    gStyle->SetStatW(0.4);
    gStyle->SetStatH(0.3);

    if (_createPed) _pedFile = new TFile((pedFileName+".root").c_str(),"NEW");
    else _pedFile = new TFile((pedFileName+".root").c_str(),"READ");
    if (!_pedFile->IsOpen()) {
      cout <<"problem with pedestal file -- exiting" << endl;
      exit(1);
    }
    if (_createPed) {   //close again to get separation between hists and peds
      _pedFile->Close();
      delete _pedFile;
    }
  }

  HstPartCrcScanPed(bool i,unsigned SLOT, unsigned FE, unsigned chip, string pedFileName, bool createPed = false) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    _SLOT = SLOT;
    _FE = FE;
    _chip = chip;
    _createPed = createPed;
    _pedFileName = pedFileName;
    gStyle->SetStatW(0.4);
    gStyle->SetStatH(0.3);

    if (_createPed) _pedFile = new TFile((pedFileName+".root").c_str(),"NEW");
    else _pedFile = new TFile((pedFileName+".root").c_str(),"READ");
    if (!_pedFile->IsOpen()) {
      cout <<"problem with pedestal file -- exiting" << endl;
      exit(1);
    }
    if (_createPed) {   //close again to get separation between hists and peds
      _pedFile->Close();
      delete _pedFile;
    }
  }





  virtual ~HstPartCrcScanPed() {
    if (_createPed) {
      _pedFile = new TFile((_pedFileName+".root").c_str(),"RECREATE");
      for (unsigned i(0);i<22;i++) 
	if (_slot[i]) 
	  for (unsigned chan(0);chan<18;chan++) {
	    _hist[i][_FE][_chip][chan]->Fit(_ped[i][_FE][_chip][chan],"RQN");
	    _ped[i][_FE][_chip][chan]->Write();
	  }
      _pedFile->Write();
    }
    _pedFile->Close();
  }


  void autoSetLimits(TH1* hist)
  {
    unsigned entries = (unsigned)hist->GetEntries();
    entries -= (unsigned)hist->GetBinContent(0);
    entries -= (unsigned)hist->GetBinContent(hist->GetNbinsX()+1);
    unsigned counter = 0;
    int bin = 1;
    while (counter/(double)entries < 0.01) counter += (unsigned)hist->GetBinContent(bin++);
    int minBin = bin-1;
    while (counter/(double)entries < 0.99) counter += (unsigned)hist->GetBinContent(bin++);
    if (!_createPed) minBin = - (int)hist->GetBinCenter(1) - 200;
    hist->GetXaxis()->SetRange(minBin,bin);
  }

  void slotCanvas(unsigned slot) {
    if (slot==_SLOT || _SLOT==0)
      {
	std::cout << "slotCanvas called with slot " << slot << " Label = " << _label[slot] << std::endl;

	_slot[slot]=true;

	_canvas[slot]=new TCanvas(_label[slot].c_str(),_label[slot].c_str(),40,40,1200,900);
	_canvas[slot]->Divide(5,4);


	_graph[slot][0].SetTitle((_label[slot]+", Pedestal vs FE/Chip/Chan").c_str());
	_graph[slot][1].SetTitle((_label[slot]+", Noise vs FE/Chip/Chan").c_str());


	char pedFitName[512];
    
	
	for(unsigned chan(0);chan<18;chan++) {
	  std::ostringstream sout;
	  sout << _label[slot] << ", FE" << _FE << ", Chip " << std::setw(2) << _chip << ", Chan " << std::setw(2) << chan;
		  
	  _hist[slot][_FE][_chip][chan] = new TH1D(sout.str().c_str(),sout.str().c_str(),33768,-1000,33767);

	  sprintf(pedFitName,"Slot %d FE %d chip %d chan %d pedestal",slot,_FE,_chip,chan);
	  if (_createPed) _ped[slot][_FE][_chip][chan] = new TF1(pedFitName,"gaus",-1000,3000);
	  else _ped[slot][_FE][_chip][chan] = (TF1*) _pedFile->Get(pedFitName);
	}
	 
      }
    else std::cout << "called with slot " << slot << " but only accepting slot 12" << std::endl;
  }


  bool postscript(std::string) {
    TFile *rootout = new TFile("partchannels_pedsub.root","RECREATE");
    for(unsigned i(0);i<22;i++) {
      if(_slot[i]) {
	for(unsigned chan(0);chan<18;chan++) 
	  {
	    rootout->cd();
	    _hist[i][_FE][_chip][chan]->Write();
	  }
      }
    }
    rootout->Write();
    rootout->Close();


    return false;
  }

  bool update() { //bool ps=false) {
    std::cout << "Updating..." << std::endl;

    for(unsigned slot(5);slot<22;slot++) {
      if(_slot[slot]) {

	_graph[slot][0].Set(0);
	_graph[slot][1].Set(0);

	for(unsigned chan(0);chan<18;chan++) {
	  unsigned bin(18*(12*_FE+_chip)+chan);

	  if (_createPed) _hist[slot][_FE][_chip][chan]->Fit(_ped[slot][_FE][_chip][chan],"RQN");

	  _graph[slot][0].AddPoint(bin,_average[slot][_FE][_chip][chan].average() - _ped[slot][_FE][_chip][chan]->GetParameter(1),0.0,_average[slot][_FE][_chip][chan].errorOnAverage());
	  _graph[slot][1].AddPoint(bin,_average[slot][_FE][_chip][chan].sigma(),0.0,_average[slot][_FE][_chip][chan].errorOnSigma());

	  _average[slot][_FE][_chip][chan].reset();
	}
	 
	
      }
    }
    
    for(unsigned i(0);i<22;i++) {
      if(_slot[i]) {
	_canvas[i]->Clear("D");
	for(unsigned chan(0);chan<18;chan++) {
	  _canvas[i]->cd(chan+1);
	  autoSetLimits(_hist[i][_FE][_chip][chan]);
	  _hist[i][_FE][_chip][chan]->Draw();
	  if (_createPed){
	    _ped[i][_FE][_chip][chan]->SetLineColor(2);
	    _ped[i][_FE][_chip][chan]->Draw("same");
	  }
	}	
	_canvas[i]->cd(19);
	_graph[i][0].Draw("AP");
	_canvas[i]->cd(20);
	_graph[i][1].Draw("AP");
	_canvas[i]->Update();
      }
    }
    return true;
  }

  bool record(const RcdRecord &r) {


    if(r.recordType()==RcdHeader::runStart) {
      SubAccessor extracter(r);
      std::vector<const CrcLocationData<CrcVmeRunData>* > v(extracter.extract< CrcLocationData<CrcVmeRunData> >());

      for(unsigned i(0);i<v.size();i++) {
	if(!_slot[v[i]->slotNumber()]) {
	  std::ostringstream sout;
	  unsigned sn((v[i]->data()->epromHeader())&0xff);
	  if(sn<10) sout << "SER00" << sn << ", Slot " << std::setw(2) << (unsigned)v[i]->slotNumber();
	  else      sout << "SER0"  << sn << ", Slot " << std::setw(2) << (unsigned)v[i]->slotNumber();
	  _label[v[i]->slotNumber()]=sout.str();
	  slotCanvas(v[i]->slotNumber());
	}
      }
      return true;
    }

    if(r.recordType()!=RcdHeader::event) return true;
    
    SubAccessor extracter(r);
    std::vector<const CrcLocationData<CrcVlinkEventData>* > v(extracter.extract< CrcLocationData<CrcVlinkEventData> >());


    for(unsigned i(0);i<v.size();i++) {
      if(_slot[v[i]->slotNumber()]) {
	const CrcVlinkFeData *fd(v[i]->data()->feData(_FE));
	if(fd!=0) {
	  for(unsigned chan(0);chan<v[i]->data()->feNumberOfAdcSamples(_FE) && chan<18;chan++) {
	    const CrcVlinkAdcSample *as(fd->adcSample(chan));
	    if(as!=0) {
	      _average[v[i]->slotNumber()][_FE][_chip][chan]+=as->adc(_chip);
	      if (_createPed) _hist[v[i]->slotNumber()][_FE][_chip][chan]->Fill(as->adc(_chip));
	      else _hist[v[i]->slotNumber()][_FE][_chip][chan]->Fill(as->adc(_chip) - _ped[v[i]->slotNumber()][_FE][_chip][chan]->GetParameter(1));
		
	    }
	  }
	}
      }
    }

    return true;
  }

private:
  TCanvas *_canvas[22];

  HstTGraphErrors _graph[22][2];
  TH1D* _hist[22][8][12][18];
  TF1* _ped[22][8][12][18];
  TFile* _pedFile;
  unsigned _SLOT;
  unsigned _FE;
  unsigned _chip;

  bool _slot[22];
  bool _createPed;
  std::string _label[22];
  string _pedFileName;
  UtlAverage _average[22][8][12][18];
};

#endif
