#ifndef HstCrcFeNoise_HH
#define HstCrcFeNoise_HH

#include <cassert>

//#include "TROOT.h"
#include "TMapFile.h"
#include "TH1F.h"
#include "TH2F.h"
#include "TProfile.h"
#include "TRandom.h"

#include "DaqRunStart.hh"

#include "RcdUserRO.hh"
#include "RcdWriterDmy.hh"
#include "RcdWriterAsc.hh"
#include "RcdWriterBin.hh"

#include "UtlAverage.hh"
#include "SubAccessor.hh"


class HstCrcFeNoise : public RcdUserRO {

public:
  HstCrcFeNoise() {
    readPedestal();
    for(unsigned c(0);c<2;c++) {
      for(unsigned i(0);i<=21;i++) {
	for(unsigned fe(0);fe<8;fe++) {
	  _number[c][i][fe]=0;
	  _pedestal[c][i][fe]=0;
	  _noise[c][i][fe]=0;
	}
      }
    }
  }
  
  
  virtual ~HstCrcFeNoise() {
    for(unsigned c(0);c<2;c++) {
      for(unsigned i(0);i<=21;i++) {
	for(unsigned fe(0);fe<8;fe++) {
	  if(_number[c][i][fe]  !=0) delete _number[c][i][fe];
	  if(_pedestal[c][i][fe]!=0) delete _pedestal[c][i][fe];
	  if(_noise[c][i][fe]   !=0) delete _noise[c][i][fe];
	  
	  _number[c][i][fe]=0;
	  _pedestal[c][i][fe]=0;
	  _noise[c][i][fe]=0;
	}
      }
    }
  }

  void readPedestal() {
    std::ifstream pedFile;
    char line[512];
    pedFile.open("pedestal_testbeam.dat");
    unsigned ii,slot,fe,chip,chan;
    double pedsigma,pedmean,pedrms;
    while (pedFile.good())
      {
	//configFile >> buffer;
	pedFile.getline(line,sizeof(line));

	if (line[0] != '#')
	  {
	    std::istringstream buffer(line);
	    buffer >> ii;
	    buffer >> slot;
	    buffer >> fe;
	    buffer >> chip;
	    buffer >> chan;
	    buffer >> subped[slot][fe][chip][chan];
	    buffer >> pedsigma;
	    buffer >> pedmean;
	    buffer >> pedrms;

	  }
      }
    pedFile.close();
  }
  /*
  void update() {
    _pedestal.Draw();
    _noise.Draw();
  }
  */

  bool record(const RcdRecord &r) {

    if(r.recordType()==RcdHeader::runStart) {
      for(unsigned c(0);c<2;c++) {
	for(unsigned i(0);i<=21;i++) {
	  for(unsigned fe(0);fe<8;fe++) {
	    if(_number[c][i][fe]  !=0) delete _number[c][i][fe];
	    if(_pedestal[c][i][fe]!=0) delete _pedestal[c][i][fe];
	    if(_noise[c][i][fe]   !=0) delete _noise[c][i][fe];
	  
	    _number[c][i][fe]=0;
	    _pedestal[c][i][fe]=0;
	    _noise[c][i][fe]=0;
	  }
	}
      }

      SubAccessor accessor(r);
      std::vector<const CrcLocationData<CrcVmeRunData>* >
	v(accessor.access< CrcLocationData<CrcVmeRunData> >());
 
      for(unsigned i(0);i<v.size();i++) {

	// Get crate number
	unsigned crate(2);
	if(v[i]->crateNumber()==0xec) crate=0;
	if(v[i]->crateNumber()==0xac) crate=1;
	if(crate<2) {

	  // Get slot number
	  if(v[i]->slotNumber()<22) {
	    unsigned slot(v[i]->slotNumber());

	    for(unsigned fe(0);fe<8;fe++) {
	      std::ostringstream label;
	      label << "HstCrcFeNoiseCrate" << crate << "Slot";
	      if(slot<10) label << "0";
	      label << slot << "Fe" << fe;
	      
	      std::ostringstream title;
	      if(crate==0) title << "ECAL Crate, ";
	      if(crate==1) title << "AHCAL Crate, ";
	      title << " Slot " << std::setw(2) << slot << ", FE" << fe;
	      
	      _number[crate][slot][fe]=new 
		TH1F((label.str()+"Number").c_str(),
		     (title.str()+", Number of reads vs 18*ADC+Chan").c_str(),
		     216,0,216);
	      
	      _pedestal[crate][slot][fe]=new 
		TH1F((label.str()+"Average").c_str(),
		     (title.str()+", Average vs 18*ADC+Chan").c_str(),
		     216,0,216);
	      
	      _noise[crate][slot][fe]=new 
		TH1F((label.str()+"Rms").c_str(),
		     (title.str()+", RMS vs 18*ADC+Chan").c_str(),
		     216,0,216);
	      
	      for(unsigned chip(0);chip<12;chip++) {
		for(unsigned chan(0);chan<18;chan++) {
		  _average[crate][slot][fe][chip][chan].reset();
		}
	      }
	    }
	  }
	}
      }

      return true;
    }


   
    if(r.recordType()==RcdHeader::acquisitionEnd) {
      for(unsigned c(0);c<2;c++) {
	for(unsigned i(0);i<=21;i++) {
	  for(unsigned fe(0);fe<8;fe++) {
	    if(_number[c][i][fe]!=0 && _pedestal[c][i][fe]!=0 && _noise[c][i][fe]!=0) {
	      _number[c][i][fe]->Reset();
	      _pedestal[c][i][fe]->Reset();
	      _noise[c][i][fe]->Reset();
	      
	      for(unsigned chip(0);chip<12;chip++) {
		for(unsigned chan(0);chan<18;chan++) {
		  _number[c][i][fe]->SetBinContent(  18*chip+chan+1,_average[c][i][fe][chip][chan].number());
		  _pedestal[c][i][fe]->SetBinContent(18*chip+chan+1,_average[c][i][fe][chip][chan].average()-subped[i][fe][chip][chan]);
		  _pedestal[c][i][fe]->SetBinError(  18*chip+chan+1,_average[c][i][fe][chip][chan].errorOnAverage());
		  _noise[c][i][fe]->SetBinContent(   18*chip+chan+1,_average[c][i][fe][chip][chan].sigma());
		  _noise[c][i][fe]->SetBinError(     18*chip+chan+1,_average[c][i][fe][chip][chan].errorOnSigma());
		  _average[c][i][fe][chip][chan].reset();
		}
	      }
	    }
	  }
	}
      }
     
      return true;
    }
   
    if(r.recordType()==RcdHeader::event) {
      //r.RcdHeader::print(std::cout);

      SubAccessor accessor(r);
      std::vector<const CrcLocationData<CrcVlinkEventData>* >
	v(accessor.access< CrcLocationData<CrcVlinkEventData> >());

      for(unsigned i(0);i<v.size();i++) {

	// Get crate number
	unsigned crate(2);
	if(v[i]->crateNumber()==0xec) crate=0;
	if(v[i]->crateNumber()==0xac) crate=1;
	if(crate<2) {

	  // Get slot number
	  if(v[i]->slotNumber()<22) {
	    unsigned slot(v[i]->slotNumber());
	    if(_number[crate][slot]!=0 &&
	       _pedestal[crate][slot]!=0 &&
	       _noise[crate][slot]!=0) {

	      // Loop over FE number
	      for(unsigned fe(0);fe<8;fe++) {
		const CrcVlinkFeData *fd(v[i]->data()->feData(fe));
		if(fd!=0) {

		  // Loop over mplex channel number
		  for(unsigned chan(0);chan<v[i]->data()->feNumberOfAdcSamples(fe) && chan<18;chan++) {
		    const CrcVlinkAdcSample *as(fd->adcSample(chan));
		    if(as!=0) {

		      // Loop over chips=ADCs
		      for(unsigned chip(0);chip<12;chip++) {
			_average[crate][slot][fe][chip][chan]+=as->adc(chip);
		      }
		    }
		  }
		}
	      }
	    }
	  }
	}
      }
    }
    return true;
  }

private:
  double  subped[22][8][12][18];
  TH1F *_number[2][22][8];
  TH1F *_pedestal[2][22][8];
  TH1F *_noise[2][22][8];
  UtlAverage _average[2][22][8][12][18];
};

#endif
