#ifndef HstCrcChannelShm_HH
#define HstCrcChannelShm_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 "HstCrcChannelStore.hh"
#include "ShmObject.hh"


class HstCrcChannelShm : public RcdUserRO {

public:
  HstCrcChannelShm() :
    _shmHstCrcChannelStore(HstCrcChannelStore::shmKey), _pShm(_shmHstCrcChannelStore.payload()) {
    assert(_pShm!=0);
  }

  virtual ~HstCrcChannelShm() {
  }

  bool record(const RcdRecord &r) {

    // 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();

      if(_crate!=_pShm->_crate ||
	 _slot !=_pShm->_slot  ||
	 _fe   !=_pShm->_fe    ||
	 _chip !=_pShm->_chip  ||
	 _chan !=_pShm->_chan) {

	_crate=_pShm->_crate;
	_slot =_pShm->_slot;
	_fe   =_pShm->_fe;
	_chip =_pShm->_chip;
	_chan =_pShm->_chan;
	_pShm->reset();
      }

      SubAccessor accessor(r);
      std::vector<const CrcLocationData<CrcVlinkEventData>* >
	v(accessor.access< CrcLocationData<CrcVlinkEventData> >());
      
      for(unsigned i(0);i<v.size();i++) {
	
	// Make sure data block is self-consistent
	bool verified(v[i]->verify() && v[i]->data()->verify());
	
	// Get crate number
	unsigned crate(3);
	if(v[i]->crateNumber()==0xec) crate=0;
	if(v[i]->crateNumber()==0xce) crate=0;
	if(v[i]->crateNumber()==0xac) crate=1;
	if(v[i]->crateNumber()==0xde) crate=2;

	if(crate==_crate) {
	  
	  // Get slot number
	  unsigned slot(v[i]->slotNumber());
	  if(slot==_slot) {

	    // Use FE number
	    const CrcVlinkFeData *fd(v[i]->data()->feData(_fe));
	    if(fd!=0) {
		  
	      // Use channel number
	      if(_chan<v[i]->data()->feNumberOfAdcSamples(_fe)) {
		const CrcVlinkAdcSample *as(fd->adcSample(_chan));
		if(as!=0) {
		  unsigned short adc(as->adc(_chip)+32768);
		  _pShm->_adc[adc]++;
		  if(!verified) _pShm->_bad[adc]++;
		}
	      }
	    }
	  }
	}
      }
	
      _pShm->_validEvent=true;
      break;
    }
  
    default: {
      break;
    }
    };
 
    return true;
  }

private:
  unsigned _crate,_slot,_fe,_chip,_chan;

  ShmObject<HstCrcChannelStore> _shmHstCrcChannelStore;
  HstCrcChannelStore *_pShm;
};

#endif
