#ifndef HstBattery_HH
#define HstBattery_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 "HstTGraphErrors.hh"

// dual/inc/utl
#include "UtlAverage.hh"

// dual/inc/rcd
#include "RcdRecord.hh"

// dual/inc/crc
#include "CrcLocationData.hh"
#include "CrcVlinkEventData.hh"

// dual/inc/daq
#include "DaqEvent.hh"

// dual/inc/sub
#include "SubAccessor.hh"

// dual/inc/hst
#include "HstBase.hh"

Double_t QuadErr(Double_t *x, Double_t *par) {
  return sqrt(par[0]*par[0]+x[0]*x[0]*par[1]*par[1]);
}

class DacData {
public:
  DacData(unsigned d0, unsigned d1) : _dac0(d0), _dac1(d1) {}

  void print() {
    std::cout << "DacData::print() DAC0 = " 
	      << std::setw(5) << _dac0 << ", DAC1 = "
	      << std::setw(5) << _dac1 << std::endl;
    for(unsigned fe(0);fe<1;fe++) {
      for(unsigned chip(0);chip<1;chip++) {
	std::cout << "FE" << fe << ", Chip " << std::setw(2) << chip << ", ";
	_average[fe][chip].print(std::cout);
      }
    }
  }

  unsigned _dac0,_dac1;
  UtlAverage _average[8][12];
};


class HstBattery : public HstBase {

public:
  HstBattery(unsigned s=12, bool inter=false) : HstBase(inter), _slot(s), _fileNameStub("test") {

    gStyle->SetOptFit(1);
    gStyle->SetOptStat(111111);

    //_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,2);
    _canvas[1]->Divide(1,2);
    _canvas[2]->Divide(1,2);

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	for(unsigned i(0);i<3;i++) {
	  std::ostringstream sout[2];
	  if(chip<10) sout[0] << "FE" << fe << "Chip0" << chip;
	  else        sout[0] << "FE" << fe << "Chip"  << chip;
	  sout[1] << "FE" << fe << ", Chip " << std::setw(2) << chip << ", ADC distribution";
	  
	  if(i==0) _adcs[fe][chip][i]=new TH1F((sout[0].str()+"All").c_str(),sout[1].str().c_str(),600,-5000.0,25000.0);
	  if(i==1) _adcs[fe][chip][i]=new TH1F((sout[0].str()+"Ped").c_str(),sout[1].str().c_str(),100,-200.0,200.0);
	  if(i==2) _adcs[fe][chip][i]=new TH1F((sout[0].str()+"Sig").c_str(),sout[1].str().c_str(),400,18000.0,20000.0);
	  //_graph[fe][chip][dac][i].SetMarkerColor(1);
	  //_graph[fe][chip][dac][i].SetMarkerStyle(20);
	}
      }
    }

    _summary[0][0].Set(96);
    _summary[0][0].SetTitle("Pedestal vs 12*FE+Chip");
    _summary[0][0].SetMarkerColor(1);
    _summary[0][0].SetMarkerStyle(20);

    _summary[0][1].Set(96);
    _summary[0][1].SetTitle("Pedestal RMS vs 12*FE+Chip");
    _summary[0][1].SetMarkerColor(1);
    _summary[0][1].SetMarkerStyle(20);

    _summary[1][0].Set(96);
    _summary[1][0].SetTitle("Raw signal vs 12*FE+Chip");
    _summary[1][0].SetMarkerColor(1);
    _summary[1][0].SetMarkerStyle(20);

    _summary[1][1].Set(96);
    _summary[1][1].SetTitle("Raw signal RMS vs 12*FE+Chip");
    _summary[1][1].SetMarkerColor(1);
    _summary[1][1].SetMarkerStyle(20);

    _summary[2][0].Set(96);
    _summary[2][0].SetTitle("Signal vs 12*FE+Chip");
    _summary[2][0].SetMarkerColor(1);
    _summary[2][0].SetMarkerStyle(20);

    _summary[2][1].Set(96);
    _summary[2][1].SetTitle("Signal RMS vs 12*FE+Chip");
    _summary[2][1].SetMarkerColor(1);
    _summary[2][1].SetMarkerStyle(20);
  }

  virtual ~HstBattery() {
  }

  bool update() {
    update(false);
    return true;
  }

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

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	unsigned bin(12*fe+chip);

	double err1(_average[fe][chip][1].errorOnAverage());
	double err3(_average[fe][chip][3].errorOnAverage());
	
	_summary[0][0].SetPoint(     bin,bin,_average[fe][chip][1].average());
	_summary[0][0].SetPointError(bin,0.0,err1+0.001);
	_summary[0][1].SetPoint(     bin,bin,_average[fe][chip][1].sigma());
	_summary[0][1].SetPointError(bin,0.0,_average[fe][chip][1].errorOnSigma()+0.001);

	_summary[1][0].SetPoint(     bin,bin,_average[fe][chip][3].average());
	_summary[1][0].SetPointError(bin,0.0,err3+0.001);
	_summary[1][1].SetPoint(     bin,bin,_average[fe][chip][3].sigma());
	_summary[1][1].SetPointError(bin,0.0,_average[fe][chip][3].errorOnSigma()+0.001);

	_summary[2][0].SetPoint(     bin,bin,_average[fe][chip][3].average()-_average[fe][chip][1].average());
	_summary[2][0].SetPointError(bin,0.0,sqrt(err3*err3+err1*err1)+0.001);
	_summary[2][1].SetPoint(bin,bin,sqrt(_average[fe][chip][3].sigma()*_average[fe][chip][3].sigma()+
					     _average[fe][chip][1].sigma()*_average[fe][chip][1].sigma()));
	_summary[2][1].SetPointError(bin,0.0,_average[fe][chip][3].errorOnSigma()+0.001);
      }
    }

    /*
    double extraError(0.6);
    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	for(unsigned dac(0);dac<2;dac++) {
	  unsigned bin(_graph[fe][chip][dac][0].GetN());
	  
	  if(!fits) {
	    if(_dac[(dac+1)%2]==0) {
	      _graph[fe][chip][dac][0].Set(bin);
	      _graph[fe][chip][dac][0].SetPoint(bin,_dac[dac],_average[fe][chip].average());
	      double err(_average[fe][chip].errorOnAverage());
	      if((chip<=5 && dac==0) || (chip>=6 && dac==1)) err=sqrt(err*err+extraError*extraError);
	      _graph[fe][chip][dac][0].SetPointError(bin,0.0,err);
	      
	      _graph[fe][chip][dac][1].Set(bin);
	      _graph[fe][chip][dac][1].SetPoint(bin,_dac[dac],_average[fe][chip].sigma());
	      _graph[fe][chip][dac][1].SetPointError(bin,0.0,_average[fe][chip].errorOnSigma());
	    }
	    



	  } else {

	    _graph[fe][chip][dac][0].Fit("pol1","Q",0,5000.0,50000.0);
	    double *pars=_graph[fe][chip][dac][0].GetFunction("pol1")->GetParameters();
	    double *errs=_graph[fe][chip][dac][0].GetFunction("pol1")->GetParErrors();
	    double chisq=_graph[fe][chip][dac][0].GetFunction("pol1")->GetChisquare();
	    int     nDof=_graph[fe][chip][dac][0].GetFunction("pol1")->GetNDF();
	    if(nDof>0) chisq/=nDof;
	    else       chisq=-1.0;
	    
	    _graph[fe][chip][dac][2].Set(bin);
	    for(unsigned i(0);i<(unsigned)_graph[fe][chip][dac][0].GetN();i++) {
	      double x,y;
	      _graph[fe][chip][dac][0].GetPoint(i,x,y);
	      if(x>=1000.0) {
		_graph[fe][chip][dac][2].SetPoint(i,x,y-pars[0]-x*pars[1]);
		_graph[fe][chip][dac][2].SetPointError(i,0.0,_graph[fe][chip][dac][0].GetErrorY(i));
	      }
	    }
	    
	    if((chip<=5 && dac==0) || (chip>=6 && dac==1)) {
	      _summary[0][0].SetPoint(12*fe+chip,12*fe+chip,pars[0]);
	      _summary[0][0].SetPointError(12*fe+chip,0.0,errs[0]);
	      _summary[0][1].SetPoint(12*fe+chip,12*fe+chip,pars[1]);
	      _summary[0][1].SetPointError(12*fe+chip,0.0,errs[1]);
	    } else {
	      _summary[1][0].SetPoint(12*fe+chip,12*fe+chip,pars[0]);
	      _summary[1][0].SetPointError(12*fe+chip,0.0,errs[0]);
	      _summary[1][1].SetPoint(12*fe+chip,12*fe+chip,pars[1]);
	      _summary[1][1].SetPointError(12*fe+chip,0.0,errs[1]);
	    }
	    
	    TF1 quadErr("quadErr",QuadErr,0,100000,2);
	    Double_t qpar[2];
	    qpar[0]=1.3;
	    qpar[1]=0.000036;
	    quadErr.SetParameters(qpar);

	    _graph[fe][chip][dac][1].Fit("quadErr","Q",0,2000.0,50000.0);
	    pars=_graph[fe][chip][dac][1].GetFunction("quadErr")->GetParameters();
	    errs=_graph[fe][chip][dac][1].GetFunction("quadErr")->GetParErrors();
	    chisq=_graph[fe][chip][dac][1].GetFunction("quadErr")->GetChisquare();
	    nDof=_graph[fe][chip][dac][1].GetFunction("quadErr")->GetNDF();
	    if(nDof>0) chisq/=nDof;
	    else       chisq=-1.0;
	    
	    _graph[fe][chip][dac][3].Set(bin);
	    for(unsigned i(0);i<(unsigned)_graph[fe][chip][dac][1].GetN();i++) {
	      double x,y;
	      _graph[fe][chip][dac][1].GetPoint(i,x,y);
	      if(x>=1000.0) {
		_graph[fe][chip][dac][3].SetPoint(i,x,y-QuadErr(&x,pars));
		_graph[fe][chip][dac][3].SetPointError(i,0.0,_graph[fe][chip][dac][1].GetErrorY(i));
	      }
	    }
	    
	    if((chip<=5 && dac==0) || (chip>=6 && dac==1)) {
	      _summary[2][0].SetPoint(12*fe+chip,12*fe+chip,pars[0]);
	      _summary[2][0].SetPointError(12*fe+chip,0.0,errs[0]);
	      _summary[2][1].SetPoint(12*fe+chip,12*fe+chip,pars[1]);
	      _summary[2][1].SetPointError(12*fe+chip,0.0,errs[1]);
	    }
	  }
	}
	_average[fe][chip].reset();
      }
    }
    */

    for(unsigned i(0);i<3;i++) {
      _canvas[i]->cd(1);
      _summary[i][0].Draw("AP");
      _canvas[i]->cd(2);
      _summary[i][1].Draw("AP");
    }
  }

  bool record(const RcdRecord &r) {
    if(r.recordType()==RcdHeader::runEnd ||
       r.recordType()==RcdHeader::runStop) {
      update(true);
      postscript(_fileNameStub+"Batt.ps");
      return true;
    }

    SubAccessor accessor(r);
    
    if(r.recordType()==RcdHeader::runStart) {
      bool slotUsed(false);
      std::ostringstream sout;

      std::vector<const CrcLocationData<CrcVmeRunData>*>
	w(accessor.access< CrcLocationData<CrcVmeRunData> >());
      for(unsigned i(0);i<w.size();i++) {
	w[i]->print(std::cout);
	if(w[i]->slotNumber()==_slot) {
	  slotUsed=true;
	  sout << "SER0";
	  if(w[i]->data()->serialNumber()<10) sout << "0";
	  sout << (unsigned)w[i]->data()->serialNumber();
	}
      }
      assert(slotUsed);

      std::vector<const DaqRunStart*>
	v(accessor.access<DaqRunStart>());
      assert(v.size()==1);
      v[0]->print(std::cout);

      sout << "Run" << v[0]->runNumber() << "Slot";
      if(_slot<10) sout << "0";
      sout << _slot;
      _fileNameStub=sout.str();

      return true;
    }

    if(r.recordType()!=RcdHeader::event) return true;

    //update(false);
    
    std::vector<const CrcLocationData<CrcVlinkEventData>*>
      v(accessor.access<CrcLocationData<CrcVlinkEventData> >());

    for(unsigned i(0);i<v.size();i++) {
      if(v[i]->slotNumber()==_slot) {
	bool outOfRange(false);

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

	    bool chipSignal[12]={false,false,false,false,false,false,
				 false,false,false,false,false,false};

	    // Loop over mplex channel number
	    for(unsigned chan(0);chan<v[i]->data()->feNumberOfAdcSamples(fe);chan++) {
	      const CrcVlinkAdcSample *as(fd->adcSample(chan));
	      if(as!=0) {
		
		// Loop over chips=ADCs
		for(unsigned chip(0);chip<12;chip++) {
		  _adcs[fe][chip][0]->Fill(as->adc(chip));
		  _adcs[fe][chip][1]->Fill(as->adc(chip));
		  _adcs[fe][chip][2]->Fill(as->adc(chip));

		  unsigned n(0);
		  if(as->adc(chip)> -100) n=1;
		  if(as->adc(chip)>  100) n=2;
		  if(as->adc(chip)>18400) n=3;
		  if(as->adc(chip)>19800) n=4;

		  if(n==3) chipSignal[chip]=true;
	      
		  if(n<1 || n>3) {
		    outOfRange=true;
		    /*
		    std::cout << "FE" << fe << ", Chip " << chip << ", Chan "
			      << chan << ", ADC = " << as->adc(chip)
			      << std::endl;
		    */
		  }

		  _average[fe][chip][n].event(as->adc(chip));
		}
	      }
	    }

	    unsigned nSignal(0);
	    for(unsigned chip(0);chip<12;chip++) {
	      if(chipSignal[chip]) nSignal++;
	    }

	    if(nSignal!=6 && nSignal!=12) {
	    }

	  }
	}
	//if(outOfRange) v[i]->print(std::cout) << std::endl;
      }
    }

    return true;
  }

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

    gPad->SetLogy(true);

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

    /*
    TF1 quadErr("quadErr",QuadErr,0,100000,2);
    Double_t parPol1[8][12][2][2],errPol1[8][12][2][2],chiPol1[8][12][2];
    Double_t parQuad[8][12][2][2],errQuad[8][12][2][2],chiQuad[8][12][2];

    Double_t *p;
    Double_t qpar[2];

    HstTGraphErrors g[18];
    g[ 0].SetTitle("Disabled Dacs, Mean vs. 12*FE+Chip");
    g[ 1].SetTitle("Disabled Dacs, Rms vs. 12*FE+Chip");

    g[ 2].SetTitle("On-Dac Fit Interpolation vs. 12*FE+Chip");
    g[ 3].SetTitle("On-Dac Fit Slope vs. 12*FE+Chip");
    g[ 4].SetTitle("On-Dac Fit Chi-sq/Ndof vs. 12*FE+Chip");
    g[ 5].SetTitle("Off-Dac Fit Interpolation vs. 12*FE+Chip");
    g[ 6].SetTitle("Off-Dac Fit Slope vs. 12*FE+Chip");
    g[ 7].SetTitle("Off-Dac Fit Chi-sq/Ndof vs. 12*FE+Chip");

    g[ 8].SetTitle("On-Dac Fit Baseline Noise vs. 12*FE+Chip");
    g[ 9].SetTitle("On-Dac Fit Dac Noise vs. 12*FE+Chip");
    g[10].SetTitle("On-Dac Fit Chi-sq/Ndof vs. 12*FE+Chip");
    g[11].SetTitle("Off-Dac Fit Baseline Noise vs. 12*FE+Chip");
    g[12].SetTitle("Off-Dac Fit Dac Noise vs. 12*FE+Chip");
    g[13].SetTitle("Off-Dac Fit Chi-sq/Ndof vs. 12*FE+Chip");

    g[14].SetTitle("On-Dac Interpolation-Mean vs. 12*FE+Chip");
    g[15].SetTitle("On-Dac Baseline Noise-Rms vs. 12*FE+Chip");
    g[16].SetTitle("Off-Dac Interpolation-Mean vs. 12*FE+Chip");
    g[17].SetTitle("Off-Dac Baseline Noise-Rms vs. 12*FE+Chip");
    */

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	for(unsigned i(0);i<3;i++) {
	/*
	for(unsigned dac(0);dac<2;dac++) {
	  HstTGraphErrors gm;
	  gm.SetMarkerStyle(20);
	  gm.SetMarkerSize(0.5);

	  {std::ostringstream sout;
	  sout << "FE" << fe << " Chip " <<std::setw(2) << chip;
	  if(dac==0) sout << " Mean vs. BotDac";
	  else       sout << " Mean vs. TopDac";
	  gm.SetTitle(sout.str().c_str());}

	  HstTGraphErrors ge;
	  ge.SetMarkerSize(0.5);

	  {std::ostringstream sout;
	  sout << "FE" << fe << " Chip " <<std::setw(2) << chip;
	  if(dac==0) sout << " Rms vs. BotDac";
	  else       sout << " Rms vs. TopDac";
	  ge.SetTitle(sout.str().c_str());}

	  for(unsigned i(0);i<_vDacData.size();i++) {
	    if(dac==0 && _vDacData[i]._dac1==0) {
	      gm.AddPoint(_vDacData[i]._dac0,_vDacData[i]._average[fe][chip].average(),0.0,_vDacData[i]._average[fe][chip].errorOnAverage()+0.0001);
	      ge.AddPoint(_vDacData[i]._dac0,_vDacData[i]._average[fe][chip].sigma(),0.0,_vDacData[i]._average[fe][chip].errorOnSigma()+0.0001);
	    }
	    if(dac==1 && _vDacData[i]._dac0==0) {
	      gm.AddPoint(_vDacData[i]._dac1,_vDacData[i]._average[fe][chip].average(),0.0,_vDacData[i]._average[fe][chip].errorOnAverage()+0.0001);
	      ge.AddPoint(_vDacData[i]._dac1,_vDacData[i]._average[fe][chip].sigma(),0.0,_vDacData[i]._average[fe][chip].errorOnSigma()+0.0001);
	    }
	  }

	  // Linear fit
	  gm.Fit("pol1","Q",0,1.0,40000.0);
	  p=gm.GetFunction("pol1")->GetParameters();
	  if((dac==0 && chip<=5) || (dac==1 && chip>=6)) {
	    parPol1[fe][chip][0][0]=p[0];
	    parPol1[fe][chip][0][1]=p[1];
	  } else {
	    parPol1[fe][chip][1][0]=p[0];
	    parPol1[fe][chip][1][1]=p[1];
	  }

	  p=gm.GetFunction("pol1")->GetParErrors();
	  if((dac==0 && chip<=5) || (dac==1 && chip>=6)) {
	    errPol1[fe][chip][0][0]=p[0];
	    errPol1[fe][chip][0][1]=p[1];
	  } else {
	    errPol1[fe][chip][1][0]=p[0];
	    errPol1[fe][chip][1][1]=p[1];
	  }

	  double chisq=gm.GetFunction("pol1")->GetChisquare();
	  int     nDof=gm.GetFunction("pol1")->GetNDF();
	  if((dac==0 && chip<=5) || (dac==1 && chip>=6)) {
	    if(nDof>0) chiPol1[fe][chip][0]=chisq/nDof;
	    else       chiPol1[fe][chip][0]=-1.0;
	  } else {
	    if(nDof>0) chiPol1[fe][chip][1]=chisq/nDof;
	    else       chiPol1[fe][chip][1]=-1.0;
	  }

	  // Quadratic fit
	  qpar[0]=1.3;
	  qpar[1]=0.000036;
	  quadErr.SetParameters(qpar);
	  ge.Fit("quadErr","Q",0,1.0,40000.0);

	  p=ge.GetFunction("quadErr")->GetParameters();
	  if((dac==0 && chip<=5) || (dac==1 && chip>=6)) {
	    parQuad[fe][chip][0][0]=fabs(p[0]);
	    parQuad[fe][chip][0][1]=fabs(p[1]);
	  } else {
	    parQuad[fe][chip][1][0]=fabs(p[0]);
	    parQuad[fe][chip][1][1]=fabs(p[1]);
	  }

	  p=ge.GetFunction("quadErr")->GetParErrors();
	  if((dac==0 && chip<=5) || (dac==1 && chip>=6)) {
	    errQuad[fe][chip][0][0]=p[0];
	    errQuad[fe][chip][0][1]=p[1];
	  } else {
	    errQuad[fe][chip][1][0]=p[0];
	    errQuad[fe][chip][1][1]=p[1];
	  }

	  chisq=ge.GetFunction("quadErr")->GetChisquare();
           nDof=ge.GetFunction("quadErr")->GetNDF();
	  if((dac==0 && chip<=5) || (dac==1 && chip>=6)) {
	    if(nDof>0) chiQuad[fe][chip][0]=chisq/nDof;
	    else       chiQuad[fe][chip][0]=-1.0;
	  } else {
	    if(nDof>0) chiQuad[fe][chip][1]=chisq/nDof;
	    else       chiQuad[fe][chip][1]=-1.0;
	  }

	  c.Clear();
	  gm.Draw("AP");
	  c.Update();

	  c.Clear();
	  ge.Draw("AP");
	  c.Update();
	}
	*/

	//c.Clear();
	  _adcs[fe][chip][i]->Draw();
	  c.Update();
	}
      }
    }

    /*
    bool errors[8][12][9][2];
    double disabledMeanLo(-150.0),disabledMeanHi(150.0);
    double disabledRmsLo(1.1),disabledRmsHi(1.6);
    double onSlopeLo(0.44),onSlopeHi(0.46);
    double offSlopeLo(-0.0001),offSlopeHi(0.0001);
    double dacNoiseLo(0.00003),dacNoiseHi(0.00004);

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	for(unsigned i(0);i<9;i++) {
	  for(unsigned j(0);j<2;j++) {
	    errors[fe][chip][i][j]=false;
	  }
	}
      }
    }
    */

	/*
    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {

	// Disabled mean
	g[ 0].AddPoint(12*fe+chip,_average[fe][chip].average(),0.0,_average[fe][chip].errorOnAverage());
	if(_average[fe][chip].average()<disabledMeanLo) errors[fe][chip][0][0]=true;
	if(_average[fe][chip].average()>disabledMeanHi) errors[fe][chip][0][1]=true;

	// Disabled rms
	g[ 1].AddPoint(12*fe+chip,_average[fe][chip].sigma(),0.0,_average[fe][chip].errorOnSigma());
	if(_average[fe][chip].sigma()<disabledRmsLo) errors[fe][chip][1][0]=true;
	if(_average[fe][chip].sigma()>disabledRmsHi) errors[fe][chip][1][1]=true;

	// On-dac fit
	g[ 2].AddPoint(12*fe+chip,parPol1[fe][chip][0][0],0.0,errPol1[fe][chip][0][0]);
	if(parPol1[fe][chip][0][0]<disabledMeanLo) errors[fe][chip][2][0]=true;
	if(parPol1[fe][chip][0][0]>disabledMeanHi) errors[fe][chip][2][1]=true;

	g[ 3].AddPoint(12*fe+chip,parPol1[fe][chip][0][1],0.0,errPol1[fe][chip][0][1]);
	if(parPol1[fe][chip][0][1]<onSlopeLo) errors[fe][chip][3][0]=true;
	if(parPol1[fe][chip][0][1]>onSlopeHi) errors[fe][chip][3][1]=true;

	g[ 4].AddPoint(12*fe+chip,chiPol1[fe][chip][0],0.0,0.0);

	// Off-dac fit
	g[ 5].AddPoint(12*fe+chip,parPol1[fe][chip][1][0],0.0,errPol1[fe][chip][1][0]);
	if(parPol1[fe][chip][1][0]<disabledMeanLo) errors[fe][chip][4][0]=true;
	if(parPol1[fe][chip][1][0]>disabledMeanHi) errors[fe][chip][4][1]=true;

	g[ 6].AddPoint(12*fe+chip,parPol1[fe][chip][1][1],0.0,errPol1[fe][chip][1][1]);
	if(parPol1[fe][chip][1][1]<offSlopeLo) errors[fe][chip][5][0]=true;
	if(parPol1[fe][chip][1][1]>offSlopeHi) errors[fe][chip][5][1]=true;

	g[ 7].AddPoint(12*fe+chip,chiPol1[fe][chip][1],0.0,0.0);
	  
	// On-dac noise fit
	g[ 8].AddPoint(12*fe+chip,parQuad[fe][chip][0][0],0.0,errQuad[fe][chip][0][0]);
	if(parQuad[fe][chip][0][0]<disabledRmsLo) errors[fe][chip][6][0]=true;
	if(parQuad[fe][chip][0][0]>disabledRmsHi) errors[fe][chip][6][1]=true;

	g[ 9].AddPoint(12*fe+chip,parQuad[fe][chip][0][1],0.0,errQuad[fe][chip][0][1]);
	if(parQuad[fe][chip][0][1]<dacNoiseLo) errors[fe][chip][7][0]=true;
	if(parQuad[fe][chip][0][1]>dacNoiseHi) errors[fe][chip][7][1]=true;

	g[10].AddPoint(12*fe+chip,chiQuad[fe][chip][0],0.0,0.0);

	// Off-dac noise fit
	g[11].AddPoint(12*fe+chip,parQuad[fe][chip][1][0],0.0,errQuad[fe][chip][1][0]);
	if(parQuad[fe][chip][1][0]<disabledRmsLo) errors[fe][chip][8][0]=true;
	if(parQuad[fe][chip][1][0]>disabledRmsHi) errors[fe][chip][8][1]=true;

	g[12].AddPoint(12*fe+chip,parQuad[fe][chip][1][1],0.0,errQuad[fe][chip][1][1]);
	g[13].AddPoint(12*fe+chip,chiQuad[fe][chip][1],0.0,0.0);

	double totalError;

	totalError=sqrt(_average[fe][chip].errorOnAverage()*_average[fe][chip].errorOnAverage()+
			errPol1[fe][chip][0][0]*errPol1[fe][chip][0][0]);
	g[14].AddPoint(12*fe+chip,parPol1[fe][chip][0][0]-_average[fe][chip].average(),0.0,totalError);

	totalError=sqrt(_average[fe][chip].errorOnSigma()*_average[fe][chip].errorOnSigma()+
			errQuad[fe][chip][0][0]*errQuad[fe][chip][0][0]);
	g[15].AddPoint(12*fe+chip,parQuad[fe][chip][0][0]-_average[fe][chip].sigma(),0.0,totalError);

	totalError=sqrt(_average[fe][chip].errorOnAverage()*_average[fe][chip].errorOnAverage()+
			errPol1[fe][chip][1][0]*errPol1[fe][chip][1][0]);
	g[16].AddPoint(12*fe+chip,parPol1[fe][chip][1][0]-_average[fe][chip].average(),0.0,totalError);

	totalError=sqrt(_average[fe][chip].errorOnSigma()*_average[fe][chip].errorOnSigma()+
			errQuad[fe][chip][1][0]*errQuad[fe][chip][1][0]);
	g[17].AddPoint(12*fe+chip,parQuad[fe][chip][1][0]-_average[fe][chip].sigma(),0.0,totalError);
      }
    }
    for(unsigned i(0);i<18;i++) {
      g[i].SetMarkerSize(0.5);

      c.Clear();
      g[i].Draw("AP");
      c.Update();
    }
	*/
    gPad->SetLogy(false);

    for(unsigned i(0);i<3;i++) {
      for(unsigned j(0);j<2;j++) {
	c.Clear();
	_summary[i][j].Draw("AP");
	c.Update();
      }
    }

    ps.Close();

    _average[0][0][1].print(std::cout);


    std::ofstream fout((_fileNameStub+"Batt.txt").c_str());
    fout << _fileNameStub << std::endl
	 << "                    Pdstl  Noise  Range" << std::endl
	 << "                    Lo Hi  Lo Hi  Lo Hi" << std::endl;
 

    for(unsigned fe(0);fe<8;fe++) {
      for(unsigned chip(0);chip<12;chip++) {
	bool anyErrors(false);

	if(_average[fe][chip][1].average()<-50) anyErrors=true;
	if(_average[fe][chip][1].average()> 50) anyErrors=true;

	if(_average[fe][chip][1].sigma()<0.1) anyErrors=true;
	if(_average[fe][chip][1].sigma()>2.5) anyErrors=true;

	if(_average[fe][chip][0].number()>0) anyErrors=true;
	if(_average[fe][chip][4].number()>0) anyErrors=true;

	if(anyErrors) {
	  fout << "#";
	  if((12*fe+chip)<10) fout << "0";
	  fout << 12*fe+chip << " = FE" << fe << ", Chip ";
	  if(chip<10) fout << " ";
	  fout << chip;

	  fout << "   ";
	  if(_average[fe][chip][1].average()<-50.0) fout << "X";
	  else                                      fout << " ";

	  fout << "  ";
	  if(_average[fe][chip][1].average()> 50.0) fout << "X";
	  else                                      fout << " ";

	  fout << "   ";
	  if(_average[fe][chip][1].sigma()<0.1) fout << "X";
	  else                                  fout << " ";

	  fout << "  ";
	  if(_average[fe][chip][1].sigma()>2.5) fout << "X";
	  else                                  fout << " ";

	  fout << "   ";
	  if(_average[fe][chip][0].number()>0) fout << "X";
	  else                                 fout << " ";

	  fout << "  ";
	  if(_average[fe][chip][4].number()>0) fout << "X";
	  else                                 fout << " ";

	  fout << std::endl;
	}
      }
    }

    return true;
  }

private:
  //TApplication _application;
  TCanvas *_canvas[4];
  TH1F *_adcs[8][12][3];
  //TGraphErrors _graph[8][12][2][4];
  TGraphErrors _summary[3][2];


  std::vector<TGraphErrors*> _vConfig[3];
  UtlAverage _average[8][12][5];

  unsigned _slot;
  std::string _fileNameStub;
  bool _dacEnable;
  unsigned _dac[2];
  unsigned _nDacData;
  std::vector<DacData> _vDacData;
};

#endif
