#ifndef HstGeneric_HH
#define HstGeneric_HH

#include <cassert>

// HST_MAP defines if using file mapping or shared memory
#ifdef HST_MAP
#include "TMapFile.h"
#endif

#include "RcdMultiUserRO.hh"

#include "HstRecord.hh"
#include "HstCrcNoise.hh"
#include "HstCrcChannel.hh"
#include "HstCrcFeNoise.hh"
#include "HstCrcSignal.hh"
#include "HstTriggerPoll.hh"
#include "HstSpill.hh"
#include "HstTrgEvent.hh"
#include "HstBeTrgHistory.hh"
#include "HstCheckConfiguration.hh"
#include "HstCheckSubrecords.hh"
#include "HstLc1176.hh"
#include "HstCaen767.hh"
#include "HstLalHodoscope.hh"
#include "HstMpsBunchTrain.hh"


class HstGeneric : public RcdMultiUserRO {

public:

  // Set default bits to enable required histograms
  enum {
    //defaultHstGenericBits=0x1763 // = 0b 00010111 01100011
    defaultHstGenericBits=0x3107 // = 0b 00110001 00000111
  };


  HstGeneric(const UtlPack bits=defaultHstGenericBits,
	     const std::string mapFile="HstGeneric.map",
	     const unsigned mBytes=64) :
    _hstRecord(0),
    _hstCrcNoise(0),
    _hstCrcChannel(0),
    _hstCrcFeNoise(0),
    _hstCrcSignal(0),
    _hstTriggerPoll(0),
    _hstSpill(0),
    _hstTrgEvent(0),
    _hstBeTrgHistory(0),
    _hstCheckConfiguration(0),
    _hstCheckSubrecords(0),
    _hstLc1176(0),
    _hstCaen767(0),
    _hstLalHodoscope(0),
    _hstMpsBunchTrain(0) {
    
#ifdef HST_MAP
    // The following magic number needs to be got from running a root session
    // interactively using rootn.exe and typing
    //   root [0] m = TMapFile::Create("dummy.map","recreate",64*1024*1024);
    //   root [1] m->Print()
    // which gives
    //
    //    Memory mapped file:   dummy.map
    //      Title:                
    //  Option:               CREATE
    //      Mapped Memory region: 0xb35c2000 - 0xb75c2000 (64.00 MB)
    //      Current breakval:     0xb35c9000
    //
    // where the magic number is the first in the "Mapped Memory region"
    // range. Don't forget to rm dummy.map afterwards.
    //
    // The code below will then only work for sizes up to the size
    // used (64MBytes here). Larger sizes will cause a crash.

    assert(mBytes<=64);
    TMapFile::SetMapAddress(0xb35c2000);

    // Create a new memory mapped file. The memory mapped file can be
    // opened in an other process on the same machine and the objects
    // stored in it can be accessed.
    
    _mfile = TMapFile::Create(mapFile.c_str(),"RECREATE",mBytes*1024*1024,
			     "DAQ Memory Mapped Histogram File");

    // Print status of mapped file
    _mfile->Print();

    // Set updating period
    _nEvents=0;
    _rEvents=10;
    //_rEvents=0; // TEMP no updating between acquisitions
#endif

    // Enable histogramming
    _doHists=true;
    _ignorRunType=false;

    // Add modules; histograms must be created after map file
    if(bits.bit( 0)) {
     _hstRecord=new HstRecord;
      addUser(*_hstRecord);
    } else {
      _hstRecord=0;
      std::cout << "HstGeneric::ctor() HstRecord disabled" << std::endl;
    }

    if(bits.bit( 1)) {
      _hstCrcNoise=new HstCrcNoise;
      addUser(*_hstCrcNoise);
    } else {
      _hstCrcNoise=0;
      std::cout << "HstGeneric::ctor() HstCrcNoise disabled" << std::endl;
    }
      
#ifndef HST_MAP
    if(bits.bit( 2)) {
      _hstCrcChannel=new HstCrcChannel;
      addUser(*_hstCrcChannel);
    } else {
      _hstCrcChannel=0;
      std::cout << "HstGeneric::ctor() HstCrcChannel disabled" << std::endl;
    }
#endif
    
#ifdef HST_MAP
    if(bits.bit( 3)) {
      _hstCrcFeNoise=new HstCrcFeNoise;
      addUser(*_hstCrcFeNoise);
    } else {
      _hstCrcFeNoise=0;
      std::cout << "HstGeneric::ctor() HstCrcFeNoise disabled" << std::endl;
    }
    
    if(bits.bit( 4)) {
      _hstCrcSignal=new HstCrcSignal;
      addUser(*_hstCrcSignal);
    } else {
      _hstCrcSignal=0;
      std::cout << "HstGeneric::ctor() HstCrcSignal disabled" << std::endl;
    }
    
    if(bits.bit( 5)) {
      _hstTriggerPoll=new HstTriggerPoll;
      addUser(*_hstTriggerPoll);
    } else {
      _hstTriggerPoll=0;
      std::cout << "HstGeneric::ctor() HstTriggerPoll disabled" << std::endl;
    }
    
    if(bits.bit( 6)) {
      _hstSpill=new HstSpill;
      addUser(*_hstSpill);
    } else {
      _hstSpill=0;
      std::cout << "HstGeneric::ctor() HstSpill disabled" << std::endl;
    }
 
    if(bits.bit( 7)) {
      _hstTrgEvent=new HstTrgEvent;
      addUser(*_hstTrgEvent);
    } else {
      _hstTrgEvent=0;
      std::cout << "HstGeneric::ctor() HstTrgEvent disabled" << std::endl;
    }
#endif
     
    if(bits.bit( 8)) {
      _hstBeTrgHistory=new HstBeTrgHistory;
      addUser(*_hstBeTrgHistory);
    } else {
      _hstBeTrgHistory=0;
      std::cout << "HstGeneric::ctor() HstBeTrgHistory disabled" << std::endl;
    }

#ifdef HST_MAP
    if(bits.bit( 9)) {
      _hstCheckConfiguration=new HstCheckConfiguration;
      addUser(*_hstCheckConfiguration);
    } else {
      _hstCheckConfiguration=0;
      std::cout << "HstGeneric::ctor() HstCheckConfiguration disabled" << std::endl;
    }

    if(bits.bit(10)) {
      _hstCheckSubrecords=new HstCheckSubrecords;
      addUser(*_hstCheckSubrecords);
    } else {
      _hstCheckSubrecords=0;
      std::cout << "HstGeneric::ctor() HstCheckSubrecords disabled" << std::endl;
    }
#endif
    
    if(bits.bit(11)) {
      _hstLc1176=new HstLc1176;
      addUser(*_hstLc1176);
    } else {
      _hstLc1176=0;
      std::cout << "HstGeneric::ctor() HstLc1176 disabled" << std::endl;
    }

    if(bits.bit(12)) {
      _hstCaen767=new HstCaen767;
      addUser(*_hstCaen767);
    } else {
      _hstCaen767=0;
      std::cout << "HstGeneric::ctor() HstCaen767 disabled" << std::endl;
    }
    
    if(bits.bit(13)) {
      _hstLalHodoscope=new HstLalHodoscope;
      addUser(*_hstLalHodoscope);
    } else {
      _hstLalHodoscope=0;
      std::cout << "HstGeneric::ctor() HstLalHodoscope disabled" << std::endl;
    }
    
    if(bits.bit(31)) {
      _hstMpsBunchTrain=new HstMpsBunchTrain;
      addUser(*_hstMpsBunchTrain);
    } else {
      _hstMpsBunchTrain=0;
      std::cout << "HstGeneric::ctor() HstMpsBunchTrain disabled" << std::endl;
    }
    
#ifdef HST_MAP
    // Print status of mapped file
    //_mfile->Update();
    _mfile->Print();
    //_mfile->ls();
#endif
  }

  virtual ~HstGeneric() {
    delete _hstRecord;
    delete _hstCrcNoise;
    delete _hstCrcChannel;
    delete _hstCrcFeNoise;
    delete _hstCrcSignal;
    delete _hstTriggerPoll;
    delete _hstSpill;
    delete _hstTrgEvent;
    delete _hstBeTrgHistory;
    delete _hstCheckConfiguration;
    delete _hstCheckSubrecords;
    delete _hstLc1176;
    delete _hstCaen767;
    delete _hstLalHodoscope;
    delete _hstMpsBunchTrain;
    
#ifdef HST_MAP
    _mfile->Close();
#endif
 }

  virtual bool record(const RcdRecord &r) {

    // Possibly disable histogramming
    if(r.recordType()==RcdHeader::runStart) {
      _doHists=true;
      if(!_ignorRunType) {
	SubAccessor accessor(r);
	std::vector<const DaqRunStart*>
	  v(accessor.extract<DaqRunStart>());

        if(v.size()==1) {
          _doHists=v[0]->runType().histogramRun();
          printLevel(v[0]->runType().printLevel());
        }
      }
    }

    if(_doHists) {
      if(!RcdMultiUserRO::record(r)) return false;

#ifdef HST_MAP
      // updates all objects in shared memory
      if(r.recordType()!=RcdHeader::trigger &&
      	 r.recordType()!=RcdHeader::event) _mfile->Update();

      // Never update for a trigger, only an event
      if(r.recordType()==RcdHeader::event) {
	if(_rEvents>0 && (_nEvents%_rEvents)==0) _mfile->Update();
	_nEvents++;
      }
#endif
    }
    
    // Re-enable histogramming
    if(r.recordType()==RcdHeader::runEnd) _doHists=true;

    return true;
  }

  void ignorRunType(bool b) {
    _ignorRunType=b;
  }

  void updatePeriod(unsigned r) {
#ifdef HST_MAP
    _rEvents=r;
#endif
  }


private:
#ifdef HST_MAP
  TMapFile *_mfile;

  unsigned _nEvents;
  unsigned _rEvents;
#endif

  bool _ignorRunType;
  bool _doHists;

  HstRecord *_hstRecord;
  HstCrcNoise *_hstCrcNoise;
  HstCrcChannel *_hstCrcChannel;
  HstCrcFeNoise *_hstCrcFeNoise;
  HstCrcSignal *_hstCrcSignal;
  HstTriggerPoll *_hstTriggerPoll;
  HstSpill *_hstSpill;
  HstTrgEvent *_hstTrgEvent;
  HstBeTrgHistory *_hstBeTrgHistory;
  HstCheckConfiguration *_hstCheckConfiguration;
  HstCheckSubrecords *_hstCheckSubrecords;
  HstLc1176 *_hstLc1176;
  HstCaen767 *_hstCaen767;
  HstLalHodoscope *_hstLalHodoscope;
  HstMpsBunchTrain *_hstMpsBunchTrain;
};

#endif
