#ifndef MpsAnalysisCheck_HH
#define MpsAnalysisCheck_HH

#include <cassert>

#include "TFile.h"
#include "TF1.h"
#include "TH1F.h"
#include "TH2F.h"
#include "TProfile.h"

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

#include "MpsAnalysisBase.hh"
#include "MpsSensor1HitLists.hh"


class MpsAnalysisCheck : public MpsAnalysisBase {

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

  virtual ~MpsAnalysisCheck() {
    endRoot();
  }

  virtual bool mpsAnalysisValidRun(IlcRunType::Type t) const {
    return true; // Check all runs
  }

  bool runStart(const RcdRecord &r) {
    SubAccessor accessor(r);

    std::vector<const MpsLocationData<MpsUsbDaqRunData>* >
      v(accessor.access< MpsLocationData<MpsUsbDaqRunData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << v.size() << " MpsUsbDaqRunData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<v.size();i++) {
	  v[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    _vUsbDaqRunData.clear();
    /*
    _vLocation.clear();
    _vUsbDaqConfigurationValid.clear();
    _vUsbDaqConfigurationData.clear();
    _vPcbConfigurationValid.clear();
    _vPcbConfigurationData.clear();
    _vSensorConfigurationValid.clear();
    _vSensorConfigurationData.clear();
    */

    for(unsigned i(0);i<v.size();i++) {
      //_vLocation.push_back(v[i]->location());
      _vUsbDaqRunData.push_back(*(v[i]->data()));

      //_vUsbDaqConfigurationValid.push_back(false);
      //_vUsbDaqConfigurationData.push_back(MpsUsbDaqConfigurationData());
      //_vPcbConfigurationValid.push_back(false);
      //_vPcbConfigurationData.push_back(MpsPcb1ConfigurationData());
      //_vSensorConfigurationValid.push_back(false);
      //_vSensorConfigurationData.push_back(MpsSensor1ConfigurationData());
    }

    _runStartTime=r.recordTime();

    _hTemp=new TH2F("hTemp","Temperature since start of run;Sec;C",
		    500,0.0,100000.0,300,10.0,40.0);
    _pTemp=new TProfile("pTemp","Temperature since start of run;Sec;C",
			500,0.0,100000.0);
    return true;
  }

  bool runEnd(const RcdRecord &r) {
    SubAccessor accessor(r);

    assert(_vUsbDaqRunData.size()==_vLocation.size());

    std::vector<const MpsLocationData<MpsUsbDaqRunData>* >
      v(accessor.access< MpsLocationData<MpsUsbDaqRunData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << v.size() << " MpsUsbDaqRunData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<v.size();i++) {
	  v[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    assert(v.size()==_vLocation.size());

    for(unsigned i(0);i<v.size();i++) { 
      bool checked(false);
      //for(unsigned j(0);j<_vUsbDaqRunData.size();j++) {
      unsigned j(i); {
	
	if(v[i]->location()==_vLocation[j]) {
	  //if(v[i]->usbDaqAddress()==_vLocation[j].usbDaqAddress()) {

	  checked=true;
	  assert(_vLocation[j]==v[i]->location());
	  assert(_vUsbDaqRunData[j]==*(v[i]->data()));
	} else {
	  std::cout << " Locations for USB_DAQ " << j << " do not agree" << std::endl;
	  _vLocation[j].print(std::cout," STORED ");
	  v[i]->location().print(std::cout," READ   ");
	}
      }
      assert(checked);
    }

    return true;
  }

  bool configurationStart(const RcdRecord &r) {
    SubAccessor accessor(r);

    std::vector<const MpsLocationData<MpsUsbDaqConfigurationData>* >
      w(accessor.access< MpsLocationData<MpsUsbDaqConfigurationData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << w.size() << " MpsUsbDaqConfigurationData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<w.size();i++) {
	  w[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    if(_configurationStart.configurationNumberInRun()==0) {
    } else {
      assert(_vUsbDaqConfigurationValid.size()==_vLocation.size());
      assert(_vUsbDaqConfigurationData.size()==_vLocation.size());
    }

    std::vector<const MpsLocationData<MpsUsbDaqConfigurationData>* > wWrite;
    std::vector<const MpsLocationData<MpsUsbDaqConfigurationData>* > wRead;

    for(unsigned i(0);i<w.size();i++) {
      if(w[i]->write()) wWrite.push_back(w[i]);
      else               wRead.push_back(w[i]);
    }
    
    for(unsigned i(0);i<wWrite.size();i++) {
      if(wWrite[i]->usbDaqBroadcast()) {
	for(unsigned j(0);j<_vUsbDaqConfigurationData.size();j++) {
	  _vUsbDaqConfigurationValid[j]=true;
	  _vUsbDaqConfigurationData[j]=*(wWrite[i]->data());
	}
      }
    }

    for(unsigned i(0);i<wWrite.size();i++) {
      if(!wWrite[i]->usbDaqBroadcast()) {
	for(unsigned j(0);j<_vUsbDaqConfigurationData.size();j++) {
	  if(wWrite[i]->usbDaqAddress()==_vLocation[j].usbDaqAddress()) {
	    _vUsbDaqConfigurationValid[j]=true;
	    _vUsbDaqConfigurationData[j]=*(wWrite[i]->data());
	  }
	}
      }
    }

    for(unsigned j(0);j<_vUsbDaqConfigurationData.size();j++) {
      assert(_vUsbDaqConfigurationValid[j]);
    }

    assert(wRead.size()==_vLocation.size());
    for(unsigned i(0);i<wRead.size();i++) { 

      bool checked(false);
      //for(unsigned j(0);j<_vUsbDaqConfigurationData.size();j++) {
      //if(wRead[i]->location()==_vLocation[j]) {
	  //if(wRead[i]->usbDaqAddress()==_vLocation[j].usbDaqAddress()) {
	  checked=true;
	  assert(_vLocation[i]==wRead[i]->location());
	  if(_vUsbDaqConfigurationData[i]!=*(wRead[i]->data())) {
	    _vUsbDaqConfigurationData[i].print(std::cout,"WRIT ");
	    wRead[i]->print(std::cout,"READ ");
	  }
	  assert(_vUsbDaqConfigurationData[i]==*(wRead[i]->data()));

      assert(checked);
    }

    
    std::vector<const MpsLocationData<MpsPcb1ConfigurationData>* >
      v(accessor.access< MpsLocationData<MpsPcb1ConfigurationData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << v.size() << " MpsPcb1ConfigurationData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<v.size();i++) {
	  v[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    assert(_vPcbConfigurationValid.size()==_vLocation.size());
    assert(_vPcbConfigurationData.size()==_vLocation.size());

    std::vector<const MpsLocationData<MpsPcb1ConfigurationData>* > vWrite;
    std::vector<const MpsLocationData<MpsPcb1ConfigurationData>* > vRead;

    for(unsigned i(0);i<v.size();i++) {
      if(v[i]->write()) vWrite.push_back(v[i]);
      else               vRead.push_back(v[i]);
    }

    for(unsigned i(0);i<vWrite.size();i++) {
      if(vWrite[i]->sensorBroadcast()) {
	for(unsigned j(0);j<_vPcbConfigurationData.size();j++) {
	  _vPcbConfigurationValid[j]=true;
	  _vPcbConfigurationData[j]=*(vWrite[i]->data());
	}
      }
    }

    for(unsigned i(0);i<vWrite.size();i++) {
      if(!vWrite[i]->sensorBroadcast()) {
	for(unsigned j(0);j<_vPcbConfigurationData.size();j++) {
	  if(vWrite[i]->sensorId()==_vLocation[j].sensorId()) {
	    _vPcbConfigurationValid[j]=true;
	    _vPcbConfigurationData[j]=*(vWrite[i]->data());
	  }
	}
      }
    }

    for(unsigned j(0);j<_vPcbConfigurationData.size();j++) {
      assert(_vPcbConfigurationValid[j]);
    }

    assert(vRead.size()==_vLocation.size());
    for(unsigned i(0);i<vRead.size();i++) { 
      bool checked(false);
      for(unsigned j(0);j<_vPcbConfigurationData.size();j++) {
	if(vRead[i]->sensorId()==_vLocation[j].sensorId()) {
	  checked=true;
	  assert(_vLocation[j]==vRead[i]->location());
	  assert(_vPcbConfigurationData[j]==*(vRead[i]->data()));
	}
      }
      assert(checked);
    }

    /*

    std::vector<const MpsLocationData<MpsSensor1ConfigurationData>* >
      u(accessor.access< MpsLocationData<MpsSensor1ConfigurationData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << u.size() << " MpsSensor1ConfigurationData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<u.size();i++) {
	  u[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    assert(_vSensorConfigurationValid.size()==_vLocation.size());
    assert(_vSensorConfigurationData.size()==_vLocation.size());

    for(unsigned i(0);i<u.size();i++) {
      assert(u[i]->write());
      if(u[i]->sensorBroadcast()) {
	for(unsigned j(0);j<_vSensorConfigurationData.size();j++) {
	  _vSensorConfigurationValid[j]=true;
	  _vSensorConfigurationData[j]=*(u[i]->data());
	}
      }
    }

    for(unsigned i(0);i<u.size();i++) {
      if(!u[i]->sensorBroadcast()) {
	for(unsigned j(0);j<_vSensorConfigurationData.size();j++) {
	  if(u[i]->sensorId()==_vLocation[j].sensorId()) {
	    _vSensorConfigurationValid[j]=true;
	    _vSensorConfigurationData[j]=*(u[i]->data());
	  }
	}
      }
    }

    for(unsigned j(0);j<_vSensorConfigurationData.size();j++) {
      assert(_vSensorConfigurationValid[j]);
    }
    */
    return true;
  }
  
  bool configurationEnd(const RcdRecord &r) {
    /*
    SubAccessor accessor(r);

    std::vector<const MpsLocationData<MpsUsbDaqConfigurationData>* >
      w(accessor.access< MpsLocationData<MpsUsbDaqConfigurationData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << w.size() << " MpsUsbDaqConfigurationData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<w.size();i++) {
	  w[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    assert(w.size()==_vLocation.size());
    for(unsigned i(0);i<w.size();i++) { 
      bool checked(false);
      for(unsigned j(0);j<_vUsbDaqConfigurationData.size();j++) {
	if(w[i]->location()==_vLocation[j]) {
	  //if(w[i]->usbDaqAddress()==_vLocation[j].usbDaqAddress()) {
	  checked=true;
	  assert(_vLocation[j]==w[i]->location());
	  assert(_vUsbDaqConfigurationData[j]==*(w[i]->data()));
	}
      }
      assert(checked);
    }

    std::vector<const MpsLocationData<MpsPcb1ConfigurationData>* >
      v(accessor.access< MpsLocationData<MpsPcb1ConfigurationData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << v.size() << " MpsPcb1ConfigurationData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<v.size();i++) {
	  v[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    assert(v.size()==_vLocation.size());
    for(unsigned i(0);i<v.size();i++) { 
      bool checked(false);
      for(unsigned j(0);j<_vPcbConfigurationData.size();j++) {
	if(v[i]->sensorId()==_vLocation[j].sensorId()) {
	  checked=true;
	  assert(_vLocation[j]==v[i]->location());
	  assert(_vPcbConfigurationData[j]==*(v[i]->data()));
	}
      }
      assert(checked);
    }

    std::vector<const MpsLocationData<MpsSensor1ConfigurationData>* >
      u(accessor.access< MpsLocationData<MpsSensor1ConfigurationData> >());

    if(doPrint(r.recordType(),1)) {
      std::cout << " Found " << u.size() << " MpsSensor1ConfigurationData objects" << std::endl;
      if(doPrint(r.recordType(),2)) {
	for(unsigned i(0);i<u.size();i++) {
	  u[i]->print(std::cout,"  ");
	}
      }
      std::cout << std::endl;
    }

    assert(u.size()==_vLocation.size());
    for(unsigned i(0);i<u.size();i++) { 
      bool checked(false);
      for(unsigned j(0);j<_vSensorConfigurationData.size();j++) {
	if(u[i]->sensorId()==_vLocation[j].sensorId()) {
	  checked=true;
	  assert(_vLocation[j]==u[i]->location());
	  if((_vSensorConfigurationData[j]!=*(u[i]->data()))) {
	    _vSensorConfigurationData[j].print(std::cout,"WRIT ");
	    u[i]->data()->print(std::cout,"READ ") << std::endl;
	  }
	  //assert(_vSensorConfigurationData[j]==*(u[i]->data()));
	}
      }
      assert(checked);
    }
    */
    return true;
  }

  bool slowReadout(const RcdRecord &r) {
    SubAccessor accessor(r);

    std::vector<const MpsLocationData<MpsPcb1SlowReadoutData>* >
      w(accessor.access< MpsLocationData<MpsPcb1SlowReadoutData> >());
    assert(w.size()==_vLocation.size());
    if(doPrint(r.recordType(),1)) w[0]->print(std::cout) << std::endl;

    _hTemp->Fill((r.recordTime()-_runStartTime).deltaTime(),w[0]->data()->celcius());
    _pTemp->Fill((r.recordTime()-_runStartTime).deltaTime(),w[0]->data()->celcius());
    return true;
  }
  
  bool bunchTrain(const RcdRecord &r) {
    SubAccessor accessor(r);

    std::vector<const MpsLocationData<MpsSensor1ConfigurationData>* >
      v(accessor.access< MpsLocationData<MpsSensor1ConfigurationData> >());

    //assert(v.size()==_vLocation.size());

    return true;
  }

private:
  /*
  std::vector<MpsLocation> _vLocation;
  */
  std::vector<MpsUsbDaqRunData> _vUsbDaqRunData;

  std::vector<bool> _vUsbDaqConfigurationValid;
  std::vector<MpsUsbDaqConfigurationData> _vUsbDaqConfigurationData;
  std::vector<bool> _vPcbConfigurationValid;
  std::vector<MpsPcb1ConfigurationData> _vPcbConfigurationData;
  std::vector<bool> _vSensorConfigurationValid;
  std::vector<MpsSensor1ConfigurationData> _vSensorConfigurationData;

  UtlTime _runStartTime;

  TH2F     *_hTemp;
  TProfile *_pTemp;
};

#endif
