#ifndef DheConfiguration_HH
#define DheConfiguration_HH

#include <iostream>
#include <fstream>

#include "RcdHeader.hh"
#include "RcdUserRW.hh"

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

#include "CrcConfiguration.hh"
#include "CrcReadoutConfigurationData.hh"


class DheConfiguration : public CrcConfiguration {

public:
  DheConfiguration() : CrcConfiguration(0xde) {
    _readoutConfiguration.crateNumber(0xde);
  }

  virtual ~DheConfiguration() {
  }

  virtual bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "DheConfiguration::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }
    
    // Do underlying CRC configuration
    assert(CrcConfiguration::record(r));
    
    // Check record type
    switch (r.recordType()) {
      
      // Run start 
    case RcdHeader::runStart: {

      // Disable all CRCs except for trigger BE
      for(unsigned s(2);s<=21;s++) _readoutConfiguration.slotEnable(s,false);
      
      if(_trgLocation.slotNumber()>0)
	_readoutConfiguration.slotEnable(_trgLocation.slotNumber(),true);
      
      // Now selectively enable some
      std::ifstream fin("DheFe.txt");
      if(fin) {
	unsigned s,f;
	fin >> s;
	while(fin) {
	  fin >> f;
	  if(f>0) {
	    _readoutConfiguration.slotEnable(s,true);
	    _readoutConfiguration.slotFeEnables(s,f);
	  }
	  fin >> s;
	}
	
	// TEMP!!! Enable trigger slot FE2 if cannot open file
      } else {
	_readoutConfiguration.slotFeEnables(_trgLocation.slotNumber(),0x02);
      }

      if(doPrint(r.recordType(),1))
	_readoutConfiguration.print(std::cout," ") << std::endl;
      
      break;
    }
      
      
      // Configuration start 
    case RcdHeader::configurationStart: {
      
      // Handle the ones which need work

      if(_runType.majorType()==DaqRunType::dhe ||
	 _runType.majorType()==DaqRunType::beam ||
	 _runType.majorType()==DaqRunType::cosmics) {

	dheReadoutConfiguration(r);
	dheVfeConfiguration(r);
	dheFeConfiguration(r);
      }
      
      break;
    }
      
    default: {
      break;
    }
    };
    
    return true;
  }

  virtual bool dheReadoutConfiguration(RcdRecord &r) {

    SubInserter inserter(r);
    CrcReadoutConfigurationData
      *b(inserter.insert<CrcReadoutConfigurationData>(true));
    *b=_readoutConfiguration;
    
    const unsigned char v(_runType.version());
    const UtlPack u(_runType.version());

    // Now do the readout periods, soft triggers and modes
    switch(_runType.type()) {

    case DaqRunType::dheTest: {
      b->beSoftTrigger(true);
      b->vlinkBlt(true);
      break;
    }
      
    case DaqRunType::dheNoise: {
      b->vmePeriod(v/8);
      b->bePeriod(v/8);
      b->fePeriod(v/8);

      b->beSoftTrigger(true);
      b->vlinkBlt(true);
      break;
    }

    case DaqRunType::dheBeam:
    case DaqRunType::dheCosmics:

    case DaqRunType::beamTest:
    case DaqRunType::beamNoise:
    case DaqRunType::beamData:
    case DaqRunType::beamHoldScan:
    case DaqRunType::beamStage:
    case DaqRunType::beamStageScan:

    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      if((_configurationNumber%3)<2) {
	b->becPeriod(16);
	b->bePeriod(64);
	b->fePeriod(200);
      } else {
	b->becPeriod(16);
	b->bePeriod(64);
	b->fePeriod(200);
      }
      b->vlinkBlt(true);
      break;
    }
      
    default: {
      break;
    }
    };

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

    return true;
  }
  

  virtual bool dheVfeConfiguration(RcdRecord &r) {

    // Define vector for configuration data
    std::vector< CrcLocationData<DheVfeConfigurationData4> > vVcd;

    _location.slotBroadcast(true);
    _location.crcComponent(CrcLocation::feBroadcast);
    vVcd.push_back(CrcLocationData<DheVfeConfigurationData4>(_location));


    //const unsigned char v(_runType.version());
    const UtlPack vBits(_runType.version());

    switch(_runType.type()) {

    case DaqRunType::dheTest: {
      break;
    }
      
    case DaqRunType::dheNoise: {
      break;
    }
      
    case DaqRunType::dheBeam:
    case DaqRunType::dheCosmics:
      
    case DaqRunType::beamTest:
    case DaqRunType::beamNoise:
    case DaqRunType::beamData:
    case DaqRunType::beamHoldScan:
    case DaqRunType::beamStage:
    case DaqRunType::beamStageScan:
      
    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      if((_configurationNumber%3)==1) {
	
	// Calibration
	
      } else {
	
	// Standard readout
      }

      break;
    }
      
    default: {
      break;
    }
    };

    // Load configuration into record
    SubInserter inserter(r);
    
    if(doPrint(r.recordType(),1)) std::cout
	<< " Number of DheVfeConfigurationData subrecords inserted = "
	<< vVcd.size() << std::endl << std::endl;
    
    for(unsigned i(0);i<vVcd.size();i++) {
      if(doPrint(r.recordType(),2)) vVcd[i].print(std::cout,"  ") << std::endl;
	inserter.insert< CrcLocationData<DheVfeConfigurationData4> >(vVcd[i]);
    }
    
    return true;
  }
  

  virtual bool dheFeConfiguration(RcdRecord &r) {

    // Define vector for configuration data
    std::vector< CrcLocationData<CrcFeConfigurationData> > vFcd;

    _location.slotBroadcast(true);
    _location.crcComponent(CrcLocation::feBroadcast);
    vFcd.push_back(CrcLocationData<CrcFeConfigurationData>(_location));

    // Always do 64 reads and set other counters to match
    vFcd[0].data()->setDhe();

    //const unsigned char v(_runType.version());
    const UtlPack vBits(_runType.version());

    switch(_runType.type()) {

    case DaqRunType::dheTest: {
      break;
    }
      
    case DaqRunType::dheNoise: {
      break;
    }
      
    case DaqRunType::dheBeam:
    case DaqRunType::dheCosmics:
      
    case DaqRunType::beamTest:
    case DaqRunType::beamNoise:
    case DaqRunType::beamData:
    case DaqRunType::beamHoldScan:
    case DaqRunType::beamStage:
    case DaqRunType::beamStageScan:
      
    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      if((_configurationNumber%3)==1) {
	
	// Calibration
	
      } else {
	
	// Standard readout
      }

      break;
    }
      
    default: {
      break;
    }
    };

    // Load configuration into record
    SubInserter inserter(r);
    
    if(doPrint(r.recordType(),1)) std::cout
	<< " Number of CrcFeConfigurationData subrecords inserted = "
	<< vFcd.size() << std::endl << std::endl;
    
    for(unsigned i(0);i<vFcd.size();i++) {
      if(doPrint(r.recordType(),2)) vFcd[i].print(std::cout,"  ") << std::endl;
	inserter.insert< CrcLocationData<CrcFeConfigurationData> >(vFcd[i]);
    }
    
    return true;
  }
  

protected:
  CrcReadoutConfigurationData _readoutConfiguration;
};

#endif
