#ifndef DaqReadout_HH
#define DaqReadout_HH

#include <vector>
#include <fstream>
#include <iostream>

#include "RcdUserRW.hh"

#include "SubInserter.hh"
#include "SubAccessor.hh"

#include "DaqRunStart.hh"
#include "DaqRunEnd.hh"
#include "DaqConfigurationStart.hh"
#include "DaqConfigurationEnd.hh"
#include "DaqAcquisitionStart.hh"
#include "DaqAcquisitionEnd.hh"
#include "DaqSpillStart.hh"
#include "DaqSpillEnd.hh"
#include "DaqTransferStart.hh"
#include "DaqTransferEnd.hh"


class DaqReadout : public RcdUserRW {

public:
  enum Counter {
    cfgInRun,
    slwInRun,slwInCfg,
    acqInRun,acqInCfg,
    splInRun,splInCfg,
    tsfInRun,tsfInCfg,
    trgInRun,trgInCfg,trgInAcq,trgInSpl,
    evtInRun,evtInCfg,evtInAcq,evtInTsf,

    //cfgToRun,
    //slwToRun,slwToCfg,
    //acqToRun,acqToCfg,
    //splToRun,splToCfg,
    //tsfToRun,tsfToCfg,
    trgToRun,trgToCfg,trgToAcq,trgToSpl,
    //evtToRun,evtToCfg,evtToAcq,evtToTsf,
    endOfCounterEnum
  };
  
  DaqReadout() :
    _shmRunControl(RunControl::shmKey), _pRc(_shmRunControl.payload()),
    
#ifdef CERN_SETTINGS
    // Limit number of events to fit into CERN spills 12/07/07
    //_maxNumberOfEventsInBuffer(1800) {
    // Reset to maximum limit for AHCAL-only runs 15/08/07
    _maxNumberOfEventsInBuffer(2000) {
#else 
    // This is the physical CRC memory limit
    _maxNumberOfEventsInBuffer(2000) {
#endif
      
    assert(_pRc!=0);
      
    _inRun=false;
    _inConfiguration=false;
    _inAcquisition=false;
    _inSpill=false;
  }
    
  virtual ~DaqReadout() {
  }

  bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "DaqReadout::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }
    
    SubInserter inserter(r);
    
    UtlPack tid;
    tid.halfWord(1,SubHeader::daq);
    tid.byte(2,1);
    DaqTwoTimer *t(inserter.insert<DaqTwoTimer>(true));
    t->timerId(tid.word());
    
    
    // Get time of record and check durations
    _headerTime=r.recordTime();
    _timeLimit=UtlTimeDifference(0x7fffffff,999999);
    
    if(_inSpill) {
      _activeTime[3]=_headerTime-_time[3];
      _remainingTime[3]=_spillStart.maximumTimeOfSpill()-_activeTime[3];
      if(_remainingTime[3]<_timeLimit) _timeLimit=_remainingTime[3];
      
      //if(_headerTime-_time[3]>_spillStart.maximumTimeOfSpill()) {
      if(_remainingTime[3].deltaTime()<0.0) {
	if(_pRc->flag()>RunControl::spillEnd) {
	  _pRc->flag(RunControl::spillEnd);
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::spillEnd: Time taken = "
		      << _activeTime[3] << " >= maximum time in spill = " 
		      << _spillStart.maximumTimeOfSpill()
		      << std::endl << std::endl;
	  }
	}
      }
    }
    
    if(_inAcquisition) {
      _activeTime[2]=_headerTime-_time[2];
      _remainingTime[2]=_acquisitionStart.maximumTimeOfAcquisition()-_activeTime[2];
      if(_remainingTime[2]<_timeLimit) _timeLimit=_remainingTime[2];
      
      //if(_headerTime-_time[2]>_acquisitionStart.maximumTimeOfAcquisition()) {
      if(_remainingTime[2].deltaTime()<0.0) {
	if(_pRc->flag()>RunControl::acquisitionEnd) {
	  _pRc->flag(RunControl::acquisitionEnd);
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::acquisitionEnd: Time taken = "
		      << _activeTime[2] << " >= maximum time in acquisition = " 
		      << _acquisitionStart.maximumTimeOfAcquisition()
		      << std::endl << std::endl;
	  }
	}
      }
    }
    
    if(_inConfiguration) {
      _activeTime[1]=_headerTime-_time[1];
      _remainingTime[1]=_configurationStart.maximumTimeOfConfiguration()-_activeTime[1];
      if(_remainingTime[1]<_timeLimit) _timeLimit=_remainingTime[1];
      
      //if(_headerTime-_time[1]>_configurationStart.maximumTimeOfConfiguration()) {
      if(_remainingTime[1].deltaTime()<0.0) {
	if(_pRc->flag()>RunControl::configurationEnd) {
	  _pRc->flag(RunControl::configurationEnd);
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::configurationEnd: Time taken = "
		      << _activeTime[1] << " >= maximum time in configuration = " 
		      << _configurationStart.maximumTimeOfConfiguration()
		      << std::endl << std::endl;
	  }
	}
      }
    }
    
    if(_inRun) {
      _activeTime[0]=_headerTime-_time[0];
      _remainingTime[0]=_runStart.maximumTimeOfRun()-_activeTime[0];
      if(_remainingTime[0]<_timeLimit) _timeLimit=_remainingTime[0];
      
      //    if(_headerTime-_time[0]>_runStart.maximumTimeOfRun()) {
      if(_remainingTime[0].deltaTime()<0.0) {
	if(_pRc->flag()>RunControl::runEnd) {
	  _pRc->flag(RunControl::runEnd);
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::runEnd: Time taken = "
		      << _activeTime[0] << " >= maximum time in run = " 
		      << _runStart.maximumTimeOfRun()
		      << std::endl << std::endl;
	  }
	}
      }
    }
    
    // Check record type
    switch (r.recordType()) {
      
    case RcdHeader::runStart: {
      _count[cfgInRun]=0;
      _count[slwInRun]=0;
      _count[acqInRun]=0;
      _count[splInRun]=0;
      _count[tsfInRun]=0;
      _count[trgInRun]=0;
      _count[evtInRun]=0;
      
      _inRun=true;
      _time[0]=_headerTime;
      
      SubAccessor accessor(r);
      std::vector<const DaqRunStart*> v(accessor.access<DaqRunStart>());
      assert(v.size()<=1);
      
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;
      
      //_count[cfgToRun]=v[0]->maximumNumberOfConfigurationsInRun();
      //_count[acqToRun]=v[0]->maximumNumberOfAcquisitionsInRun();
      _count[trgToRun]=v[0]->maximumNumberOfEventsInRun();

      // Save start of run information
      _runStart=*(v[0]);

      break;
    }
      
    case RcdHeader::runEnd: {
      _inRun=false;
      
      SubInserter inserter(r);
      DaqRunEnd *d(inserter.insert<DaqRunEnd>(true));
      
      d->runNumber(_runStart.runNumber());
      d->runType(_runStart.runType());
      d->actualNumberOfConfigurationsInRun(_count[cfgInRun]);
      d->actualNumberOfSlowReadoutsInRun(  _count[slwInRun]);
      d->actualNumberOfAcquisitionsInRun(  _count[acqInRun]);
      //if(trgInRun>evtInRun) d->actualNumberOfEventsInRun(_count[trgInRun]);
      //else                  d->actualNumberOfEventsInRun(_count[evtInRun]);
      d->actualNumberOfEventsInRun(        _count[evtInRun]);
      d->actualTimeOfRun(_headerTime-_time[0]);

      if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;

      assert(_count[trgInRun]==_count[evtInRun]);

      break;
    }
      
    case RcdHeader::configurationStart: {
      _count[slwInCfg]=0;
      _count[acqInCfg]=0;
      _count[splInCfg]=0;
      _count[tsfInCfg]=0;
      _count[trgInCfg]=0;
      _count[evtInCfg]=0;
      
      _inConfiguration=true;
      _time[1]=_headerTime;
      
      SubAccessor accessor(r);
      std::vector<const DaqConfigurationStart*> v(accessor.access<DaqConfigurationStart>());
      assert(v.size()==1);
      
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;
      
      // Save start of configuration information
      _configurationStart=*(v[0]);
      
      _count[trgToCfg]=_configurationStart.maximumNumberOfEventsInConfiguration();

      /*
      // Get trigger configuration (for spill invert)
      std::vector<const TrgReadoutConfigurationData*> 
	w(accessor.access<TrgReadoutConfigurationData>());
      assert(w.size()==1);
      
      if(doPrint(r.recordType(),1)) w[0]->print(std::cout," ") << std::endl;
      
      // Save trigger readout configuration information
      _trgReadoutConfiguration=*(w[0]);
      */

      break;
    }
      
    case RcdHeader::configurationEnd: {
      _inConfiguration=false;
      
      SubInserter inserter(r);
      DaqConfigurationEnd *d(inserter.insert<DaqConfigurationEnd>(true));
      
      d->configurationNumberInRun(                 _count[cfgInRun]);
      d->actualNumberOfSlowReadoutsInConfiguration(_count[slwInCfg]);
      d->actualNumberOfAcquisitionsInConfiguration(_count[acqInCfg]);
      d->actualNumberOfEventsInConfiguration(      _count[trgInCfg]);
      //if(trgInCfg>evtInCfg) d->actualNumberOfEventsInConfiguration(
      //else                  d->actualNumberOfEventsInConfiguration(_count[evtInCfg]);
      d->actualTimeOfConfiguration(_headerTime-_time[1]);
      
      if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;
      
      // Increment counts
      _count[cfgInRun]++;
      
      // Check for end of run conditions
      if(_count[cfgInRun]>=_runStart.maximumNumberOfConfigurationsInRun()) {
	if(_pRc->flag()>RunControl::runEnd) _pRc->flag(RunControl::runEnd);
      }

      assert(_count[trgInCfg]==_count[evtInCfg]);

      break;
    }
      
    case RcdHeader::slowReadout: {
      _count[slwInRun]++;
      _count[slwInCfg]++;
      
      break;
    }
      
    case RcdHeader::acquisitionStart: {
      _count[trgInAcq]=0;//e
      _count[evtInAcq]=0;//e
      
      _inAcquisition=true;
      _time[2]=_headerTime;
      
      SubAccessor accessor(r);
      std::vector<const DaqAcquisitionStart*> v(accessor.access<DaqAcquisitionStart>());
      assert(v.size()<=1);
      
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;
      
      _count[trgToAcq]=v[0]->maximumNumberOfEventsInAcquisition();

      // Save start of configuration information
      _acquisitionStart=*(v[0]);
      
      // Default to no spill signal
      _spilling=false;
      _inSpill=false;
      _bufferFull=false;
      _count[trgInSpl]=0;
      
      break;
    }
      
    case RcdHeader::acquisitionEnd: {
      _inAcquisition=false;
      
      SubInserter inserter(r);
      DaqAcquisitionEnd *d(inserter.insert<DaqAcquisitionEnd>(true));
      
      d->acquisitionNumberInRun(           _count[acqInRun]);
      d->acquisitionNumberInConfiguration( _count[acqInCfg]);
      //if(trgInAcq>evtInAcq) d->actualNumberOfEventsInAcquisition(_count[trgInAcq]);
      //else                  d->actualNumberOfEventsInAcquisition(_count[evtInAcq]);
      d->actualNumberOfEventsInAcquisition(_count[trgInAcq]);
      d->actualTimeOfAcquisition(_headerTime-_time[2]);
      
      if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;
      
      // Increment counts
      _count[acqInRun]++;
      _count[acqInCfg]++;
      
      // Check for end of configuration conditions
      if(_count[acqInCfg]>=_configurationStart.maximumNumberOfAcquisitionsInConfiguration()) {
	if(_pRc->flag()>RunControl::configurationEnd) _pRc->flag(RunControl::configurationEnd);
      }
      
      // Check for end of run conditions
      if(_count[acqInRun]>=_runStart.maximumNumberOfAcquisitionsInRun()) {
	if(_pRc->flag()>RunControl::runEnd) _pRc->flag(RunControl::runEnd);
      }
      
      assert(_count[trgInAcq]==_count[evtInAcq]);

      break;
    }
      
    case RcdHeader::spillStart: {
      _count[trgInSpl]=0;

      _inSpill=true;
      _time[3]=_headerTime;




      _spilling=true;
      


      
      
      // Correct time for spill poll length
      SubAccessor accessor(r);
      std::vector<const CrcLocationData<CrcBeTrgPollData>*>
	w(accessor.access< CrcLocationData<CrcBeTrgPollData> >());
      // Use difference not absolute as could be different PC timing
      if(w.size()==1) _time[3]+=w[0]->data()->actualTime();
      
      std::vector<const DaqSpillStart*> v(accessor.access<DaqSpillStart>());
      assert(v.size()<=1);
      
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;
      
      _count[trgToSpl]=v[0]->maximumNumberOfEventsInSpill();

      // Save start of configuration information
      _spillStart=*(v[0]);
      
      // Set up the burst trigger counts
      
      
      if(_spillStart.maximumNumberOfEventsInSpill()==0) {
	DaqConfiguration::maximumNumberOfExtraTriggersInBurst(0);
      } else {
	if(_spillStart.maximumNumberOfEventsInSpill()>499) {
	  DaqConfiguration::maximumNumberOfExtraTriggersInBurst(499);
	} else {
	  DaqConfiguration::maximumNumberOfExtraTriggersInBurst(_spillStart.maximumNumberOfEventsInSpill()-1);
	}
      }
      
      // Set up burst limits
      unsigned limit(_count[trgToRun]);
      if(_count[trgToCfg]<limit) limit=_count[trgToCfg];
      if(_count[trgToAcq]<limit) limit=_count[trgToAcq];
      if(_count[trgToSpl]<limit) limit=_count[trgToSpl];

      /*
      std::cout << " spillStart: counts trgToRun,Cfg,Acq,Spl = "
		<< _count[trgToRun] << ", "
		<< _count[trgToCfg] << ", "
		<< _count[trgToAcq] << ", "
		<< _count[trgToSpl] << ", "
		<< "limit = " << limit << std::endl;
      */

      DaqConfiguration::maximumNumberOfExtraTriggersInBurst(limit-1);
      DaqConfiguration::maximumTimeOfBurst(_timeLimit);
      
      break;
    }
      
    case RcdHeader::spillEnd: {
      _inSpill=false;
      
      SubInserter inserter(r);
      DaqSpillEnd *d(inserter.insert<DaqSpillEnd>(true));
      
      d->spillNumberInRun(           _count[splInRun]);
      d->spillNumberInConfiguration( _count[splInCfg]);
      d->actualNumberOfEventsInSpill(_count[trgInSpl]);
      d->actualTimeOfSpill(_headerTime-_time[3]);
      
      if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;
      
      _count[splInRun]++;
      _count[splInCfg]++;
      
      break;
    }
      
      /*
	case RcdHeader::spill: {
	_count[trgInSpl]=0;
	
	_time[3]=_headerTime;
	
	SubAccessor accessor(r);
	std::vector<const CrcLocationData<CrcBeTrgEventData>*>
	v(accessor.access< CrcLocationData<CrcBeTrgEventData> >());
	if(v.size()==1) _count[trgInSpl]=v[0]->data()->triggerCounter();
	
	SubInserter inserter(r);
	DaqSpillEnd *d(inserter.insert<DaqSpillEnd>(true));
	
	d->spillNumberInRun(_count[splInRun]);
	d->spillNumberInConfiguration(_count[splInCfg]);
	d->actualNumberOfEventsInSpill(_count[trgInSpl]);
	d->actualTimeOfSpill(_headerTime-_time[3]);
	
	_count[splInRun]++;
	_count[splInCfg]++;
	
	_count[trgInRun]+=_count[trgInSpl];
	_count[trgInCfg]+=_count[trgInSpl];
	_count[trgInAcq]+=_count[trgInSpl];
	
	if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;
	
	break;
	}
      */      

    case RcdHeader::transferStart: {
      _count[evtInTsf]=0;
      
      _time[4]=_headerTime;
      
      break;
    }
      
    case RcdHeader::transferEnd: {
      SubInserter inserter(r);
      DaqTransferEnd *d(inserter.insert<DaqTransferEnd>(true));
      
      d->transferNumberInRun(           _count[tsfInRun]);
      d->transferNumberInConfiguration( _count[tsfInCfg]);
      d->actualNumberOfEventsInTransfer(_count[evtInTsf]);
      d->actualTimeOfTransfer(_headerTime-_time[4]);
      
      if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;
      
      _count[tsfInRun]++;
      _count[tsfInCfg]++;
      
      break;
    }
      
    case RcdHeader::trigger:
    case RcdHeader::triggerBurst: {
      
      if(r.recordType()==RcdHeader::triggerBurst) {
	SubAccessor accessor(r);
	std::vector<const DaqBurstEnd*> v(accessor.access<DaqBurstEnd>());
	assert(v.size()<=1); // Allow no DaqBurstEnd as inserted by TrgReadout
	
	unsigned nTrg(1);
	if(v.size()==1) nTrg+=v[0]->actualNumberOfExtraTriggersInBurst();
	DaqConfiguration::numberOfTriggersInBurst(nTrg);

	_count[trgInRun]+=nTrg;
	_count[trgInCfg]+=nTrg;
	_count[trgInAcq]+=nTrg;
	_count[trgInSpl]+=nTrg;
	assert(_inSpill);
	
	assert(_count[trgToRun]>=nTrg);
	assert(_count[trgToCfg]>=nTrg);
	assert(_count[trgToAcq]>=nTrg);
	assert(_count[trgToSpl]>=nTrg);

	_count[trgToRun]-=nTrg;
	_count[trgToCfg]-=nTrg;
	_count[trgToAcq]-=nTrg;
	_count[trgToSpl]-=nTrg;

	if(v.size()==1) {
	  _bufferFull=v[0]->bufferFull();// || _count[trgInSpl]>=_maxNumberOfEventsInBuffer;
	  _spilling=v[0]->inSpill();
	}

	// Set up burst limits for next burst
	unsigned limit(_count[trgToRun]);
	if(_count[trgToCfg]<limit) limit=_count[trgToCfg];
	if(_count[trgToAcq]<limit) limit=_count[trgToAcq];
	if(_count[trgToSpl]<limit) limit=_count[trgToSpl];

	/*
	std::cout << " triggerBurst: counts trgToRun,Cfg,Acq,Spl = "
		  << _count[trgToRun] << ", "
		  << _count[trgToCfg] << ", "
		  << _count[trgToAcq] << ", "
		  << _count[trgToSpl] << ", "
		  << "limit = " << limit << std::endl;
	*/

	DaqConfiguration::maximumNumberOfExtraTriggersInBurst(limit-1);
	DaqConfiguration::maximumTimeOfBurst(_timeLimit);
	
      } else {
	SubAccessor accessor(r);
	std::vector<const DaqTrigger*> v(accessor.access<DaqTrigger>());
	assert(v.size()<=1); // Allow no DaqTrigger as inserted by TrgReadout
		
	_count[trgInRun]++;
	_count[trgInCfg]++;
	_count[trgInAcq]++;
	if(_inSpill) _count[trgInSpl]++;
	
	assert(_count[trgToRun]>0);
	_count[trgToRun]--;
	assert(_count[trgToCfg]>0);
	_count[trgToCfg]--;
	assert(_count[trgToAcq]>0);
	_count[trgToAcq]--;
	if(_inSpill) {
	  assert(_count[trgToSpl]>0);
	  _count[trgToSpl]--;
	}

	if(v.size()==1) {
	  _bufferFull=v[0]->bufferFull();// || _count[trgInSpl]>=_maxNumberOfEventsInBuffer;
	  _spilling=v[0]->inSpill();
	}
      }
      
      
#ifdef SPILL_INPUT_OLD
      
      SubAccessor accessor(r);
      std::vector<const CrcLocationData<CrcBeTrgEventData>*>
        v(accessor.access<CrcLocationData<CrcBeTrgEventData> >());

      if(v.size()>0) {
	//bool oldS=_spilling;
	if(_trgReadoutConfiguration.spillInvert()) {
	  _spilling=(v[0]->data()->inputStatus()&(1<<SPILL_INPUT))==0;
	} else {
	  _spilling=(v[0]->data()->inputStatus()&(1<<SPILL_INPUT))!=0;
	}
	/*
	std::cout << " input status = " << printHex(v[0]->data()->inputStatus()) << std::endl;

	if(_spilling!=oldS) {
	  std::cout << "DaqReadout spill status changed from ";
	  if(oldS) std::cout << "spilling to ";
	  else std::cout << "not spilling to ";
	  if(_spilling) std::cout << "spilling";
	  else std::cout << "not spilling";
	  std::cout << std::endl;
	}
	*/
      }

      // Check for TDC close to full
      if(!_BufferFull) {
	std::vector<const BmlLocationData<BmlCaen767TriggerData>*>
	  b(accessor.access< BmlLocationData<BmlCaen767TriggerData> >());
	
	for(unsigned i(0);i<b.size();i++) {
	  BmlCaen767StatusRegister s(b[i]->data()->statusRegister());
	  if(s.bufferAlmostFull()) {
	    _bufferFull=true;
	    std::cerr << "TDC" << i << " almost full" << std::endl;
	    b[i]->print(std::cerr) << std::endl;
	  }
	}
      }

#endif
	
      _eventLimit=0xffffffff;

      if(_inSpill) {
	unsigned remainingEvents(0);
	if(_spillStart.maximumNumberOfEventsInSpill()>_count[trgInSpl])
	  remainingEvents=_spillStart.maximumNumberOfEventsInSpill()-_count[trgInSpl];
	if(remainingEvents<_eventLimit) _eventLimit=remainingEvents;
      	
	// Check for start-of-transfer conditions

	//if(_spilling && (_count[trgInSpl]>2000 || _bufferFull)) {
	//if(_spilling && (_count[trgInSpl]>=_maxNumberOfEventsInBuffer || _bufferFull)) {

	if(_spilling && _bufferFull) {
	  if(_pRc->flag()>RunControl::transferStart) {
	    _pRc->flag(RunControl::transferStart);
	    if(doPrint(r.recordType(),1)) {
	      std::cout << " Issuing RunControl::transferStart: Buffer full"
			<< std::endl << std::endl;
	      
	      
	      /*
		std::cout << " Transfer start  spilling ";
		if(_spilling) std::cout << "true, ";
		else          std::cout << "false, ";
		//std::cout << _count[trgInSpl] << " > 2000" << std::endl;
		std::cout << _count[trgInSpl] << " >= " << _maxNumberOfEventsInBuffer << std::endl;
	      */
	      
	    }
	  }
	}
	
	// Check for end-of-spill conditions
	
	if(_spilling && _count[trgInSpl]>=_spillStart.maximumNumberOfEventsInSpill()) {
	  if(_pRc->flag()>RunControl::spillEnd) {
	    _pRc->flag(RunControl::spillEnd);
	    std::cout << " Issuing RunControl::spillEnd: Number of triggers = "
		      << _count[trgInSpl] << " >= maximum number in spill = " 
		      << _spillStart.maximumNumberOfEventsInSpill()
		      << std::endl << std::endl;
	  }
	}	    
	    
	/*	    
	    if(doPrint(r.recordType(),1)) {
	      std::cout << " Spill end  spilling ";
	      if(_spilling) std::cout << "true, ";
	      else          std::cout << "false, ";
	      std::cout << _count[trgInSpl] << " >= " 
			<< _spillStart.maximumNumberOfEventsInSpill() << std::endl;
	*/


	if(!_spilling) {
	  if(_pRc->flag()>RunControl::spillEnd) {
	    _pRc->flag(RunControl::spillEnd);
	    if(doPrint(r.recordType(),1)) {
	      std::cout << " Issuing RunControl::spillEnd: Not in spill"
			<< std::endl << std::endl;

	    }
	  }
	}
      }
      
      // Check for end-of-acquisition conditions
      
      if(_inAcquisition) {
	unsigned remainingEvents(0);
	if(_acquisitionStart.maximumNumberOfEventsInAcquisition()>_count[trgInAcq])
	  remainingEvents=_acquisitionStart.maximumNumberOfEventsInAcquisition()-_count[trgInAcq];
	if(remainingEvents<_eventLimit) _eventLimit=remainingEvents;
      }
      
      if(_count[trgInAcq]>=_acquisitionStart.maximumNumberOfEventsInAcquisition()) {
	if(_pRc->flag()>RunControl::acquisitionEnd) {
	  _pRc->flag(RunControl::acquisitionEnd);
	  
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::acquisitionEnd: Number of triggers = "
		      << _count[trgInAcq] << " >= maximum number in acquisition = " 
		      << _acquisitionStart.maximumNumberOfEventsInAcquisition()
		      << std::endl << std::endl;
	  }
	}
      }
      
      // Check for end-of-configuration conditions
      
      if(_inConfiguration) {
	unsigned remainingEvents(0);
	if(_configurationStart.maximumNumberOfEventsInConfiguration()>_count[trgInCfg])
	  remainingEvents=_configurationStart.maximumNumberOfEventsInConfiguration()-_count[trgInCfg];
	if(remainingEvents<_eventLimit) _eventLimit=remainingEvents;
      }
      
      if(_count[trgInCfg]>=_configurationStart.maximumNumberOfEventsInConfiguration()) {
	if(_pRc->flag()>RunControl::configurationEnd) {
	  _pRc->flag(RunControl::configurationEnd);
	  
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::configurationEnd: Number of triggers = "
		      << _count[trgInCfg] << " >= maximum number in configuration = " 
		      << _configurationStart.maximumNumberOfEventsInConfiguration()
		      << std::endl << std::endl;
	  }
	}
      }
      
      // Check for end-of-run conditions
      
      if(_inRun) {
	unsigned remainingEvents(0);
	if(_runStart.maximumNumberOfEventsInRun()>_count[trgInRun])
	  remainingEvents=_runStart.maximumNumberOfEventsInRun()-_count[trgInRun];
	if(remainingEvents<_eventLimit) _eventLimit=remainingEvents;
      }
	
      if(_count[trgInRun]>=_runStart.maximumNumberOfEventsInRun()) {
	if(_pRc->flag()>RunControl::runEnd) {
	  _pRc->flag(RunControl::runEnd);
	  
	  if(doPrint(r.recordType(),1)) {
	    std::cout << " Issuing RunControl::runEnd: Number of triggers = "
		      << _count[trgInRun] << " >= maximum number in run = " 
		      << _runStart.maximumNumberOfEventsInRun()
		      << std::endl << std::endl;
	  }
	}
      }
      
      //std::cout << "Trgs in acq,spill = " << _count[trgInAcq] << " " << _count[trgInSpl] << std::endl;

      //if(oldFlag!=_pRc->flag()) std::cout << "DaqReadout flag status changed from "
      //				  << oldFlag << " to " << _pRc->flag() << std::endl;

      break;
    }
      
    case RcdHeader::event: {
      _count[evtInRun]++;
      _count[evtInCfg]++;
      _count[evtInAcq]++;
      _count[evtInTsf]++;
      
      break;
    }

    default: {
      break;
    }
    };

    // Close off overall timer
    t->setEndTime();
    if(doPrint(r.recordType(),1)) t->print(std::cout," ") << std::endl;

    return true;
  }


private:
  ShmObject<RunControl> _shmRunControl;
  RunControl *_pRc;

  bool _inRun,_inConfiguration,_inAcquisition,_inSpill;
  DaqRunStart _runStart;
  DaqConfigurationStart _configurationStart;
  DaqAcquisitionStart _acquisitionStart;
  DaqSpillStart _spillStart;

  //TrgReadoutConfigurationData _trgReadoutConfiguration;

  bool _spilling;
  bool _bufferFull;
  unsigned _remainingEvents[5];


  unsigned _count[endOfCounterEnum];

  const unsigned _maxNumberOfEventsInBuffer;
  unsigned _numberOfEventsInTransfer;
  
  unsigned _eventLimit;

  UtlTime _headerTime;
  UtlTime _time[5];
  UtlTimeDifference _activeTime[5];
  UtlTimeDifference _remainingTime[5];
  UtlTimeDifference _timeLimit;
};

#endif
