#ifndef MpsAnalysisMaskThresholdScan_HH
#define MpsAnalysisMaskThresholdScan_HH

#include <cassert>

#include "RcdUserRO.hh"
#include "SubAccessor.hh"

#include "HstCfgScan.hh"
#include "HstCfgCount1D.hh"
#include "MpsSensor1BunchTrainData.hh"


class MpsAnalysisMaskThresholdScan : public MpsAnalysisBase {

public:
  MpsAnalysisMaskThresholdScan() : MpsAnalysisBase("MpsAnalysisMaskThresholdScan") {

    for(unsigned x(0);x<168;x++) {
      for(unsigned y(0);y<168;y++) {
        _hCfg[x][y]=new HstCfgCount1D(_pixelLabel[x][y].c_str(),_pixelTitle[x][y].c_str());
        _hCfgB[x][y]=new HstCfgCount1D((_pixelLabel[x][y]+"B").c_str(),(_pixelTitle[x][y]+", Bool").c_str());
      }
    }
  }

  virtual ~MpsAnalysisMaskThresholdScan() {
    if(_rootFile!=0) {
      _rootFile->cd();

      endRun();
      /*
      for(unsigned s(0);s<_vLocation.size();s++) {
	for(unsigned i(0);i<4;i++) {
	  _regionWords[s][i]->runEnd();
	  _regionLogWs[s][i]->runEnd();
	}
      } 
      */
    }
  }

  virtual bool mpsAnalysisValidRun(IlcRunType::Type t) const {
    return t==IlcRunType::mpsMaskThresholdScan;
  }

  /*
  void bookHist(unsigned x, unsigned y) {
    std::ostringstream sLabel;
    sLabel << _sensorLabel[0] << "X"
	   << std::setw(3) << std::setfill('0') << x << "Y"
	   << std::setw(3) << std::setfill('0') << y;
    
    std::ostringstream sTitle;
    sTitle << _runTitle << ", " << _sensorTitle[0]
	   << ", X " << x << ", Y " << y
	   << ", Number of hits vs threshold";

    //if(x<84) {
      _hHits[x][y]=new TH1F(sLabel.str().c_str(),
			    sTitle.str().c_str(),
			    _nBins,_loLimit,_hiLimit);
      _hHitd[x][y]=new TH1F((sLabel.str()+"D").c_str(),
			    (sTitle.str()+", derivative").c_str(),
			    _nBins,_loLimit+0.5*_bin,_hiLimit+0.5*_bin);
  */
      /*
      _hHitCBad[x][y]=new TH1F((sLabel.str()+"CBad").c_str(),
			    (sTitle.str()+", channels=0").c_str(),
			    _nBins,_loLimit+0.5*_bin,_hiLimit+0.5*_bin);
      */
      /*
    } else {
      _hHits[x][y]=new TH1F(sLabel.str().c_str(),
			    sTitle.str().c_str(),
			    _nBins,2.0*_loLimit,2.0*_hiLimit);
      _hHitd[x][y]=new TH1F((sLabel.str()+"D").c_str(),
			    (sTitle.str()+", derivative").c_str(),
			    _nBins,2.0*_loLimit+_bin,2.0*_hiLimit+_bin);
    }
      */
  /*
  }
*/

  bool runStart(const RcdRecord &r) {
    for(unsigned x(0);x<168;x++) {
      for(unsigned y(0);y<168;y++) {
	_trim[x][y]=0.0;
	_aCfg[x][y].reset();
      }
    }

    std::ifstream fin("MpsAnalysisMaskThresholdScanTrim.txt");
    if(fin) {

      unsigned xr,yr;
      double tr,rr;
      
      for(unsigned x(0);x<168;x++) {
	for(unsigned y(0);y<168;y++) {
	  fin >> xr >> yr >> tr >> rr;
	  assert(xr==x && yr==y);
	  _trim[x][y]=tr;
	}
      }
    }

    _hHits2=new TH2F("hHits2","Number of hits vs x,y",
		     168,0.0,168.0,168,0.0,168.0);

    std::ostringstream sLabel;
    sLabel << _sensorLabel[0] << "Scan";

    std::ostringstream sTitle;
    sTitle << _runTitle << ", " << _sensorTitle[0]
	   << ", Number of hits vs threshold";

    /*
      int nBins(60);
      _loLimit=-100.0;
      _hiLimit= 500.0;
    */
    _nBins=200;
    _loLimit=-100.0;
    _hiLimit= 300.0;
    _bin=(_hiLimit-_loLimit)/_nBins;

    
    _hScan=new TH1F(sLabel.str().c_str(),
		    sTitle.str().c_str(),
		    _nBins,_loLimit,_hiLimit);

    for(unsigned x(0);x<168;x++) {
      /*
      double limit(100.0);
      if(x>83) limit=200;
      if(_runStart.runNumber()==470391) limit=500.0;
      */

      for(unsigned y(0);y<168;y++) {

	std::ostringstream sLabel;
	sLabel << _sensorLabel[0] << "X"
	       << std::setw(3) << std::setfill('0') << x << "Y"
	       << std::setw(3) << std::setfill('0') << y;

	std::ostringstream sTitle;
	sTitle << _runTitle << ", " << _sensorTitle[0]
	       << ", X " << x << ", Y " << y
	       << ", Number of hits vs threshold";
	/*
	_hHits[x][y]=0;
	_hHitd[x][y]=0;
	*/
	//_hHitCBad[x][y]=0;
	/*
	_hHits[x][y]=new TH1F(sLabel.str().c_str(),
			      sTitle.str().c_str(),
			      nBins,_loLimit,_hiLimit);
	_hHitd[x][y]=new TH1F((sLabel.str()+"D").c_str(),
			      (sTitle.str()+", derivative").c_str(),
			      nBins,_loLimit,_hiLimit);
	*/
      }
    }

    for(unsigned x(0);x<168;x++) {
      for(unsigned y(0);y<168;y++) {
        _hCfg[x][y]->runStart(_runStart.runNumber(),"Threshold (TU)");
        _hCfgB[x][y]->runStart(_runStart.runNumber(),"Threshold (TU)");
      }
    }

    return true;
  }

  void endRun() {
    if(_rootFile!=0) {
      for(unsigned x(0);x<168;x++) {
        for(unsigned y(0);y<168;y++) {
          _hCfg[x][y]->runEnd();
          _hCfgB[x][y]->runEnd();
        }
      }

      /*
      //TF1 line("line","pol1",0,100000);
      TF1 line("gaus","gaus",-100000,100000);
      //_hMonoSummary=new TH1F("hMonoSummary","Summary",168*168,0.0,168.0*168.0);
      
      _hRawMean=new TH1F("hRawMean","Raw mean summary",500,_loLimit,_hiLimit);
      _hRawRms=new TH1F("hRawRms","Raw RMS summary",100,0.0,100.0);

      _hSummaryNorm=new TH1F("hSummaryNorm","Norm summary",100,0.0,100000.0);
      _hSummaryMean=new TH1F("hSummaryMean","Mean summary",500,_loLimit,_hiLimit);
      _hSummaryRms=new TH1F("hSummaryRms","RMS summary",100,0.0,100.0);

      _hPixelSummaryNorm=new TH1F("hPixelSummaryNorm","Pixel Norm summary",168*168,0.0,168.0*168.0);
      _hPixelSummaryMean=new TH1F("hPixelSummaryMean","Pixel Mean summary",168*168,0.0,168.0*168.0);
      _hPixelSummaryRms=new TH1F("hPixelSummaryRms","Pixel RMS summary",168*168,0.0,168.0*168.0);
      _hPixel2SummaryNorm=new TH1F("hPixel2SummaryNorm","Pixel Norm summary",168*168,0.0,168.0*168.0);
      _hPixel2SummaryMean=new TH1F("hPixel2SummaryMean","Pixel Mean summary",168*168,0.0,168.0*168.0);
      _hPixel2SummaryRms=new TH1F("hPixel2SummaryRms","Pixel RMS summary",168*168,0.0,168.0*168.0);

      _hQuadRawMean[0]=new TH1F("hRawMean0","Quad0, Raw mean summary",500,_loLimit,_hiLimit);
      _hQuadRawRms[0]=new TH1F("hRawRms0","Quad0, Raw RMS summary",100,0.0,100.0);
      _hQuadRawMean[1]=new TH1F("hRawMean1","Quad1, Raw mean summary",500,_loLimit,_hiLimit);
      _hQuadRawRms[1]=new TH1F("hRawRms1","Quad1, Raw RMS summary",100,0.0,100.0);
      _hQuadRawMean[2]=new TH1F("hRawMean2","Quad2, Raw mean summary",500,_loLimit,_hiLimit);
      _hQuadRawRms[2]=new TH1F("hRawRms2","Quad2, Raw RMS summary",100,0.0,100.0);
      _hQuadRawMean[3]=new TH1F("hRawMean3","Quad3, Raw mean summary",500,_loLimit,_hiLimit);
      _hQuadRawRms[3]=new TH1F("hRawRms3","Quad3, Raw RMS summary",100,0.0,100.0);

      _hQuadSummaryNorm[0]=new TH1F("hSummaryNorm0","Quad0, Norm summary",100,0.0,100000.0);
      _hQuadSummaryMean[0]=new TH1F("hSummaryMean0","Quad0, Mean summary",400,-200.0,200.0);
      _hQuadSummaryRms[0]=new TH1F("hSummaryRms0","Quad0, RMS summary",100,0.0,100.0);
      _hQuadSummaryNorm[1]=new TH1F("hSummaryNorm1","Quad1, Norm summary",100,0.0,100000.0);
      _hQuadSummaryMean[1]=new TH1F("hSummaryMean1","Quad1, Mean summary",400,-200.0,200.0);
      _hQuadSummaryRms[1]=new TH1F("hSummaryRms1","Quad1, RMS summary",100,0.0,100.0);
      _hQuadSummaryNorm[2]=new TH1F("hSummaryNorm2","Quad2, Norm summary",100,0.0,100000.0);
      _hQuadSummaryMean[2]=new TH1F("hSummaryMean2","Quad2, Mean summary",400,-200.0,200.0);
      _hQuadSummaryRms[2]=new TH1F("hSummaryRms2","Quad2, RMS summary",100,0.0,100.0);
      _hQuadSummaryNorm[3]=new TH1F("hSummaryNorm3","Quad3, Norm summary",100,0.0,100000.0);
      _hQuadSummaryMean[3]=new TH1F("hSummaryMean3","Quad3, Mean summary",400,-200.0,200.0);
      _hQuadSummaryRms[3]=new TH1F("hSummaryRms3","Quad3, RMS summary",100,0.0,100.0);
      
      std::ofstream fout("MpsAnalysisMaskThresholdScan.txt");
      std::ofstream gout("MpsAnalysisMaskThresholdScanRow0.txt");

      for(unsigned x(0);x<168;x++) {
	std::cout << "Fitting x = " << x << std::endl;

        for(unsigned y(0);y<168;y++) {
	  if(_hHits[x][y]!=0) {
	    if(_hHits[x][y]->GetEntries()==0) {
	      delete _hHits[x][y];
	      delete _hHitd[x][y];
	      //delete _hHitCBad[x][y];

	      if((x>=42 && x<84 && y==167) || (x==63 && y==0)) gout << " 0 0";

	    } else {
	      
	      
	      
	      //_pMono[x][y]->Approximate(kTRUE);
	      //_pMono[x][y]->Fit("line");
	      
	      if(_hHits[x][y]->GetMean()==0.0 || 
		 _hHits[x][y]->GetMean()>400.0) {
		std::cout << "Pixel " << x << " " << y << " has mean "
			  << _hHits[x][y]->GetMean() << " and RMS " 
			  << _hHits[x][y]->GetRMS() << std::endl;
	      }
	      
	      
	      _hRawMean->Fill(_hHits[x][y]->GetMean());
	      _hRawRms->Fill(_hHits[x][y]->GetRMS());
	      fout << std::setw(3) << x << " " << std::setw(3) << y << " "
		   << std::setw(12) << _hHits[x][y]->GetMean() << " "
		   << std::setw(12) << _hHits[x][y]->GetRMS() << std::endl;

	      if((x>=42 && x<84 && y==167) || (x==63 && y==0)) gout << " " << _hHits[x][y]->GetMean()
					     << " " << _hHits[x][y]->GetRMS();
	      
	      _hQuadRawMean[(x/84)+2*(y/84)]->Fill(_hHits[x][y]->GetMean());
	      _hQuadRawRms[(x/84)+2*(y/84)]->Fill(_hHits[x][y]->GetRMS());
	      
	      
	      _hHits[x][y]->Fit("gaus","Q");
	      double *p(line.GetParameters());
	      //double *e(line.GetParErrors());
	      if(line.GetChisquare()>0.0) {
		//_hMonoSummary->SetBinContent(168*x+y+1,p[1]);
		//_hMonoSummary->SetBinError(168*x+y+1,e[1]);
		_hSummaryNorm->Fill(p[0]);
		_hSummaryMean->Fill(p[1]);
		_hSummaryRms->Fill(p[2]);
		
		_hPixelSummaryNorm->Fill(168*x+y,p[0]);
		_hPixelSummaryMean->Fill(168*x+y,p[1]);
		_hPixelSummaryRms->Fill(168*x+y,p[2]);
		_hPixel2SummaryNorm->Fill(168*y+x,p[0]);
		_hPixel2SummaryMean->Fill(168*y+x,p[1]);
		_hPixel2SummaryRms->Fill(168*y+x,p[2]);
		
		_hQuadSummaryNorm[(x/84)+2*(y/84)]->Fill(p[0]);
		_hQuadSummaryMean[(x/84)+2*(y/84)]->Fill(p[1]);
		_hQuadSummaryRms[(x/84)+2*(y/84)]->Fill(p[2]);
	      }
	    }
	  } else {
	    if((x>=42 && x<84 && y==167) || (x==63 && y==0)) gout << " 0 0";
	  }
	}
      }
      fout.close();
      gout << std::endl;
      gout.close();
    }

      */

    /*
    for(unsigned s(0);s<_vLocation.size();s++) {
      for(unsigned i(0);i<4;i++) {
	_regionWords[s][i]->runEnd();
	_regionLogWs[s][i]->runEnd();
      }
      
      MpsSensor1ConfigurationData d;
      d.maskSensor(false);
      d.trimSensor(0);
      d.stripCheckBitCounter();
      
      for(unsigned x(0);x<168;x++) {
	if(_hiNorm[s][x/42]>0) {
	  double norm(1.0/_hiNorm[s][x/42]);
	  
	  for(unsigned y(0);y<168;y++) {
	    double fraction(_hiCount[s][x][y]*norm);
	    
	    if(_hiCount[s][x][y]>1 && fraction>0.000001) {
	      std::cout << _sensorTitle[s] << ", x " << std::setw(3) << x
			<< ", y " << std::setw(3) << y
			<< " Hi count = " << std::setw(6)
			<< _hiCount[s][x][y]
			<< ", norm = " << std::setw(10)
			<< _hiNorm[s][x/42]
			<< ", fraction = " << std::setw(10)
			<< fraction << std::endl;

	      d.mask(x,y,true);
	    }
	  }
	}
      }
      
      d.writeFile(_runLabel+_sensorLabel[s]+".cfg");
   }
    */
    }
    endRoot();
  }

  bool runEnd(const RcdRecord &r) {
    endRun();
    /*
    for(unsigned s(0);s<_vLocation.size();s++) {
      for(unsigned i(0);i<4;i++) {
	_regionWords[s][i]->runEnd();
	_regionLogWs[s][i]->runEnd();
      }

      MpsSensor1ConfigurationData d;
      d.maskSensor(false);
      d.trimSensor(0);
      d.stripCheckBitCounter();

      for(unsigned x(0);x<168;x++) {
	if(_hiNorm[s][x/42]>0) {
	  double norm(1.0/_hiNorm[s][x/42]);
	  
	  for(unsigned y(0);y<168;y++) {
	    double fraction(_hiCount[s][x][y]*norm);

	    if(_hiCount[s][x][y]>1 && fraction>0.000001) {
	      std::cout << _sensorTitle[s] << ", x " << std::setw(3) << x
			<< ", y " << std::setw(3) << y
			<< " Hi count = " << std::setw(6)
			<< _hiCount[s][x][y]
			<< ", norm = " << std::setw(10)
			<< _hiNorm[s][x/42]
			<< ", fraction = " << std::setw(10)
			<< fraction << std::endl;

	      d.mask(x,y,true);
	    }
	  }
	}
      }

      d.writeFile(_runLabel+_sensorLabel[s]+".cfg");
    }
    */
    return true;
  }

  bool configurationStart(const RcdRecord &r) {
    for(unsigned s(0);s<_vLocation.size();s++) {
      for(unsigned i(0);i<4;i++) {
	/*
	  _regionWords[s][i]->configurationStart(_vPcbConfigurationData[s].regionThresholdValue(i));
	  _regionLogWs[s][i]->configurationStart(_vPcbConfigurationData[s].regionThresholdValue(i));
	  
	  if(i<2) _hiThreshold[s][i]=_vPcbConfigurationData[s].regionThresholdValue(i)>= 500;
	  else    _hiThreshold[s][i]=_vPcbConfigurationData[s].regionThresholdValue(i)>=1000;
	  }
	  
	  _nBunchTrains[s]=_vUsbDaqConfigurationData[s].spillCycleCount()+1;
	  
	*/
	
	_thr[i]=_vPcbConfigurationData[s].regionThresholdValue(i);
	//std::cout << "Sensor " << s << ", region " << i << ", threshold value = " << _thr[i] << std::endl;
      }
    }

    for(unsigned x(0);x<168;x++) {
      for(unsigned y(0);y<168;y++) {
        _hCfg[x][y]->configurationStart((int)_thr[x/42]);
        _hCfgB[x][y]->configurationStart((int)_thr[x/42]);
      }
    }

    return true;
  }
  
  bool bunchTrain(const RcdRecord &r) {
    SubAccessor accessor(r);

    std::vector<const MpsLocationData<MpsSensor1BunchTrainData>* >
      //w(accessor.access< MpsLocationData<MpsSensor1BunchTrainData> >());
      w(sensor1BunchTrainData(r));
    assert(w.size()==_vLocation.size());

    for(unsigned s(0);s<w.size();s++) {
      if(w[s]!=0) {
	if(doPrint(r.recordType(),1)) w[s]->print(std::cout) << std::endl;

	bool pixelHit[168][168];
	for(unsigned x(0);x<168;x++) {
	  for(unsigned y(0);y<168;y++) {
	    pixelHit[x][y]=false;
	  }
	}

	/*	
	for(unsigned i(0);i<4;i++) {
	  unsigned nWords(w[s]->data()->numberOfRegionHits(i));

	  // For samplers, only count number of hits for small timestamps
	  if(i>=2) {
	    nWords=0;
	    const MpsSensor1BunchTrainDatum *p(w[s]->data()->regionData(i));
	    for(unsigned j(0);j<w[s]->data()->numberOfRegionHits(i);j++) {
	      if(p[j].timeStamp()<500) nWords++;
	    }
	  }

	  _regionWords[s][i]->Fill(nWords);
	  if(nWords>0) {
	    _regionLogWs[s][i]->Fill(std::log10((double)nWords));
	  }
	}
	*/

	for(unsigned region(0);region<4;region++) {
	  const MpsSensor1BunchTrainDatum *p(w[s]->data()->regionData(region));
	  for(unsigned j(0);j<w[s]->data()->numberOfRegionHits(region);j++) {
	    if(p[j].row()<168 && p[j].group()<7) {

	      for(unsigned c(0);c<6;c++) {
		if(p[j].channel(c)) {
                  pixelHit[c+6*p[j].group()+42*region][p[j].row()]=true;

		  _hHits2->Fill(c+6*p[j].group()+42*region,p[j].row());
		  _hScan->Fill(_thr[region]-_trim[c+6*p[j].group()+42*region][p[j].row()]);

		  /*
		  if(_hHits[c+6*p[j].group()+42*region][p[j].row()]==0) bookHist(c+6*p[j].group()+42*region,p[j].row());
		  _hHits[c+6*p[j].group()+42*region][p[j].row()]->Fill(_thr[region]);

		  //if(region<2) {
		    _hHitd[c+6*p[j].group()+42*region][p[j].row()]->Fill(_thr[region]+0.5*_bin);
		    _hHitd[c+6*p[j].group()+42*region][p[j].row()]->Fill(_thr[region]-0.5*_bin,-1.0);
		  */
		    /*
		  } else {
		    _hHitd[c+6*p[j].group()+42*region][p[j].row()]->Fill(_thr[region]+_bin);
		    _hHitd[c+6*p[j].group()+42*region][p[j].row()]->Fill(_thr[region]-_bin,-1.0);
		  }
		    */
		  _hCfg[c+6*p[j].group()+42*region][p[j].row()]->Fill();
		  _aCfg[c+6*p[j].group()+42*region][p[j].row()]+=_thr[region];
		}
	      }
	    }
	  }
	}

	for(unsigned x(0);x<168;x++) {
	  for(unsigned y(0);y<168;y++) {
	    if(pixelHit[x][y]) _hCfgB[x][y]->Fill();
	  }
	}
      }
    }

    return true;
  }

  void endRoot() {
    if(_rootFile!=0) {
      _rootFile->cd();

      std::cout << "Calling INHERITED endRoot" << std::endl;

      std::ostringstream fTitle;
      fTitle << "MpsAnalysisMaskThresholdScan"
	     << std::setfill('0') << std::setw(6)
	     << _runStart.runNumber() << ".txt";

      std::ofstream fout(fTitle.str().c_str());

      for(unsigned x(0);x<168;x++) {
        for(unsigned y(0);y<168;y++) {

	  /*
	  if(_hHits[x][y]!=0) {
	    fout << x << " " << y
		 << " " << _hHits[x][y]->GetEntries();
	    
	    if(_hHits[x][y]->GetEntries()!=0) {
	      fout << " " << _hHits[x][y]->GetMean()
		   << " " << _hHits[x][y]->GetRMS()
		   << std::endl;
	      
	    } else {
	      fout << " 0 0" << std::endl;
	    }
	  }
	  */

	  if(_aCfg[x][y].number()>0) {
	    fout << x << " " << y
		 << " " << _aCfg[x][y].number()
		 << " " << _aCfg[x][y].average()
		 << " " << _aCfg[x][y].sigma() << std::endl;
	  }

	}
      }

      fout.close();

      MpsAnalysisBase::endRoot();
    }
  }

private:
  double _thr[4];

  HstCfgCount1D *_hCfg[168][168];
  HstCfgCount1D *_hCfgB[168][168];
  UtlAverage _aCfg[168][168];

  int _nBins;
  double _loLimit;
  double _hiLimit;
  double _bin;

  double _trim[168][168];

  TH2F *_hHits2;
  TH1F *_hScan;
  //TH1F *_hHits[168][168];
  //TH1F *_hHitd[168][168];
  //TH1F *_hHitCBad[28][168];

  TH1F *_hRawMean;
  TH1F *_hRawRms;

  TH1F *_hQuadRawMean[4];
  TH1F *_hQuadRawRms[4];

  TH1F *_hSummaryNorm;
  TH1F *_hSummaryMean;
  TH1F *_hSummaryRms;

  TH1F *_hQuadSummaryNorm[4];
  TH1F *_hQuadSummaryMean[4];
  TH1F *_hQuadSummaryRms[4];

  TH1F *_hPixelSummaryNorm;
  TH1F *_hPixelSummaryMean;
  TH1F *_hPixelSummaryRms;
  TH1F *_hPixel2SummaryNorm;
  TH1F *_hPixel2SummaryMean;
  TH1F *_hPixel2SummaryRms;
};

#endif
