#ifndef HstNoise_HH
#define HstNoise_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 "UtlAverage.hh"
#include "RcdRecord.hh"
#include "CrcLocationData.hh"
#include "CrcVlinkEventData.hh"
#include "DaqEvent.hh"
#include "SubAccessor.hh"


class HstNoise {

public:
  HstNoise(unsigned s, unsigned f=1) : _application("Noise Application",0,0), _slot(s), _feMask(f) {

    gROOT->Reset();
    gROOT->SetStyle("Plain");

    for(unsigned i(0);i<8;i++) {
      if((_feMask&(1<<i))!=0) {
	std::ostringstream sout;
	sout << "Slot " << _slot <<  ", FE" << i << " Noise Canvas";

	_canvas[i]=new TCanvas(sout.str().c_str(),sout.str().c_str(),400+10*i,10+10*i,600,800);
	_canvas[i]->Divide(1,2);
      }
    }
    //_canvas[8]=new TCanvas("Noise","Noise",400+10*8,10+10*8,600,400);

    for(unsigned i(0);i<8;i++) {
      std::ostringstream sout;
      sout << "Slot " << _slot << ", FE" << i << " ";

      _graph[i][0].Set(216);
      _graph[i][0].SetTitle((sout.str()+"Pedestal vs Chip/Channel").c_str());
      _graph[i][0].SetMarkerColor(1);
      _graph[i][0].SetMarkerStyle(20);
      
      _graph[i][1].Set(216);
      _graph[i][1].SetTitle((sout.str()+"Noise vs Chip/Channel").c_str());
      _graph[i][1].SetMarkerColor(1);
      _graph[i][1].SetMarkerStyle(20);

      for(unsigned chan(0);chan<18;chan++) {
	for(unsigned chip(0);chip<12;chip++) {
	  std::ostringstream sout;
	  sout << "Slot " << _slot << ", FE" << i << ", Chip " << chip << ", Chan " << chan;

	  _hist[i][chip][chan].SetNameTitle(sout.str().c_str(),sout.str().c_str());
	  _hist[i][chip][chan].SetBins(100,-30000,30000);
	}
      }
    }

    /*
    _canvas[8]->cd();
    _hist[0][0][0].Draw();
    _canvas[8]->Update();
    */
  }

  virtual ~HstNoise() {
  }

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

    for(unsigned i(0);i<8;i++) {
      if((_feMask&(1<<i))!=0) {
	for(unsigned chan(0);chan<18;chan++) {
	  for(unsigned chip(0);chip<12;chip++) {
	    unsigned bin(18*chip+chan);
	    _graph[i][0].SetPoint(bin,bin,_average[i][chip][chan].average());
	    _graph[i][0].SetPointError(bin,0.0,_average[i][chip][chan].errorOnAverage());
	    _graph[i][1].SetPoint(bin,bin,_average[i][chip][chan].sigma());
	    _graph[i][1].SetPointError(bin,0.0,_average[i][chip][chan].errorOnSigma());
	    //	    if(chip==11 && chan==0) std::cout << "FE" << i << " average = " << _average[i][chip][chan].average() << std::endl;

	    _hist[i][chip][chan].Reset();
	    _hist[i][chip][chan].SetBins(100,unsigned(_average[i][chip][chan].average())-50,unsigned(_average[i][chip][chan].average())+50);

	    _average[i][chip][chan].reset();
	  }
	}
      }
    }

    for(unsigned i(0);i<8;i++) {
      if((_feMask&(1<<i))!=0) {
	_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();

	std::ostringstream sout;
	sout << "dps/noiseFE" << i << ".ps";
	if(ps) _canvas[i]->Print(sout.str().c_str());
      }
    }

    //    _canvas[8]->Clear();
    //   _canvas[8]->cd();
    /*    
	  _hist[0][0][0].Draw();
       _canvas[8]->Update();
    */
  }

  void event(RcdRecord &r) {
    if(r.recordType()!=RcdHeader::event) return;
    
    SubAccessor extracter(r);
    
    std::vector<const DaqEvent*> z(extracter.extract<DaqEvent>());
    assert(z.size()==1);

    std::vector<const CrcLocationData<CrcVlinkEventData>* > v(extracter.extract< CrcLocationData<CrcVlinkEventData> >());
    //assert(v.size()==1);

    //    v[0]->print(std::cout);

    for(unsigned i(0);i<v.size();i++) {
      if(v[i]->slotNumber()==_slot) {
	const CrcVlinkEventData *p(v[i]->data());
	for(unsigned f(0);f<8;f++) {
	  const CrcVlinkFeData *fd(v[i]->data()->feData(f));
	  if(fd!=0) {
	    for(unsigned chan(0);chan<p->feNumberOfAdcSamples(f) && chan<18;chan++) {
	      const CrcVlinkAdcSample *as(fd->adcSample(chan));
	      if(as!=0) {
		for(unsigned chip(0);chip<12;chip++) {
		  _average[f][chip][chan].event(as->adc(chip));
		  _hist[f][chip][chan].Fill(as->adc(chip));
		}
	      }
	    }
	  }
	}
      }
    }
  }

private:
  TApplication _application;
  const unsigned _slot;
  const unsigned _feMask;
  TCanvas *_canvas[9];
  TGraphErrors _graph[8][2];
  TH1D _hist[8][12][18];
  UtlAverage _average[8][12][18];
};

#endif
