#ifndef HstExtDac_HH
#define HstExtDac_HH

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

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

#include "UtlAverage.hh"
#include "HstTGraphErrors.hh"
#include "RcdRecord.hh"
#include "CrcLocationData.hh"
#include "CrcVlinkEventData.hh"
#include "HodData.hh"
#include "HodTrack.hh"
#include "DaqEvent.hh"
#include "SubAccessor.hh"


class HstExtDac {

public:
  HstExtDac(unsigned s=18, unsigned f=0, unsigned c=0) : 
    _application("Noise Application",0,0),
    _slot(s), _fe(f), _chip(c), _cludge(0) {

    //	       _canvas("Noise Canvas","Noise Canvas",500,10,600,800) {

    gROOT->Reset();
    gROOT->SetStyle("Plain");
    gStyle->SetOptFit(1);

    //_canvas[0].SetCanvasSize(600,800);
    //_canvas[0].SetWindowSize(600,800);
    _canvas[0]=new TCanvas("IntDac Canvas[0]","IntDac Canvas[0]",10,10,600,800),
    _canvas[1]=new TCanvas("IntDac Canvas[1]","IntDac Canvas[1]",20,20,600,800),
    _canvas[2]=new TCanvas("IntDac Canvas[2]","IntDac Canvas[2]",30,30,600,800),

    _canvas[0]->Divide(1,3);
    _canvas[1]->Divide(1,3);
    _canvas[2]->Divide(1,2);

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	std::ostringstream sout[3];
	sout[0] << "FE" << fe << ", Chip " << chip << ", ADC mean vs DAC";
	sout[1] << "FE" << fe << ", Chip " << chip << ", ADC noise vs DAC";
	sout[2] << "FE" << fe << ", Chip " << chip << ", ADC residuals vs DAC";
	
	for(unsigned i(0);i<3;i++) {
	  _graph[fe][chip][i].SetTitle(sout[i].str().c_str());
	  _graph[fe][chip][i].SetMarkerColor(1);
	  _graph[fe][chip][i].SetMarkerStyle(20);
	}
      }
    }

    _summary[0].Set(96);
    _summary[0].SetTitle("Fit Intercept vs FE/Chip");
    _summary[0].SetMarkerColor(1);
    _summary[0].SetMarkerStyle(20);

    _summary[1].Set(96);
    _summary[1].SetTitle("Fit Slope vs FE/Chip");
    _summary[1].SetMarkerColor(1);
    _summary[1].SetMarkerStyle(20);
  }

  virtual ~HstExtDac() {
  }

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

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	_graph[fe][chip][0].Set(0);
	_graph[fe][chip][1].Set(0);
	_graph[fe][chip][2].Set(0);
	for(unsigned i(0);i<_dac.size();i++) {
	  if(_average[fe][chip][i].number()>1) {
	    std::cout << "FE" << fe << ", Chip " << chip << " DAC " << _dac[i] 
		 << " has entries" << std::endl;

	    _graph[fe][chip][0].AddPoint(_dac[i],_average[fe][chip][i].average(),0.0,_average[fe][chip][i].errorOnAverage());
	    _graph[fe][chip][1].AddPoint(_dac[i],_average[fe][chip][i].sigma(),0.0,_average[fe][chip][i].errorOnSigma());
	  }
	}

	if(fits) {
	  if(_graph[fe][chip][0].GetN()>1) {
	    _graph[fe][chip][0].Fit("pol1","Q",0,-65000.0,65000.0);
	    double *pars=_graph[fe][chip][0].GetFunction("pol1")->GetParameters();
	    double *errs=_graph[fe][chip][0].GetFunction("pol1")->GetParErrors();
	    
	    _graph[fe][chip][2].Set(0);
	    for(int i(0);i<_graph[fe][chip][0].GetN();i++) {
	      double x,y;
	      _graph[fe][chip][0].GetPoint(i,x,y);
	      //if(x>=1000.0) {
		_graph[fe][chip][2].AddPoint(x,y-pars[0]-x*pars[1],0.0,_graph[fe][chip][0].GetErrorY(i));
		//}
	    }
	    
	    _summary[0].SetPoint(12*fe+chip,12*fe+chip,pars[0]);
	    _summary[0].SetPointError(12*fe+chip,0.0,errs[0]);
	    _summary[1].SetPoint(12*fe+chip,12*fe+chip,pars[1]);
	    _summary[1].SetPointError(12*fe+chip,0.0,errs[1]);
	  }
	}
      }
    }

    _canvas[0]->cd(1);
    _graph[_fe][_chip][0].Draw("AP");
    _canvas[0]->cd(2);
    _graph[_fe][_chip][1].Draw("AP");
    _canvas[0]->cd(3);
    _graph[_fe][_chip][2].Draw("AP");
    _canvas[0]->Update();

    _canvas[1]->cd(1);
    _graph[_fe][_chip][0].Draw("AP");
    _canvas[1]->cd(2);
    _graph[_fe][_chip][1].Draw("AP");
    _canvas[1]->cd(3);
    _graph[_fe][_chip][2].Draw("AP");
    _canvas[1]->Update();

    _canvas[2]->cd(1);
    _summary[0].Draw("AP");
    _canvas[2]->cd(2);
    _summary[1].Draw("AP");
    _canvas[2]->Update();
  }

  void event(RcdRecord &r) {
    if(r.recordType()==RcdHeader::configurationEnd ||
       r.recordType()==RcdHeader::configurationStop) {
      //update();
      return;
    }

    if(r.recordType()==RcdHeader::runEnd ||
       r.recordType()==RcdHeader::runStop) {
      _cludge++;
      //update(true);
      return;
    }

    SubAccessor extracter(r);
    
    if(r.recordType()==RcdHeader::configurationStart) {
      int d(0);

      std::vector<const CrcLocationData<CrcFeConfigurationData>*> v(extracter.extract< CrcLocationData<CrcFeConfigurationData> >());

      for(unsigned i(0);i<v.size() && i<1;i++) {
	//if(               _cludge<= 5) d= v[i]->data()->dacData(0);
	//if(_cludge>= 6 && _cludge<=11) d= v[i]->data()->dacData(0);
	//if(_cludge>=12 && _cludge<=17) d=-v[i]->data()->dacData(0);
	//if(_cludge>=18               ) d=-v[i]->data()->dacData(0);

	d=v[i]->data()->dacData(0);
	if(_cludge>=12) {
	  d=-v[i]->data()->dacData(0);
	  if(d==0) d=-1;
	}
      }

      _nDac=0xffffffff;
      for(unsigned i(0);i<_dac.size();i++) {
	if(_dac[i]==d) _nDac=i;
      }

      if(_nDac==0xffffffff) {
	_nDac=_dac.size();
	_dac.push_back(d);
	cout << "Adding DAC setting " << _nDac << " = " << d << endl;
	for(unsigned fe(0);fe<8;fe++) {
	  for(unsigned chip(0);chip<12;chip++) {
	    _average[fe][chip].push_back(UtlAverage());
	  }
	}
      }

      return;
    }

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

    for(unsigned i(0);i<v.size();i++) {
      //cout << "Slot " << (unsigned)v[i]->slotNumber() << " seen" << endl;
      if(v[i]->slotNumber()==_slot) {
	//cout << "Slot " << _slot << " found" << endl;
	for(unsigned fe(0);fe<8;fe++) {
	  const CrcVlinkFeData *fd(v[i]->data()->feData(fe));
	  if(fd!=0) {
	    //cout << "FE" << fe << " data found" << endl;
	    for(unsigned chan(0);chan<v[i]->data()->feNumberOfAdcSamples(fe);chan++) {
	      const CrcVlinkAdcSample *as(fd->adcSample(chan));
	      if(as!=0) {
		//cout << "Chan" << chan << " data found" << endl;
		//for(unsigned chip(0);chip<12;chip++) {
		unsigned chip(_cludge%12);
		_average[fe][chip][_nDac]+=as->adc(chip);
		//cout << "FE" << fe << ", Chip " << chip << " has entries = " <<	_average[fe][chip][_nDac].number() << endl;
		//}
	      }
	    }
	  }
	}
      }
    }
  }

  void postscript(std::string file) {
    TCanvas c("PS Canvas","PS Canvas",10,10,600,400);
    c.cd();

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

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	for(unsigned i(0);i<3;i++) {
	  c.Clear();
	  _graph[fe][chip][i].Draw("AP");
	  c.Update();
	}
      }
    }

    c.Clear();
    _summary[0].Draw("AP");
    c.Update();

    c.Clear();
    _summary[1].Draw("AP");
    c.Update();

    ps.Close();
  }

private:
  TApplication _application;
  TCanvas *_canvas[3];
  HstTGraphErrors _graph[8][12][3];
  TGraphErrors _summary[2];

  unsigned _nDac;
  std::vector<int> _dac;
  std::vector<UtlAverage> _average[8][12];

  unsigned _slot,_fe,_chip;
  //int _dac[2];


  unsigned _cludge;
};

#endif
