#ifndef RunCount_HH
#define RunCount_HH

#include <sys/types.h>
#include <unistd.h>
#include <time.h>

#include "RcdCount.hh"
#include "SubAccessor.hh"


class RunCount {

public:
  //enum {
  //  shmKey=0x76543213
  //};

  RunCount() {
  }

  void increment(const RcdRecord &r) {

    // Get number of triggers to increment by
    unsigned triggerIncrement(0);
    if(r.recordType()==RcdHeader::trigger) triggerIncrement=1;
    if(r.recordType()==RcdHeader::triggerBurst) {
      SubAccessor accessor(r);
      std::vector<const DaqBurstEnd*> v(accessor.access<DaqBurstEnd>());
      assert(v.size()==1);
      triggerIncrement=v[0]->actualNumberOfTriggersInBurst();
    }

    // Count everything
    if(r.recordType()==RcdHeader::startUp) {

      _header[0]=(RcdHeader)r;
      _count[0].reset();
      _triggers[0]=0;
    }

    if(true) {
      _count[0]+=r;
      _triggers[0]+=triggerIncrement;
    }
      
    // Count the current sequence
    if(r.recordType()==RcdHeader::startUp ||
       r.recordType()==RcdHeader::sequenceStart) {

       if(r.recordType()==RcdHeader::sequenceStart) _header[1]=(RcdHeader)r;
      _count[1].reset();
      _triggers[1]=0;
    }

    if(r.recordType()!=RcdHeader::startUp && 
       r.recordType()!=RcdHeader::shutDown) {

      _count[1]+=r;
      _triggers[1]+=triggerIncrement;
    }

    // Count the current run
    if(r.recordType()==RcdHeader::startUp       ||
       r.recordType()==RcdHeader::sequenceStart ||
       r.recordType()==RcdHeader::runStart) {

       if(r.recordType()==RcdHeader::runStart) _header[2]=(RcdHeader)r;
      _count[2].reset();
      _triggers[2]=0;
    }

    if(r.recordType()!=RcdHeader::startUp       && 
       r.recordType()!=RcdHeader::sequenceStart &&
       r.recordType()!=RcdHeader::sequenceEnd   &&
       r.recordType()!=RcdHeader::shutDown) {

      _count[2]+=r;
      _triggers[2]+=triggerIncrement;
    }

    // Count the current configuration
    if(r.recordType()==RcdHeader::startUp       ||
       r.recordType()==RcdHeader::sequenceStart ||
       r.recordType()==RcdHeader::runStart      ||
       r.recordType()==RcdHeader::configurationStart) {

      if(r.recordType()==RcdHeader::configurationStart) _header[3]=(RcdHeader)r;
      _count[3].reset();
      _triggers[3]=0;
    }

    if(r.recordType()!=RcdHeader::startUp       && 
       r.recordType()!=RcdHeader::sequenceStart &&
       r.recordType()!=RcdHeader::runStart      &&
       r.recordType()!=RcdHeader::runEnd        &&
       r.recordType()!=RcdHeader::sequenceEnd   &&
       r.recordType()!=RcdHeader::shutDown) {

      _count[3]+=r;
      _triggers[3]+=triggerIncrement;
    }

    // Count the current acquisition
    if(r.recordType()==RcdHeader::startUp            ||
       r.recordType()==RcdHeader::runStart           ||
       r.recordType()==RcdHeader::sequenceStart      ||
       r.recordType()==RcdHeader::configurationStart ||
       r.recordType()==RcdHeader::acquisitionStart) {

      if(r.recordType()==RcdHeader::acquisitionStart) _header[4]=(RcdHeader)r;
      _count[4].reset();
      _triggers[4]=0;
    }

    if(r.recordType()!=RcdHeader::startUp            && 
       r.recordType()!=RcdHeader::sequenceStart      &&
       r.recordType()!=RcdHeader::runStart           &&
       r.recordType()!=RcdHeader::configurationStart &&
       r.recordType()!=RcdHeader::configurationEnd   &&
       r.recordType()!=RcdHeader::runEnd             &&
       r.recordType()!=RcdHeader::sequenceEnd        &&
       r.recordType()!=RcdHeader::slowReadout        &&
       r.recordType()!=RcdHeader::shutDown) {

      _count[4]+=r;
      _triggers[4]+=triggerIncrement;
    }

    // Last headers
    if(r.recordType()!=RcdHeader::trigger &&
       r.recordType()!=RcdHeader::triggerBurst &&
       r.recordType()!=RcdHeader::event) _header[5]=(RcdHeader)r;
    _header[6]=(RcdHeader)r;
  }

  unsigned count(RcdHeader::RecordType t=RcdHeader::event, unsigned j=0) const {
    assert(j<5);
    return _count[j].count(t);
  }

  RcdHeader header(unsigned i) const {
    assert(i<7);
    return _header[i];
  }

  RcdCount counter(unsigned i) const {
    assert(i<5);
    return _count[i];
  }

  unsigned triggers(unsigned i=0) const {
    assert(i<5);
    return _triggers[i];
  }

  std::ostream& print(std::ostream& o=std::cout, std::string s="") const {
    o << s << "RunCount::print()" << std::endl;

    _header[0].print(o,s+" Job  ");
    _count[0].print(o,s+" Job  ") << std::endl;

    //_header[1].print(o,s+" Seq  ");
    //_count[1].print(o,s+" Seq  ") << std::endl;

    _header[2].print(o,s+" Run  ");
    _count[2].print(o,s+" Run  ") << std::endl;

    _header[3].print(o,s+" Cfg  ");
    _count[3].print(o,s+" Cfg  ") << std::endl;

#ifndef DAQ_ILC_TIMING
    _header[4].print(o,s+" Acq  ");
    _count[4].print(o,s+" Acq  ") << std::endl;

    _header[5].print(o,s+" Last ");
    //if(_header[5]!=_header[6])
#endif
    _header[6].print(o,s+" Last ");

    return o;
  }

private:
  RcdHeader _header[7];
  RcdCount _count[5];
  unsigned _triggers[5];
};

#endif
