#ifndef HstBeTrgHistoryShm_HH
#define HstBeTrgHistoryShm_HH

#include <cassert>

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

#include "HstBeTrgHistoryStore.hh"
#include "ShmObject.hh"


class HstBeTrgHistoryShm : public RcdUserRO {

public:
  HstBeTrgHistoryShm() :
    _shmHstBeTrgHistoryStore(HstBeTrgHistoryStore::shmKey),
    _pShm(_shmHstBeTrgHistoryStore.payload()) {
    assert(_pShm!=0);
  }

  virtual ~HstBeTrgHistoryShm() {
  }

  bool record(const RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "HstBeTrgHistory::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }

    DaqTwoTimer tt;

    // Check for user-requested reset
    if(_pShm->_resetNow) {
      _pShm->reset();
      _pShm->_resetNow=false;
    }

    _pShm->fill(r);

    switch (r.recordType()) {
  
    case RcdHeader::runStart: {
      if(_pShm->_resetLevel==HstFlags::run) _pShm->reset();
      break;
    }
  
    case RcdHeader::configurationStart: {
      if(_pShm->_resetLevel==HstFlags::configuration) _pShm->reset();
      break;
    }
  
    case RcdHeader::acquisitionStart: {
      if(_pShm->_resetLevel==HstFlags::acquisition) _pShm->reset();
      break;
    }
  
    case RcdHeader::event: {
      if(_pShm->_resetLevel==HstFlags::event) _pShm->reset();

      SubAccessor accessor(r);

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

      unsigned nBeTrgHistory(0);

      for(unsigned i(0);i<v.size();i++) {

	const CrcVlinkTrgData *td(v[i]->data()->trgData());
	if(td!=0) {
	  nBeTrgHistory++;
	  if(doPrint(r.recordType(),1)) td->print(std::cout," ") <<std::endl;

	  // Check for errors
	  if(td->header()    !=0x12345678) _pShm->_errors.fill(0);
	  if(td->trailer(256)!=0xfedcba98) _pShm->_errors.fill(1);

	  std::vector<const DaqEvent*>
	    d(accessor.access<DaqEvent>());
	  if(d.size()!=1) {
	    _pShm->_errors.fill(2);
	  } else {
	    if(d[0]->eventNumberInAcquisition()+1!=td->triggerCounter())
	      _pShm->_errors.fill(3);
	  }

	  // Store trigger history bits
	  const UtlPack *u((const UtlPack*)td->data());
	  for(unsigned j(0);j<253;j++) {
	    for(unsigned k(0);k<32;k++) {
	      if(u[j].bit(k)) _pShm->_history[k].fill(j);
	    }
	  }
	}
      }

      // Store number of histories found
      if(nBeTrgHistory>1) std::cout << "ERROR = " << nBeTrgHistory << std::endl;
      _pShm->_size.fill(nBeTrgHistory);

      break;
    }
  
    default: {
      break;
    }
    };

    // Finish up
    _pShm->_validEvent=true;

    tt.setEndTime();
    UtlTimeDifference dt(tt.timeDifference());
    if(dt.seconds()==0) {
      _pShm->_timers[r.recordType()].fill(dt.microseconds()/10);
    } else {
      _pShm->_timers[r.recordType()].fill(10000);
    }

    return true;
  }

private:
  ShmObject<HstBeTrgHistoryStore> _shmHstBeTrgHistoryStore;
  HstBeTrgHistoryStore *_pShm;
};

#endif
