#ifndef ChkDaqData_HH
#define ChkDaqData_HH

#include <iostream>
#include <fstream>

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

// dual/inc/rcd
#include "RcdHeader.hh"
#include "RcdUserRO.hh"

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


class ChkDaqData : public RcdUserRO {

public:
  ChkDaqData() : RcdUserRO() {
    for(unsigned i(0);i<100;i++) {
      _counts[0][i]=0;
      _counts[1][i]=0;
    }

    for(unsigned i(0);i<RcdHeader::endOfRecordTypeEnum;i++) {
      for(unsigned j(0);j<10;j++) {
	for(unsigned k(0);k<7;k++) {
	  _rcdCount[i][j][k]=0;
	}
      }
    }
  }

  virtual ~ChkDaqData() {
  }

  bool record(const RcdRecord &r) {

    // Check record header






    SubAccessor accessor(r);

    // Get lists of all relevant DAQ subrecords
    std::vector<const DaqRunStart*>
      vDRS(accessor.access<DaqRunStart>());
    std::vector<const DaqRunEnd*>
      vDRE(accessor.access<DaqRunEnd>());
    std::vector<const DaqConfigurationStart*>
      vDCS(accessor.access<DaqConfigurationStart>());
    std::vector<const DaqConfigurationEnd*>
      vDCE(accessor.access<DaqConfigurationEnd>());
    std::vector<const DaqSpillStart*>
      vDSS(accessor.access<DaqSpillStart>());
    std::vector<const DaqSpillEnd*>
      vDSE(accessor.access<DaqSpillEnd>());
    std::vector<const DaqEvent*>
      vDEV(accessor.access<DaqEvent>());

    _rcdCount[r.recordType()][vDRS.size()][0]++;
    _rcdCount[r.recordType()][vDRE.size()][1]++;
    _rcdCount[r.recordType()][vDCS.size()][2]++;
    _rcdCount[r.recordType()][vDCE.size()][3]++;
    _rcdCount[r.recordType()][vDSS.size()][4]++;
    _rcdCount[r.recordType()][vDSE.size()][5]++;
    _rcdCount[r.recordType()][vDEV.size()][6]++;


    // Check for type of record
    switch(r.recordType()) {

    case RcdHeader::runStart: {
      if(_printLevel>0) {
	std::cout << "ChkDaqData::record()  Number of DaqRunStart"
		  << " subrecords in runStart = " << vDRS.size() << std::endl;
	if(_printLevel>1) {
	  for(unsigned i(0);i<vDRS.size();i++) {
	    vDRS[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==1) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;


      if(vDRS.size()==1) {
	if(vDRS[0]->runNumber()>0) {
	  _counts[0][1]++;
	} else {
	  _counts[1][1]++;
	  std::cout << "ChkDaqData::record()  ERROR Run number"
		    << " in runStart = "<< vDRS[0]->runNumber() << std::endl;
	}

	if(vDRS[0]->runType()>0) {
	  _counts[0][2]++;
	} else {
	  _counts[1][2]++;
	  std::cout << "ChkDaqData::record()  ERROR Run type"
		    << " in runStart = "<< vDRS[0]->runType() << std::endl;
	}

	_mCpR=vDRS[0]->maximumNumberOfConfigurationsInRun();
	_mSpR=vDRS[0]->maximumNumberOfSpillsInRun();
	_mEpR=vDRS[0]->maximumNumberOfEventsInRun();

      } else {
	std::cout << "ChkDaqData::record()  ERROR Number of DaqRunStart"
		  << " subrecords in runStart = " << vDRS.size() << std::endl;

	_mCpR=0;
	_mSpR=0;
	_mEpR=0;
      }

      break;
    }

    case RcdHeader::runStop:
    case RcdHeader::runEnd: {
      if(_printLevel>0) {
	std::cout << "ChkDaqData::record()  Number of DaqRunEnd"
		  << " subrecords in runStop/End = " << vDRE.size() << std::endl;
	if(_printLevel>1) {
	  for(unsigned i(0);i<vDRE.size();i++) {
	    vDRE[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==1) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;

      if(vDRE.size()==1) {
	if(vDRE[0]->runNumber()>0) {
	  _counts[0][11]++;
	} else {
	  _counts[1][11]++;
	  std::cout << "ChkDaqData::record()  ERROR Run number"
		    << "in runStop/End = " << vDRE[0]->runNumber() << std::endl;
	}

	if(vDRE[0]->actualNumberOfConfigurationsInRun()==_nCpR) {
	  _counts[0][12]++;
	} else {
	  _counts[1][12]++;
	  std::cout << "ChkDaqData::record()  ERROR Actual number of configurations"
		    << "in runStop/End = " << vDRE[0]->actualNumberOfConfigurationsInRun() << std::endl;
	}

	if(vDRE[0]->actualNumberOfSpillsInRun()==_nSpR) {
	  _counts[0][13]++;
	} else {
	  _counts[1][13]++;
	  std::cout << "ChkDaqData::record()  ERROR Actual number of spills"
		    << "in runStop/End = " << vDRE[0]->actualNumberOfSpillsInRun() << std::endl;
	}

	if(vDRE[0]->actualNumberOfEventsInRun()==_nEpR) {
	  _counts[0][14]++;
	} else {
	  _counts[1][14]++;
	  std::cout << "ChkDaqData::record()  ERROR Actual number of events"
		    << "in runStop/End = " << vDRE[0]->actualNumberOfEventsInRun() << std::endl;
	}

      } else {
	std::cout << "ChkDaqData::record()  ERROR Number of DaqRunEnd"
		  << " subrecords in runStop/End = " << vDRE.size() << std::endl;
      }

      break;
    }

    case RcdHeader::configurationStart: {
      if(_printLevel>2) {
	std::cout << "ChkDaqData::record()  Number of DaqConfigurationStart"
		  << " subrecords in configurationStart = " << vDCS.size() << std::endl;
	if(_printLevel>3) {
	  for(unsigned i(0);i<vDCS.size();i++) {
	    vDCS[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==1) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;

      if(vDCS.size()==1) {
	if(vDCS[0]->configurationNumberInRun()==_nCpR) {
	  _counts[0][21]++;
	} else {
	  _counts[1][21]++;
	  std::cout << "ChkDaqData::record()  ERROR Number of configurations"
		    << "in runStop/End = " << vDCS[0]->configurationNumberInRun() << std::endl;
	}

	_mSpC=vDCS[0]->maximumNumberOfSpillsInConfiguration();
	_mEpC=vDCS[0]->maximumNumberOfEventsInConfiguration();

      } else {
	std::cout << "ChkDaqData::record()  ERROR Number of DaqConfigurationStart"
		  << " subrecords in configurationStart = " << vDCS.size() << std::endl;

	_mSpC=0;
	_mEpC=0;
      }

      break;
    }

    case RcdHeader::configurationStop:
    case RcdHeader::configurationEnd: {
      if(_printLevel>2) {
	std::cout << "ChkDaqData::record()  Number of DaqConfigurationEnd"
		  << " subrecords in configurationStart/End = " << vDCE.size() << std::endl;
	if(_printLevel>3) {
	  for(unsigned i(0);i<vDCE.size();i++) {
	    vDCE[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==1) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;

	if(vDCE[0]->actualNumberOfSpillsInConfiguration()==_nSpC) {
	  _counts[0][31]++;
	} else {
	  _counts[1][31]++;
	  std::cout << "ChkDaqData::record()  ERROR Actual number of spills"
		    << "in runStop/End = " << vDRE[0]->actualNumberOfSpillsInRun() << std::endl;
	}

	if(vDCE[0]->actualNumberOfEventsInConfiguration()==_nEpC) {
	  _counts[0][32]++;
	} else {
	  _counts[1][32]++;
	  std::cout << "ChkDaqData::record()  ERROR Actual number of events"
		    << "in runStop/End = " << vDRE[0]->actualNumberOfEventsInRun() << std::endl;
	}

      _nCpR++;

      break;
    }

    case RcdHeader::spillStart: {
      _counter=0;
      _beTrgCounter=0;
      _beCounter=0;
      for(unsigned i(0);i<8;i++) {
	_feCounter[i]=0;
	_vlinkCounter[i]=0;
      }

      if(_printLevel>4) {
	std::cout << "ChkDaqData::record()  Number of DaqSpillStart"
		  << " subrecords in spillStart = " << vDSS.size() << std::endl;
	if(_printLevel>5) {
	  for(unsigned i(0);i<vDSS.size();i++) {
	    vDSS[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==1) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;

      if(vDSS.size()==1) {
	_mEpS=vDSS[0]->maximumNumberOfEventsInSpill();

      } else {
	std::cout << "ChkDaqData::record()  ERROR Number of DaqSpillStart"
		  << " subrecords in spillStart = " << vDSS.size() << std::endl;

	_mEpS=0;
      }

      break;
    }

    case RcdHeader::spillStop:
    case RcdHeader::spillEnd: {
      if(_printLevel>4) {
	std::cout << "ChkDaqData::record()  Number of DaqSpillEnd"
		  << " subrecords in spillStart/End = " << vDSE.size() << std::endl;
	if(_printLevel>5) {
	  for(unsigned i(0);i<vDSE.size();i++) {
	    vDSE[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==1) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;

      if(vDSE[0]->actualNumberOfEventsInSpill()==_nEpS) {
	_counts[0][52]++;
	} else {
	  _counts[1][52]++;
	  std::cout << "ChkDaqData::record()  ERROR Actual number of events"
		    << "in runStop/End = " << vDSE[0]->actualNumberOfEventsInSpill() << std::endl;
	}

      _nSpR++;
      _nSpC++;

      break;
    }

    case RcdHeader::event: {
      if(_printLevel>6) {
	std::cout << "ChkDaqData::record()  Number of DaqEvent"
		  << " subrecords in event = " << vDEV.size() << std::endl;
	if(_printLevel>7) {
	  for(unsigned i(0);i<vDEV.size();i++) {
	    vDEV[i]->print(std::cout," ") << std::endl;
	  }
	}
      }

      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==1) _counts[0][60]++;
      else               _counts[1][60]++;

      std::vector<const DaqEvent*> de(accessor.access<DaqEvent>());
      assert(de.size()==1);

      //assert(de[0]->eventNumberInSpill()==_counter);
      if(de[0]->eventNumberInSpill()==_counter) {
	_counts[0][60]++;
      } else {
	_counts[1][60]++;
	if(_counts[1][60]<5) {
	  std::cout << "ChkDaqData::record()  ERROR DaqEvent event number in spill != counter = " << _counter << std::endl;
	  de[0]->print(std::cout," ERROR ");
	}
	_counter=de[0]->eventNumberInSpill();
      }
      _counter++;

      _nEpR++;
      _nEpC++;
      _nEpS++;

      break;
    }

    default: {  
      if(vDRS.size()==0) _counts[0][ 0]++;
      else               _counts[1][ 0]++;
      if(vDRE.size()==0) _counts[0][10]++;
      else               _counts[1][10]++;
      if(vDCS.size()==0) _counts[0][20]++;
      else               _counts[1][20]++;
      if(vDCE.size()==0) _counts[0][30]++;
      else               _counts[1][30]++;
      if(vDSS.size()==0) _counts[0][40]++;
      else               _counts[1][40]++;
      if(vDSE.size()==0) _counts[0][50]++;
      else               _counts[1][50]++;
      if(vDEV.size()==0) _counts[0][60]++;
      else               _counts[1][60]++;

      break;
    }
    };

    return true;
  }

  std::ostream& print(std::ostream& o, std::string s="") {
    o << s << "ChkDaqData::print()" << std::endl;

    for(unsigned i(0);i<100;i++) {
      if(_counts[0][i]>0 || _counts[1][i]>0) {
	o << s << " Count " << std::setw(4) << i 
	  << ", Good = " << std::setw(8) << _counts[0][i]
	  << ", bad = " << std::setw(8) << _counts[1][i] << std::endl;
      }
    }

    for(unsigned i(0);i<RcdHeader::endOfRecordTypeEnum;i++) {
      o << s << " Record type " << std::setw(2) << i << " = "
	<< RcdHeader::recordTypeName((RcdHeader::RecordType)i) << std::endl;
      for(unsigned k(0);k<7;k++) {
	o << s << "  List " << k << " counts =";
	for(unsigned j(0);j<10;j++) {
	  o << " " << _rcdCount[i][j][k];
	}
	o << std::endl;
      }
    }

    return o;
  }

private:
  unsigned _nCpR,_mCpR;
  unsigned _nSpR,_mSpR;
  unsigned _nEpR,_mEpR;
  unsigned _nSpC,_mSpC;
  unsigned _nEpC,_mEpC;
  unsigned _nEpS,_mEpS;

  unsigned _counter;
  unsigned _beTrgCounter;
  unsigned _beCounter;
  unsigned _feCounter[8];
  unsigned _vlinkCounter[8];
  unsigned _counts[2][100];

  unsigned _rcdCount[RcdHeader::endOfRecordTypeEnum][10][7];
};

#endif
