#ifndef MpsAnalysisThresholdScan_HH
#define MpsAnalysisThresholdScan_HH

#include <cassert>

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

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


class MpsAnalysisThresholdScan : public MpsAnalysisBase {

public:
  MpsAnalysisThresholdScan() : MpsAnalysisBase("MpsAnalysisThresholdScan") {
  }

  virtual ~MpsAnalysisThresholdScan() {
    if(_rootFile!=0) {
      _rootFile->cd();
      for(unsigned s(0);s<_vLocation.size();s++) {
	for(unsigned i(0);i<4;i++) {
	  _regionWords[s][i]->runEnd();
	  _regionLogWs[s][i]->runEnd();
	}
      } 
    }
    endRoot();
  }

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

  bool runStart(const RcdRecord &r) {
    assert(_vLocation.size()<=4);

    for(unsigned s(0);s<_vLocation.size();s++) {
      for(unsigned i(0);i<4;i++) {
	std::ostringstream sLabel[2];
	sLabel[0] << _sensorLabel[s] << "Region" << i << "Lin";
	sLabel[1] << _sensorLabel[s] << "Region" << i << "Log";
	
	std::ostringstream sTitle[2];
	sTitle[0] << "Region " << i << ", Number of words";
	sTitle[1] << "Region " << i << ", Log10(number of words)";
	
	_regionWords[s][i]=new HstCfgScan(sLabel[0].str().c_str(),
					  sTitle[0].str().c_str(),
					  3200,0.0,3200.0);
	
	_regionLogWs[s][i]=new HstCfgScan(sLabel[1].str().c_str(),
					  sTitle[1].str().c_str(),
					  1000,0.0,4.0);
      }
    }

    for(unsigned s(0);s<_vLocation.size();s++) {
      for(unsigned i(0);i<4;i++) {
	_regionWords[s][i]->runStart(_runStart.runNumber(),_sensorTitle[s]+", Threshold");
	_regionLogWs[s][i]->runStart(_runStart.runNumber(),_sensorTitle[s]+", Threshold");
      }

      for(unsigned i(0);i<4;i++) {
	_hiNorm[s][i]=0;
      }
      for(unsigned x(0);x<168;x++) {
	for(unsigned y(0);y<168;y++) {
	  _hiCount[s][x][y]=0;
	}
      }
    }
    return true;
  }

  bool runEnd(const RcdRecord &r) {
    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);

      for(unsigned i(0);i<168;i++) {
	for(unsigned j(0);j<5;j++) {
	  unsigned k(5*i+j);
	  unsigned kb(~k);
	  d.stripCheckBits(5*i+j,((kb&0xfff)<<12)+(k&0xfff));
	}
      }

      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;
    }
    return true;
  }
  
  bool bunchTrain(const RcdRecord &r) {
    SubAccessor accessor(r);

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

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

      for(unsigned i(0);i<4;i++) {
	_regionWords[s][i]->Fill(w[s]->data()->numberOfRegionHits(i));
	if(w[s]->data()->numberOfRegionHits(i)>0) {
	  _regionLogWs[s][i]->Fill(std::log10((double)w[s]->data()->numberOfRegionHits(i)));
	}
      }

      for(unsigned region(0);region<4;region++) {
	if(_hiThreshold[s][region]) {
	  _hiNorm[s][region]+=_nBunchTrains[s];
	  
	  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)) {
		  _hiCount[s][42*region+6*p[j].group()+c][p[j].row()]++;
		}
	      }
	    }
	  }
	}
      }
    }

    return true;
  }


private:
  HstCfgScan *_regionWords[4][4];
  HstCfgScan *_regionLogWs[4][4];

  bool _hiThreshold[4][4];
  unsigned _nBunchTrains[4];
  unsigned _hiNorm[4][4];
  unsigned _hiCount[4][168][168];
};

#endif
