#ifndef CrcConfiguration_HH
#define CrcConfiguration_HH

/**********************************************************************
 * CrcConfiguration - puts CRC configuration data into record for one
 *                     crate depending on run type
 *
 * This mainly handles major run types slow, crc and trg
 * Major types daq and bml just turn off all CRC readout
 * Major type emc, ahc, dhc, tcm when not this crate do the same
 * Major types emc, ahc, dhc, tcm when this crate and beam and cosmics
 * are handled in the relevant XxxConfiguration classes
 *
 * For major type crc, the run types and versions are:
 * crcTest - defaults
 * crcNoise - 
 * crcIntDac -
 * crcExtDac -
 * crcParameters -
 * crcFakeEvent -
 *
 * For major type crc, the run types and versions are:
 * trgTest - defaults
 * trgReadout -
 * trgParameters -
 * trgNoise -
 * trgSpill -
 *
 **********************************************************************/

#include <iostream>
#include <fstream>

// dual/inc/daq
#include "DaqRunStart.hh"
#include "DaqConfigurationStart.hh"
#include "DaqSpillStart.hh"
#include "DaqRunType.hh"

// dual/inc/rcd
#include "RcdUserRW.hh"

// dual/inc/sub
#include "SubInserter.hh"
#include "SubAccessor.hh"


class CrcConfiguration : public RcdUserRW {

public:
  CrcConfiguration(unsigned char c) : 
    _location(c,0,0,1), _trgLocation(c,0,CrcLocation::beTrg,1),
    _runType(), _configurationNumber(0) {
  }

  virtual ~CrcConfiguration() {
  }

  void trgSlot(unsigned s) {
    assert(s>0 && s<=21);
    _trgLocation.slotNumber(s);

    std::cout << "CrcConfiguration::trgSlot()" << std::endl;
    _trgLocation.print(std::cout," ") << std::endl;
  }

  virtual bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "CrcConfiguration::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }

    // Check record type
    switch (r.recordType()) {

    // Run start 
    case RcdHeader::runStart: {

      // Access the DaqRunStart
      SubAccessor accessor(r);
      std::vector<const DaqRunStart*>
	v(accessor.extract<DaqRunStart>());
      assert(v.size()==1);
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;

      _runType=v[0]->runType();

      break;
    }

    // Configuration start is used to set up system
    case RcdHeader::configurationStart: {

      // Access the DaqConfigurationStart
      SubAccessor accessor(r);
      std::vector<const DaqConfigurationStart*>
	v(accessor.extract<DaqConfigurationStart>());
      assert(v.size()==1);
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;

      _configurationNumber=v[0]->configurationNumberInRun();


      // Do slow configuration for all run types
      slowConfiguration(r);

      // Do nothing for the following; configuration done elsewhere
      if((_runType.majorType()==DaqRunType::emc &&
	  _location.crateNumber()==0xec)  ||
	 (_runType.majorType()==DaqRunType::ahc &&
	  _location.crateNumber()==0xac)  ||
	 (_runType.majorType()==DaqRunType::dhc &&
	  _location.crateNumber()==0xdc)  ||
	 (_runType.majorType()==DaqRunType::tcm &&
	  _location.crateNumber()==0xac)  ||

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

      } else {

	// Decide if configuring or disabling
	bool disableAdc(true);
	bool disableTrg(true);

	// Handle run types with no other CRC readout
	if(_runType.majorType()==DaqRunType::daq ||
	   _runType.majorType()==DaqRunType::slow ||
	   
	   (_runType.majorType()==DaqRunType::emc &&
	    _location.crateNumber()!=0xec)  ||
	   (_runType.majorType()==DaqRunType::ahc &&
	    _location.crateNumber()!=0xac)  ||
	   (_runType.majorType()==DaqRunType::dhc &&
	    _location.crateNumber()!=0xdc)  ||
	   (_runType.majorType()==DaqRunType::tcm &&
	    _location.crateNumber()!=0xac)) {

	  disableAdc=true;
	  disableTrg=true;
	}

	// Beam line needs to use the CRC trigger only
	if(_runType.majorType()==DaqRunType::bml) {

	  disableAdc=true;
	  disableTrg=false;
	}

	// These run types need full configuration here
	if(_runType.majorType()==DaqRunType::crc ||
	   _runType.majorType()==DaqRunType::trg) {

	  disableAdc=false;
	  disableTrg=false;
	}	  

	// Handle trigger
	if(disableTrg) {
	  
	  // Only disable trigger if in this crate
	  if(_configurationNumber==0 && _trgLocation.slotNumber()>0) {
	    SubInserter inserter(r);
	    TrgReadoutConfigurationData
	      *b(inserter.insert<TrgReadoutConfigurationData>(true));
	    b->enable(false);
	    if(doPrint(r.recordType(),1)) b->print(std::cout," ") << std::endl;
	  }

	} else {
	  beTrgReadoutConfiguration(r);
	  beTrgConfiguration(r);
	}
	
	// Handle the rest of the CRCs
	if(disableAdc) {

	  // Disable all CRCs in this crate
	  if(_configurationNumber==0) {
	    SubInserter inserter(r);
	    CrcReadoutConfigurationData
	      *b(inserter.insert<CrcReadoutConfigurationData>(true));
	    b->crateNumber(_location.crateNumber());
	    for(unsigned i(2);i<=21;i++) b->slotEnable(i,false);
	    if(doPrint(r.recordType(),1)) b->print(std::cout," ") << std::endl;
	  }

	} else {
	  readoutConfiguration(r);
	  beConfiguration(r);
	  feConfiguration(r);
	}
      }
	
      /*
      // Only do trigger board for the following
      if(_runType.majorType()==DaqRunType::trg) {

	// Disable all other CRCs
	SubInserter inserter(r);
	CrcReadoutConfigurationData
	  *b(inserter.insert<CrcReadoutConfigurationData>(true));
	b->crateNumber(_location.crateNumber());
	for(unsigned i(2);i<=21;i++) {
	  if(i!=_trgLocation.slotNumber()) b->slotEnable(i,false);
	  else {
	    //b->slotFeEnable(i,0,false);
	    b->slotFeEnable(i,1,false);
	    b->slotFeEnable(i,2,false);
	    b->slotFeEnable(i,3,false);
	    b->slotFeEnable(i,4,false);
	    b->slotFeEnable(i,5,false);
	    b->slotFeEnable(i,6,false);
	    b->slotFeEnable(i,7,false);
	  }
	}
	if(doPrint(r.recordType(),1)) b->print(std::cout," ") << std::endl;

	CrcLocationData<CrcBeConfigurationData>
	  *c(inserter.insert< CrcLocationData<CrcBeConfigurationData> >(true));
	c->location(_location);
	c->slotNumber(_trgLocation.slotNumber());
	c->crcComponent(CrcLocation::be);

	c->data()->j0TriggerEnable(false);
	c->data()->j0BypassEnable(true);
	c->data()->fastSyncEnable(((_runType.version()/8)%2)==1);
	c->data()->trgDataFe0Enable(((_runType.version()/4)%2)==1);
	if(c->data()->trgDataFe0Enable()) {
	  c->data()->feDataEnable(0x1);
	  c->data()->feTriggerEnable(0x1);
	} else {
	  c->data()->feDataEnable(0xff);
	  c->data()->feTriggerEnable(0xff);
	}
	if(doPrint(r.recordType(),1)) c->print(std::cout," ") << std::endl;

	CrcLocationData<CrcFeConfigurationData>
	  *d(inserter.insert< CrcLocationData<CrcFeConfigurationData> >(true));
	d->location(_location);
	d->slotNumber(_trgLocation.slotNumber());
	d->crcComponent(CrcLocation::feBroadcast);
	//d->data()->frameSyncDelay(17);
	d->data()->qdrDataDelay(3);
	if(doPrint(r.recordType(),2)) d->print(std::cout," ") << std::endl;
      }
      */
      
      break;
    }

    // Run end
    case RcdHeader::runEnd: {
      _configurationNumber=0;
      break;
    }

    default: {
      break;
    }
    };

    return true;
  }

  virtual bool slowConfiguration(RcdRecord &r) {

    // Only set slow configuration for the first configuration of each run
    if(_configurationNumber>0) return true;

    SubInserter inserter(r);
    _location.slotBroadcast(true);

    CrcLocationData<CrcLm82ConfigurationData>
      *c(inserter.insert< CrcLocationData<CrcLm82ConfigurationData> >(true));
    c->location(_location);
    c->crcComponent(CrcLocation::vmeLm82);
    if(doPrint(r.recordType(),1)) c->print(std::cout," ") << std::endl;

    c=inserter.insert< CrcLocationData<CrcLm82ConfigurationData> >(true);
    c->location(_location);
    c->crcComponent(CrcLocation::be);
    if(doPrint(r.recordType(),1)) c->print(std::cout," ") << std::endl;

    c=inserter.insert< CrcLocationData<CrcLm82ConfigurationData> >(true);
    c->location(_location);
    c->crcComponent(CrcLocation::feBroadcast);
    if(doPrint(r.recordType(),1)) c->print(std::cout," ") << std::endl;

    CrcLocationData<CrcAdm1025ConfigurationData>
      *d(inserter.insert< CrcLocationData<CrcAdm1025ConfigurationData> >(true));
    d->location(_location);
    d->crcComponent(CrcLocation::vmeAdm1025);
    if(doPrint(r.recordType(),1)) d->print(std::cout," ") << std::endl;

    return true;    
  }
  
  virtual bool beTrgReadoutConfiguration(RcdRecord &r) {

    // Define vector for configuration data
    std::vector<TrgReadoutConfigurationData> vTrd;
    
    // Override if trigger slot is in this crate
    if(_trgLocation.slotNumber()>0) {

      // If crc run, disable readout
      if(_runType.majorType()==DaqRunType::crc) {
	if(_configurationNumber==0) {
	  vTrd.push_back(TrgReadoutConfigurationData());
	  vTrd[0].enable(false);
	}
      }

      // If trg or bml run, enable readout
      if(_runType.majorType()==DaqRunType::trg ||
	 _runType.majorType()==DaqRunType::bml) {

	// Get readout configuration
	vTrd.push_back(TrgReadoutConfigurationData());

	// Now set up depending on run type and version
	const unsigned char v(_runType.version());
	const UtlPack u(_runType.version());
	
	switch(_runType.type()) {
	  
	case DaqRunType::trgTest: {
	  break;
	}
	case DaqRunType::trgReadout: {
	  vTrd[0].enable(true);
	  vTrd[0].clearBeTrgTrigger(true);
	  vTrd[0].beTrgSoftTrigger((u.word()%2)==1);
	  vTrd[0].readPeriod(1);
	  vTrd[0].beTrgSquirt(((u.word()/2)%2)==1);
	  break;
	}
	case DaqRunType::trgParameters: {
	  vTrd[0].enable(true);
	  vTrd[0].clearBeTrgTrigger(true);
	  vTrd[0].beTrgSoftTrigger((u.word()%2)==0);
	  vTrd[0].readPeriod(1);
	  vTrd[0].beTrgSquirt(false);
	  break;
	}
	case DaqRunType::trgNoise: {
	  vTrd[0].enable(true);
	  vTrd[0].clearBeTrgTrigger(true);

	  vTrd[0].beTrgSoftTrigger(u.bit(0));

	  // Don't read FIFO using squirt if sending data to Vlink
	  if(_trgLocation.slotNumber()>0 && u.bit(2)) vTrd[0].beTrgSquirt(false);
	  else                                        vTrd[0].beTrgSquirt(true);

	  if(u.bit(3)) vTrd[0].readcPeriod(1);
	  else         vTrd[0].readcPeriod(0);

	  vTrd[0].readPeriod(u.halfByte(1));

	  break;
	}
	case DaqRunType::trgSpill: {
	  vTrd[0].beTrgSquirt(true);
	  vTrd[0].beTrgPollNumber(10000);
	  vTrd[0].beTrgSpillNumber(500);
	  vTrd[0].beTrgSpillTime(UtlTimeDifference(1,0));
	  vTrd[0].enable(true);
	  vTrd[0].clearBeTrgTrigger(false);
	  vTrd[0].readPeriod(1);
	  break;
	}

	case DaqRunType::bmlNoise: {
	  vTrd[0].enable(true);
          vTrd[0].clearBeTrgTrigger(true);
	  vTrd[0].beTrgSoftTrigger(v==254);
          vTrd[0].beTrgSquirt(true);

          vTrd[0].readPeriod(16);
          vTrd[0].readcPeriod(16);
          vTrd[0].readPeriod(1); // temp

	  break;
	}

	default: {
	  break;
	}
	}; // switch(type)
      }
    }

    // Load configuration into record
    SubInserter inserter(r);
    
    if(doPrint(r.recordType(),1)) std::cout 
      << " Number of TrgReadoutConfigurationData subrecords inserted = "
      << vTrd.size() << std::endl << std::endl;
    assert(vTrd.size()<=1);
    
    for(unsigned i(0);i<vTrd.size();i++) {
      if(doPrint(r.recordType(),1)) vTrd[i].print(std::cout,"  ") << std::endl;
      inserter.insert<TrgReadoutConfigurationData>(vTrd[i]);
    }
    
    return true;
  }
  
  virtual bool beTrgConfiguration(RcdRecord &r) {

    // Set location
    _location.crcComponent(CrcLocation::beTrg);

    // Define vector for configuration data
    std::vector< CrcLocationData<CrcBeTrgConfigurationData> > vTcd;
    
    // Turn trigger off for all CRCs
    if(_configurationNumber==0) {
      _location.slotBroadcast(true);
      vTcd.push_back(CrcLocationData<CrcBeTrgConfigurationData>(_location));
      vTcd[0].data()->inputEnable(0);
      vTcd[0].data()->generalEnable(0);
    }

    // Override if trigger slot is in this crate
    if(_trgLocation.slotNumber()>0) {

      // If trg or bml run, enable readout
      if(_runType.majorType()==DaqRunType::trg || 
	 _runType.majorType()==DaqRunType::bml) {

	const unsigned t(vTcd.size());
	vTcd.push_back(CrcLocationData<CrcBeTrgConfigurationData>(_trgLocation));
      
	// Now set up depending on run type and version
	const unsigned char v(_runType.version());
	const UtlPack u(_runType.version());
	
	switch(_runType.type()) {
	  
	case DaqRunType::trgTest: {
	  break;
	}
	case DaqRunType::trgReadout: {
	  break;
	}
	case DaqRunType::trgParameters: {
	  break;
	}
	case DaqRunType::trgNoise: {
	  if(u.bit(0)) {
	    vTcd[t].data()->inputEnable(0);
	  } else {
	    vTcd[t].data()->oscillatorEnable(true);
	    vTcd[t].data()->oscillationPeriod(40000); // 0.001 sec
	  }

	  if(u.bit(1)) vTcd[t].data()->generalEnable(0);
	  else         vTcd[t].data()->generalEnable(1);

	  break;
	}
	case DaqRunType::trgSpill: {
	  if(_configurationNumber==0) {
	    vTcd[t].data()->busyTimeout(8000); // 0.0002 sec
	    vTcd[t].data()->oscillatorEnable(true);
	    vTcd[t].data()->oscillationPeriod(4000); // 0.0001 sec
	  }
	  break;
	}

	case DaqRunType::bmlNoise: {
          vTcd[t].data()->generalEnable(0); // Don't trigger other CRCs
	  
          if(v<16) {        // Single input
            vTcd[t].data()->inputEnable(1<<v);

          } else if(v<31) { // Coincidence AND of neighbouring inputs
            vTcd[t].data()->inputEnable((1<<25)+(3<<(v-16)));
	    vTcd[t].data()->generalEnable(1<<8);
	    vTcd[t].data()->andEnable(0,3<<(v-16));

          } else if(v==254) { // Soft trigger
            vTcd[t].data()->inputEnable(0);

          } else if(v==255) { // Oscillator
            vTcd[t].data()->oscillatorEnable(true);
            vTcd[t].data()->oscillationPeriod(40000); // 1kHz
          }

	  break;
	}

	default: {
	  break;
	}
	}; // switch(type)
      }
    }

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

    // Only set readout configuration for the first time each run
    //if(_configurationNumber>0) return true; // NO! User can send configurationEnd command

    const unsigned char v(_runType.version());
    const UtlPack u(_runType.version());
    
    SubInserter inserter(r);
    
    CrcReadoutConfigurationData
      *b(inserter.insert<CrcReadoutConfigurationData>(true));
    b->crateNumber(_location.crateNumber());
    
    switch(_runType.type()) {

    case DaqRunType::crcTest: {
      break;
    }
    case DaqRunType::crcNoise:
    case DaqRunType::crcModeTest: {
      if((v%4)==1) {
	b->beSoftTrigger(true);
      }
      if((v%4)==2) {
	b->feBroadcastSoftTrigger(true);
      }
      if((v%4)==3) {
	b->feSoftTrigger(0,true);
	b->feSoftTrigger(1,true);
	b->feSoftTrigger(2,true);
	b->feSoftTrigger(3,true);
	b->feSoftTrigger(4,true);
	b->feSoftTrigger(5,true);
	b->feSoftTrigger(6,true);
	b->feSoftTrigger(7,true);
      }
      
      b->vlinkBlt(u.bit(2));
      
      if(u.bit(3)) {
	b->becPeriod(1);
	b->fePeriod(1);
      } else {
        b->becPeriod(0);
	b->fePeriod(0);
      }

      b->vmePeriod(u.halfByte(1));
      b->bePeriod(u.halfByte(1));
      
      break;
    }      
    case DaqRunType::crcBeParameters: {
      b->beSoftTrigger(true);
      b->vmePeriod(1);
      b->bePeriod(1);
      b->fePeriod(1);
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::crcFeParameters: {
      b->beSoftTrigger(true);
      b->vmePeriod(1);
      b->bePeriod(1);
      b->fePeriod(1);
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::crcIntDac: {
      b->beSoftTrigger(true);
      b->vmePeriod(0);
      b->bePeriod(0);
      b->fePeriod(0);
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::crcIntDacScan: {
      b->beSoftTrigger(true);
      b->vmePeriod(0);
      b->bePeriod(0);
      b->fePeriod(0);
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::crcExtDac: {
      b->beSoftTrigger(true);
      b->vmePeriod(0);
      b->bePeriod(0);
      b->fePeriod(0);
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::crcExtDacScan: {
      b->beSoftTrigger(true);
      b->vmePeriod(0);
      b->bePeriod(0);
      b->fePeriod(0);
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::crcFakeEvent: {
      b->beSoftTrigger(true);
      b->vmePeriod(0);
      b->bePeriod(0);
      b->fePeriod(0);
      b->vlinkBlt(true);
      break;
    }

    case DaqRunType::trgTest: {
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::trgReadout: {
      b->vlinkBlt(true);
      break;
    }
    case DaqRunType::trgParameters: {
      break;
    }
    case DaqRunType::trgNoise: {
      b->vlinkBlt(true);

      if(u.bit(3)) b->becPeriod(1);
      else         b->becPeriod(0);

      b->vmePeriod(u.halfByte(1));
      b->bePeriod(u.halfByte(1));
      b->fePeriod(u.halfByte(1));

      // If reading trigger data through FE0 Vlink, disable other FEs
      if(_trgLocation.slotNumber()>0 && u.bit(2)) {
	for(unsigned i(1);i<8;i++) b->slotFeEnable(_trgLocation.slotNumber(),i,false);
      }

      break;
    }
    case DaqRunType::trgSpill: {
      b->vlinkBlt(true);
      break;
    }

    default: {
      break;
    }
    };
  
    if(doPrint(r.recordType(),1)) b->print(std::cout," ") << std::endl;
    
    return true;
    
  }
  
  virtual bool beConfiguration(RcdRecord &r) {
    /*
    SubAccessor accessor(r);
    std::vector<const CrcReadoutConfigurationData*>
      w(accessor.extract<CrcReadoutConfigurationData>());
    */

    // Define vector for configuration data
    std::vector< CrcLocationData<CrcBeConfigurationData> > vBcd;

    _location.slotBroadcast(true);
    _location.crcComponent(CrcLocation::be);
    vBcd.push_back(CrcLocationData<CrcBeConfigurationData>(_location));

    const unsigned char v(_runType.version());
    const UtlPack u(_runType.version());

    if(_runType.majorType()==DaqRunType::crc) {
      vBcd[0].data()->j0TriggerEnable(false);
      vBcd[0].data()->j0BypassEnable(false);
    }

    switch(_runType.type()) {
      
    case DaqRunType::crcTest: {
      break;
    }
    case DaqRunType::crcNoise: {
      break;
    }
    case DaqRunType::crcBeParameters: {

      // Remove top bit from version number
      unsigned u=v%128;
      
      // Version = 0: trigger select
      if(u==0) {
	vBcd[0].data()->triggerSelect(_configurationNumber%256);
      }
      
      // Version = 1: mode
      if(u==1) {
	vBcd[0].data()->mode(_configurationNumber%256);
      }
      
      // Version = 2: readout control
      if(u==2) {
	vBcd[0].data()->readoutControl(_configurationNumber%256);
      }
      
      // Version = 3: run control
      if(u==3) {
	vBcd[0].data()->runControl(_configurationNumber%256);
      }
      
      // Version = 4: FE data enables
      if(u==4) {
	vBcd[0].data()->feDataEnable(_configurationNumber%256);
      }
      
      // Version = 5: DAQ identifier
      if(u==5) {
	vBcd[0].data()->daqId(_configurationNumber%4096);
      }
      
      // Version = 6: QDR address
      if(u==6) {
	vBcd[0].data()->qdrAddress(_configurationNumber%4);
      }
      
      // Version = 7: FE trigger enable
      if(u==7) {
	vBcd[0].data()->feTriggerEnable(_configurationNumber%256);
      }
      
      // Version = 8: J0 enables
      if(u==8) {
	vBcd[0].data()->j0TriggerEnable((_configurationNumber%2)==0);
	vBcd[0].data()->j0BypassEnable(((_configurationNumber/2)%2)==0);
      }
      
      // Version = 9: test
      if(u==9) {
	vBcd[0].data()->test(_configurationNumber%65536);
      }
      
      // Version = 10: test length
      if(u==10) {
	vBcd[0].data()->test(_configurationNumber%65536);
      }
      
      break;
    }
    case DaqRunType::crcFeParameters: {      
      break;
    }
    case DaqRunType::crcIntDac: {
      break;
    }
    case DaqRunType::crcIntDacScan: {
      break;
    }
    case DaqRunType::crcExtDac: {
      break;
    }
    case DaqRunType::crcExtDacScan: {
      break;
    }
    case DaqRunType::crcFakeEvent: {
      break;
    }

    case DaqRunType::trgTest: {
      break;
    }
    case DaqRunType::trgReadout: {
      break;
    }
    case DaqRunType::trgParameters: {
      break;
    }
    case DaqRunType::trgNoise: {
      vBcd[0].data()->j0TriggerEnable(!u.bit(1));
      vBcd[0].data()->j0BypassEnable(  u.bit(1));

      if(_trgLocation.slotNumber()>0 && u.bit(2)) {
	vBcd.push_back(CrcLocationData<CrcBeConfigurationData>(vBcd[0]));
	vBcd[1].slotNumber(_trgLocation.slotNumber());
	vBcd[1].data()->trgDataFe0Enable(true);
	vBcd[1].data()->feDataEnable(0x1);
	vBcd[1].data()->feTriggerEnable(0x1);
      }

      break;
    }
    case DaqRunType::trgSpill: {
      break;
    }

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

  virtual bool feConfiguration(RcdRecord &r) {

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

    // Always put in one for every configuration
    _location.slotBroadcast(true);
    _location.crcComponent(CrcLocation::feBroadcast);
    vFcd.push_back(CrcLocationData<CrcFeConfigurationData>(_location));

    const unsigned char v(_runType.version());
    const UtlPack u(_runType.version());
    
    switch(_runType.type()) {

    case DaqRunType::crcTest: {
      break;
    }
    case DaqRunType::crcNoise: {
      break;
    }
    case DaqRunType::crcBeParameters: {      
      break;
    }
    case DaqRunType::crcFeParameters: {
      
      // Remove highest bit from version number
      unsigned u=v%128;
      
      // Version = 0: HOLD width
      if(u==0) {
	vFcd[0].data()->holdWidth(vFcd[0].data()->holdWidth()+(_configurationNumber%4));
      }
      
      // Version = 1: HOLD width different per FE
      if(u==1) {
	for(unsigned f(0);f<8;f++) {
	  if(f==0) {
	    vFcd[0].crcComponent(CrcLocation::fe0);
	  } else {
	    _location.crcComponent((CrcLocation::CrcComponent)f);
	    vFcd.push_back(CrcLocationData<CrcFeConfigurationData>(_location));
	  }
	  vFcd[f].data()->holdStart(1);
	  vFcd[f].data()->holdWidth(vFcd[f].data()->holdWidth()+16384*(f/7)*_configurationNumber);
	}
      }
      
      // Version = 2: set ADC start and stop times
      if(u==2) {
	vFcd[0].data()->adcStartBeforeClock(_configurationNumber%18);
	vFcd[0].data()->adcEndAfterClock(_configurationNumber%18);// DO BETTER!
      }
      
      // Version = 3: set ADC delay
      if(u==3) {
	vFcd[0].data()->adcDelay(_configurationNumber%32);
      }
      
      // Version = 4: set FrameSync delay
      if(u==4) {
	vFcd[0].data()->frameSyncDelay(256*(_configurationNumber%32));
      }
      
      // Version = 5: set ReadoutSync delay
      if(u==5) {
	vFcd[0].data()->readoutSyncDelay(256*(_configurationNumber%32));
      }
      
      // Version = 6: set QDR data delay
      if(u==6) {
	vFcd[0].data()->qdrDataDelay(_configurationNumber%8);
      }
      
      // Version = 7: set counters on the VFE control lines
      if(u==7) {
	UtlPack p(0);
	
	for(unsigned i(0);i<6;i++) {
	  if((_configurationNumber%(i+2))==0) {
	    p.bit(i  ,true);
	    p.bit(i+6,true);
	  }
	}
	
	if((_configurationNumber%8)==0) {
	  p.bit(13,true);
	  p.bit(15,true);
	}
	
	vFcd[0].data()->vfeControl(p);
      }
      
      break;
    }
    case DaqRunType::crcIntDac: {
      vFcd[0].data()->internalDacEnable(true);
      if(u.bit(6)) vFcd[0].data()->dacData(CrcFeConfigurationData::bot,1024*(v&0x3f));
      if(u.bit(7)) vFcd[0].data()->dacData(CrcFeConfigurationData::top,1024*(v&0x3f));
      break;
    }
    case DaqRunType::crcIntDacScan: {
      vFcd[0].data()->dacData(CrcFeConfigurationData::bot,0);
      vFcd[0].data()->dacData(CrcFeConfigurationData::top,0);
      
      unsigned steps(v+1);
      if(_configurationNumber==0 || _configurationNumber>2*steps) {
	vFcd[0].data()->internalDacEnable(false);
      } else {
	vFcd[0].data()->internalDacEnable(true);
	if((_configurationNumber%2)==0) {
	  vFcd[0].data()->dacData(CrcFeConfigurationData::top,((_configurationNumber-1)/2)*(65536/steps));
	} else {
	  vFcd[0].data()->dacData(CrcFeConfigurationData::bot,((_configurationNumber-1)/2)*(65536/steps));
	}
      }
      break;
    }
    case DaqRunType::crcExtDac: {
      if((v&0x40)==0) vFcd[0].data()->dacData(CrcFeConfigurationData::bot,1024*(v&0x3f));
      if((v&0x80)==0) vFcd[0].data()->dacData(CrcFeConfigurationData::top,1024*(v&0x3f));
      break;
    }
    case DaqRunType::crcExtDacScan: {
      unsigned steps(v+1);
      if((_configurationNumber%2)==0) {
	vFcd[0].data()->dacData(CrcFeConfigurationData::bot,(_configurationNumber/2)*(65536/steps));
	vFcd[0].data()->dacData(CrcFeConfigurationData::top,0);
      } else {
	vFcd[0].data()->dacData(CrcFeConfigurationData::bot,0);
	vFcd[0].data()->dacData(CrcFeConfigurationData::top,(_configurationNumber/2)*(65536/steps));
      }
      break;
    }
    case DaqRunType::crcFakeEvent: {
      break;
    }
    case DaqRunType::crcModeTest: {
      unsigned i(_configurationNumber%7);
      unsigned j((_configurationNumber/7)%3);
      if(j==0) {
	vFcd[0].data()->vfeMplexClockPulses(4);
	vFcd[0].data()->adcEndAfterClock(4);
      }
      if(j==1) {
	vFcd[0].data()->vfeMplexClockPulses(70+i);
	vFcd[0].data()->adcEndAfterClock(70+i);

	vFcd[0].data()->holdEnd((vFcd[0].data()->adcEnd()+500)*4);
	vFcd[0].data()->frameSyncDelay(vFcd[0].data()->adcEnd()+1000);
	vFcd[0].data()->readoutSyncDelay(vFcd[0].data()->adcEnd()+1500);
      }
      if(j==2) {
	vFcd[0].data()->vfeMplexClockPulses(18);
	vFcd[0].data()->adcEndAfterClock(18);
      }
      break;
    }

    case DaqRunType::trgTest: {
      break;
    }
    case DaqRunType::trgReadout: {
      break;
    }
    case DaqRunType::trgParameters: {
      break;
    }
    case DaqRunType::trgNoise: {
      // Reduce data volume to one sample as ADC data not needed
      vFcd[0].data()->adcEndAfterClock(1);
      break;
    }
    case DaqRunType::trgSpill: {
      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(),1)) vFcd[i].print(std::cout,"  ") << std::endl;
      inserter.insert< CrcLocationData<CrcFeConfigurationData> >(vFcd[i]);
    }

    return true;
  }


protected:
  CrcLocation _location;
  CrcLocation _trgLocation;

  DaqRunType _runType;
  unsigned _configurationNumber;


};

#endif
