#ifndef HstFullCrcScan_HH
#define HstFullCrcScan_HH

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

#include "TROOT.h"
#include "TApplication.h"
#include "TCanvas.h"
#include "TH1D.h"
#include "TH2D.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 HstFullHoldScan : public HstBase {

public:
  HstFullHoldScan(bool i=true) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    for (unsigned fe(0); fe<8; fe++) _feEnabled[fe] = true;
    _holdScanMode = true;
    _chosenSlot = 0;
  }

  HstFullHoldScan(bool i=true,bool holdScanMode=true) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    for (unsigned fe(0); fe<8; fe++) _feEnabled[fe] = true;
    _holdScanMode = holdScanMode;
    _chosenSlot = 0;
  }

  HstFullHoldScan(bool i=true,bool holdScanMode=true, unsigned chosenSlot=0) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    for (unsigned fe(0); fe<8; fe++) _feEnabled[fe] = true;
    _holdScanMode = holdScanMode;
    _chosenSlot = chosenSlot;
  }

  HstFullHoldScan(bool i=true,bool holdScanMode=true, unsigned chosenSlot=0, bool reBin=false) : HstBase(i) {
    for(unsigned i(0);i<22;i++) _slot[i]=false;
    for (unsigned fe(0); fe<8; fe++) _feEnabled[fe] = true;
    _holdScanMode = holdScanMode;
    _chosenSlot = chosenSlot;
    _reBin = reBin;
  }

  void disableFE(unsigned fe)
  {
    _feEnabled[fe] = false;
  }

  void enableFE(unsigned fe)
  {
    _feEnabled[fe] = true;
  }


  virtual ~HstFullHoldScan() {
  }

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

	_slot[slot]=true;

	for(unsigned fe(0);fe<_maxFrontend;fe++) 
	  if (_feEnabled[fe]) 
	    {
	      for(unsigned chip(0);chip<12;chip++) {
		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;
		  if (_reBin) _hist[slot][fe][chip][chan] = new TH1D(sout.str().c_str(),sout.str().c_str(),(Int_t)(33768/8),-1000,33767);
		  else _hist[slot][fe][chip][chan] = new TH1D(sout.str().c_str(),sout.str().c_str(),33768,-1000,33767);

		}
	      }
	    }
      }
      //    else std::cout << "called with slot " << slot << " but only accepting slot 7" << std::endl;
  }

  void holdScanWrite(ofstream* file, unsigned timing, unsigned fe = 0)
  {
    assert(fe<_maxFrontend);
    assert(_feEnabled[fe]);
    *file << timing << "  ";
    for(unsigned i(0);i<22;i++) {
      if(_slot[i]) {
	for (unsigned chip(0);chip<12;chip++)
	  for(unsigned chan(0);chan<18;chan++) 
	    {
	      *file << _average[i][fe][chip][chan].average() << " " << _average[i][fe][chip][chan].sigma() << "   ";
	    }
      }
    }
    *file << std::endl;

    for(unsigned i(0);i<22;i++) 
      if(_slot[i]) 
	for (unsigned chip(0);chip<12;chip++)
	  for(unsigned chan(0);chan<18;chan++) 
	    _average[i][fe][chip][chan].reset();
    
  }

  bool postscript(std::string) {
    TFile *rootout = new TFile("allChannels.root","RECREATE");
    for(unsigned i(0);i<22;i++) {
      if(_slot[i]) {
	//	std::ostringstream sout;
	//	sout << "dps/chanNoiseSER0" << _label[i][4] << _label[i][5] << ".ps";
	//	_canvas[i]->Print(sout.str().c_str());
	for (unsigned fe(0);fe<_maxFrontend;fe++)
	  {
	    if (_feEnabled[fe])
	      {
		for (unsigned chip(0);chip<12;chip++)
		  {
		    for(unsigned chan(0);chan<18;chan++) 
		      {
			_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 i(0);i<_maxFrontend;i++) 
	  if (_feEnabled[i]) {
	  for(unsigned chip(0);chip<12;chip++) {
	    for(unsigned chan(0);chan<18;chan++) {
	      unsigned bin(18*(12*i+chip)+chan);
	      //    _graph[slot][0].AddPoint(bin,_average[slot][i][chip][chan].average(),0.0,_average[slot][i][chip][chan].errorOnAverage());
	      // _graph[slot][1].AddPoint(bin,_average[slot][i][chip][chan].sigma(),0.0,_average[slot][i][chip][chan].errorOnSigma());


	      //	      _hist[slot][i][chip][chan]->SetBins(33768,-1000,32768);
	      
	      if (!_holdScanMode) _average[slot][i][chip][chan].reset();
	      //_average[slot][i][chip][chan].reset();
	    }
	  }
	}
      }
    }
    /*
    for(unsigned i(0);i<22;i++) {
      if(_slot[i]) {
	_canvas[i]->Clear("D");
	_canvas[i]->cd(1);
	_graph[i][0].Draw("AP");
	_canvas[i]->cd(2);
	_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()]) {
        for(unsigned fe(0);fe<_maxFrontend;fe++) 
	  if (_feEnabled[fe]) {
          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) {
                for(unsigned chip(0);chip<12;chip++) {

		  _average[v[i]->slotNumber()][fe][chip][chan]+=as->adc(chip);
		  _hist[v[i]->slotNumber()][fe][chip][chan]->Fill(as->adc(chip));
		}
	      }
	    }
	  }
	}
      }
    }

    return true;
  }

private:
  TCanvas *_canvas[22];

  //TGraphErrors _graph[22][2];
  //  HstTGraphErrors _graph[22][2];
  TH1D* _hist[22][8][12][18];
  bool _feEnabled[8];
  bool _holdScanMode;
  unsigned _chosenSlot;
  bool _reBin;

  const static unsigned _maxFrontend = 8;

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

#endif
