#ifndef HstRecordShm_HH
#define HstRecordShm_HH

#include <cassert>

#include "DaqRunStart.hh"

#include "RcdUserRO.hh"
#include "RcdWriterDmy.hh"
#include "RcdWriterAsc.hh"
#include "RcdWriterBin.hh"

#include "UtlAverage.hh"
#include "SubAccessor.hh"

#include "HstRecordStore.hh"
#include "ShmObject.hh"


class HstRecordShm : public RcdUserRO {

public:
  HstRecordShm() :
    _shmHstRecordStore(HstRecordStore::shmKey),
    _pShm(_shmHstRecordStore.payload()) {
    assert(_pShm!=0);
    _seenFirst=false;
  }

  virtual ~HstRecordShm() {
  }

  bool record(const RcdRecord &r) {

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

    _pShm->fill(r);

    if(!_seenFirst) {
      _pShm->_firstTime[0]=r.recordTime();
    }

    switch (r.recordType()) {
  
    case RcdHeader::runStart: {
      if(_pShm->_resetLevel==HstFlags::run) _pShm->reset(4);
      _pShm->reset(1);
      _pShm->_firstTime[1]=r.recordTime();
      break;
    }
  
    case RcdHeader::configurationStart: {
      if(_pShm->_resetLevel==HstFlags::configuration) _pShm->reset(4);
      _pShm->reset(2);
      _pShm->_firstTime[2]=r.recordTime();
      break;
    }
  
    case RcdHeader::acquisitionStart: {
      if(_pShm->_resetLevel==HstFlags::acquisition) _pShm->reset(4);
      _pShm->reset(3);
      _pShm->_firstTime[3]=r.recordTime();
      break;
    }
  
    case RcdHeader::event: {
      if(_pShm->_resetLevel==HstFlags::event) _pShm->reset(4);
      break;
    }
  
    default: {
      break;
    }
    };
 
    unsigned bin(0);

    for(unsigned i(0);i<4;i++) {
      double dt((r.recordTime()-_pShm->_firstTime[i]).deltaTime());
      while(dt>=_pShm->_rateRange[i]) _pShm->rescale(i);
      bin=(unsigned)(1000*dt/_pShm->_rateRange[i]);
      if(bin>=1000) bin=999;
      _pShm->_rate[i][r.recordType()][bin]++;
      _pShm->_data[i][r.recordType()][bin]+=r.totalNumberOfBytes();
    }

    // Size of records
    _pShm->_size.fill(r.totalNumberOfBytes()/512,r.recordType());

    // Time to process records
    if(_seenFirst) {
      double lt((r.recordTime()-_lastHeader.recordTime()).deltaTime());
      bin=(unsigned)(5000.0*lt);

      //if(_lastHeader.recordType()==RcdHeader::trigger) 
      //std::cout << "lt = " << lt << ", bin = " << bin << std::endl;

      _pShm->_time.fill(bin,_lastHeader.recordType());
    } else {
      _seenFirst=true;
    }

    _lastHeader=r;

    _pShm->_validEvent=true;
    return true;
  }

private:
  ShmObject<HstRecordStore> _shmHstRecordStore;
  HstRecordStore *_pShm;

  bool _seenFirst;
  RcdHeader _lastHeader;
};

#endif
