#ifndef TrgConfiguration_HH
#define TrgConfiguration_HH

#include <iostream>
#include <fstream>

#include "RcdUserRW.hh"
#include "SubRecordType.hh"
#include "SubInserter.hh"
#include "SubAccessor.hh"


class TrgConfiguration : public RcdUserRW {

public:
  TrgConfiguration(unsigned char c, unsigned char s) :
    _location(c,s,CrcLocation::beTrg,1) {
  }

  virtual ~TrgConfiguration() {
  }

  virtual bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << std::endl << "TrgConfiguration::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.access<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.access<DaqConfigurationStart>());
      assert(v.size()==1);
      if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;

      assert(trgReadoutConfiguration(r,*(v[0])));
      assert(trgConfiguration(r,*(v[0])));

      break;
    }

    default: {

      break;
    }
    }; // switch(recordtype)

    return true;
  }

  bool trgReadoutConfiguration(RcdRecord &r, const DaqConfigurationStart &d) {

    // Always put a readout configuration into the record

    // Ensure always starting from known state
    _trgReadoutConfiguration=TrgReadoutConfigurationData();

    // Turn off trigger for several major run types
    if(_runType.majorType()==DaqRunType::daq ||
       _runType.majorType()==DaqRunType::slow) {
      _trgReadoutConfiguration.enable(false);

    // Otherwise need to handle by type
    } else {

      // Assume most types need a trigger
      _trgReadoutConfiguration.enable(true);
      
      // Set some reasonable parameters
      _trgReadoutConfiguration.readcPeriod(1);
      _trgReadoutConfiguration.readPeriod(16);
      _trgReadoutConfiguration.spillInvert(true);

      // Get the configuration number and version
      const unsigned iCfg(d.configurationNumberInRun());
      //const unsigned char v(_runType.version());
      const UtlPack u(_runType.version());

      // Select on run type
      switch(_runType.type()) {
	
      case DaqRunType::crcNoise: {
        _trgReadoutConfiguration.enable(u.bits(0,1)==0);
        _trgReadoutConfiguration.clearBeTrgTrigger(true);
        _trgReadoutConfiguration.beTrgSoftTrigger(true);
        _trgReadoutConfiguration.beTrgSquirt(true);
        _trgReadoutConfiguration.beTrgVlink(false);
        _trgReadoutConfiguration.readPeriod(0);
        break;
      }
      case DaqRunType::crcTest:
      case DaqRunType::crcBeParameters:
      case DaqRunType::crcFeParameters:
      case DaqRunType::crcIntDac:
      case DaqRunType::crcIntDacScan:
      case DaqRunType::crcExtDac:
      case DaqRunType::crcExtDacScan:
      case DaqRunType::crcFakeEvent:
      case DaqRunType::crcModeTest: {
        _trgReadoutConfiguration.enable(false);
        break;
      }

      case DaqRunType::trgTest: {
	_trgReadoutConfiguration.enable(true);
	break;
      }
      case DaqRunType::trgReadout: {
	if(iCfg==0) {
	  _trgReadoutConfiguration.enable(true);
	  _trgReadoutConfiguration.clearBeTrgTrigger(true);
	  _trgReadoutConfiguration.beTrgSoftTrigger((u.word()%2)==1);
	  _trgReadoutConfiguration.readPeriod(1);
	  _trgReadoutConfiguration.beTrgSquirt(((u.word()/2)%2)==1);
	}
	break;
      }
      case DaqRunType::trgParameters: {
	if(iCfg==0) {
	  _trgReadoutConfiguration.enable(true);
	  _trgReadoutConfiguration.clearBeTrgTrigger(true);
	  _trgReadoutConfiguration.beTrgSoftTrigger((u.word()%2)==0);
	  _trgReadoutConfiguration.readPeriod(1);
	  _trgReadoutConfiguration.beTrgSquirt(false);
	}
	break;
      }
      case DaqRunType::trgNoise: {
	if(iCfg==0) {
	  _trgReadoutConfiguration.enable(true);
	}
	break;
      }
      case DaqRunType::trgSpill: {
	if(iCfg==0) {
	  _trgReadoutConfiguration.beTrgSquirt(true);
	  _trgReadoutConfiguration.beTrgPollNumber(10000);
	  _trgReadoutConfiguration.beTrgSpillNumber(500);
	  _trgReadoutConfiguration.beTrgSpillTime(UtlTimeDifference(1,0));
	  _trgReadoutConfiguration.enable(true);
	  _trgReadoutConfiguration.clearBeTrgTrigger(false);
	  _trgReadoutConfiguration.readPeriod(1);
	}
	break;
      }
	
      case DaqRunType::emcTest:
      case DaqRunType::emcNoise:
      case DaqRunType::emcFeParameters:
      case DaqRunType::emcVfeDac:
      case DaqRunType::emcVfeDacScan:
      case DaqRunType::emcVfeHoldScan: {
	_trgReadoutConfiguration.enable(false);
	break;
      }
      case DaqRunType::emcTrgTiming:
      case DaqRunType::emcTrgTimingScan: {
	break;
      }
	
      case DaqRunType::sceCmNoise:
      case DaqRunType::scePmNoise:
      case DaqRunType::sceExpert: {

	// Bit 0 = BE s/w trigger, otherwise BeTrg s/w trigger
	if(u.bit(0)) {
	  _trgReadoutConfiguration.enable(false);
	} else {
	  _trgReadoutConfiguration.clearBeTrgTrigger(true);
	  _trgReadoutConfiguration.beTrgSoftTrigger(true);
	  _trgReadoutConfiguration.beTrgSquirt(false);
	  _trgReadoutConfiguration.beTrgVlink(true);
	}

	// Bit 2 = use normal spill signal
	_trgReadoutConfiguration.spillInvert(!u.bit(2));

	break;
      }
      case DaqRunType::sceCmLed:
      case DaqRunType::sceGain:	
      case DaqRunType::sceCmLedVcalibScan:
      case DaqRunType::sceCmLedHoldScan:
      case DaqRunType::scePmLed:
      case DaqRunType::scePmLedVcalibScan:
      case DaqRunType::scePmLedHoldScan: {
	_trgReadoutConfiguration.clearBeTrgTrigger(true);
	_trgReadoutConfiguration.beTrgSoftTrigger(false);
	_trgReadoutConfiguration.beTrgSquirt(false);
	_trgReadoutConfiguration.beTrgVlink(true);
	_trgReadoutConfiguration.spillInvert(false);

	_trgReadoutConfiguration.readcPeriod(10);
	_trgReadoutConfiguration.readPeriod(100);

	break;
      }
      case DaqRunType::sceTest:
      case DaqRunType::sceDacScan:
      case DaqRunType::sceAnalogOut:
      case DaqRunType::sceCmAsic:
      case DaqRunType::sceCmAsicVcalibScan:
      case DaqRunType::sceCmAsicHoldScan:
      case DaqRunType::scePmAsic:
      case DaqRunType::scePmAsicVcalibScan:
      case DaqRunType::scePmAsicHoldScan:
      case DaqRunType::sceScintillatorHoldScan: {
	_trgReadoutConfiguration.clearBeTrgTrigger(true);
	_trgReadoutConfiguration.beTrgSoftTrigger(true);
	_trgReadoutConfiguration.beTrgSquirt(false);
	_trgReadoutConfiguration.beTrgVlink(true);
	break;
      }

      case DaqRunType::ahcCmNoise:
      case DaqRunType::ahcPmNoise:
      case DaqRunType::ahcExpert: {

	// Bit 0 = BE s/w trigger, otherwise BeTrg s/w trigger
	if(u.bit(0)) {
	  _trgReadoutConfiguration.enable(false);
	} else {
	  _trgReadoutConfiguration.clearBeTrgTrigger(true);
	  _trgReadoutConfiguration.beTrgSoftTrigger(true);
	  _trgReadoutConfiguration.beTrgSquirt(false);
	  _trgReadoutConfiguration.beTrgVlink(true);
	}

	// Bit 2 = use normal spill signal
	_trgReadoutConfiguration.spillInvert(!u.bit(2));

	break;
      }
      case DaqRunType::ahcTest:
      case DaqRunType::ahcDacScan:
      case DaqRunType::ahcAnalogOut:
      case DaqRunType::ahcCmAsic:
      case DaqRunType::ahcCmAsicVcalibScan:
      case DaqRunType::ahcCmAsicHoldScan:
      case DaqRunType::ahcPmAsic:
      case DaqRunType::ahcPmAsicVcalibScan:
      case DaqRunType::ahcPmAsicHoldScan:
      case DaqRunType::ahcCmLed:
      case DaqRunType::ahcGain:	
      case DaqRunType::ahcCmLedVcalibScan:
      case DaqRunType::ahcCmLedHoldScan:
      case DaqRunType::ahcPmLed:
      case DaqRunType::ahcPmLedVcalibScan:
      case DaqRunType::ahcPmLedHoldScan:
      case DaqRunType::ahcScintillatorHoldScan: {
	_trgReadoutConfiguration.clearBeTrgTrigger(true);
	_trgReadoutConfiguration.beTrgSoftTrigger(true);
	_trgReadoutConfiguration.beTrgSquirt(false);
	_trgReadoutConfiguration.beTrgVlink(true);
	break;
      }

      case DaqRunType::dhcTest:
      case DaqRunType::dhcNoise: {
	_trgReadoutConfiguration.enable(false);
	break;
      }
      case DaqRunType::dheTest:
      case DaqRunType::dheNoise: {
	_trgReadoutConfiguration.enable(false);
	break;
      }

      case DaqRunType::tcmTest:
      case DaqRunType::tcmNoise:
      case DaqRunType::tcmCalLed:
      case DaqRunType::tcmPhysLed:
      case DaqRunType::tcmCalPedestal:
      case DaqRunType::tcmPhysPedestal: {
	_trgReadoutConfiguration.enable(false);
	break;
      }
	
      case DaqRunType::bmlInternalTest: {
	_trgReadoutConfiguration.enable(false);
	break;
      }
      case DaqRunType::bmlNoise: {
	break;
      }

      case DaqRunType::trgBeam:
	
      case DaqRunType::emcBeam:
      case DaqRunType::emcBeamHoldScan:
	
      case DaqRunType::sceBeam:
	//case DaqRunType::sceBeamHoldScan:
      case DaqRunType::sceBeamStage:
      case DaqRunType::sceBeamStageScan:
	
      case DaqRunType::ahcBeam:
	//case DaqRunType::ahcBeamHoldScan:
      case DaqRunType::ahcBeamStage:
      case DaqRunType::ahcBeamStageScan:
	
      case DaqRunType::dhcBeam:
	
      case DaqRunType::dheBeam:
	
      case DaqRunType::tcmBeam:
      case DaqRunType::tcmBeamHoldScan:
	
      case DaqRunType::bmlBeam:
	
      case DaqRunType::beamTest:
      case DaqRunType::beamNoise:
      case DaqRunType::beamData:
      case DaqRunType::beamHoldScan:
      case DaqRunType::beamStage:
      case DaqRunType::beamStageScan: {

	_trgReadoutConfiguration.clearBeTrgTrigger(true);
	_trgReadoutConfiguration.beTrgSoftTrigger(false);
	_trgReadoutConfiguration.beTrgSquirt(false);
	_trgReadoutConfiguration.beTrgVlink(true);
	//_trgReadoutConfiguration.beTrgVlink(false);

	// Configurations 0 and 1 are pedestals and calibration
	if((iCfg%3)!=2) {
	  //_trgReadoutConfiguration.readcPeriod(1);
	  //_trgReadoutConfiguration.readPeriod(16);
#ifdef FNAL_SETTINGS
	  _trgReadoutConfiguration.readcPeriod(20);
	  _trgReadoutConfiguration.readPeriod(200);
#else
	  _trgReadoutConfiguration.readcPeriod(10);
	  _trgReadoutConfiguration.readPeriod(100);
#endif
	  // Bit 6?

	  // Oscillator trigger
	  if(u.bit(7)) {

	  // Software trigger
	  } else {
	    _trgReadoutConfiguration.beTrgSoftTrigger(true);
	  }

	// Configuration 2 is data
	} else {
	  _trgReadoutConfiguration.spillInvert(false);

	  //_trgReadoutConfiguration.readcPeriod(1);
	  //_trgReadoutConfiguration.readPeriod(16);
#ifdef FNAL_SETTINGS
	  _trgReadoutConfiguration.readcPeriod(20);
	  _trgReadoutConfiguration.readPeriod(200);
#else
	  _trgReadoutConfiguration.readcPeriod(10);
	  _trgReadoutConfiguration.readPeriod(100);
#endif

	  // Bit 5 indicates faked trigger
	  
	  if(u.bit(5)) {
	    
	    // Software trigger
	    if(u.bits(0,4)==0) {
	      _trgReadoutConfiguration.beTrgSoftTrigger(true);

            // Oscillator trigger
	    } else {
	    }
	  }
	}

	break;
      }

      //ahcBeamHoldScan does not need the ped-led-beam loop; take only beam data

      case DaqRunType::sceBeamHoldScan:
      case DaqRunType::ahcBeamHoldScan: {
	_trgReadoutConfiguration.clearBeTrgTrigger(true);
	_trgReadoutConfiguration.beTrgSoftTrigger(false);
	_trgReadoutConfiguration.beTrgSquirt(false);
	_trgReadoutConfiguration.beTrgVlink(true);
	//_trgReadoutConfiguration.beTrgVlink(false);

	_trgReadoutConfiguration.spillInvert(false);

	//_trgReadoutConfiguration.readcPeriod(1);
	//_trgReadoutConfiguration.readPeriod(16);
#ifdef FNAL_SETTINGS
	  _trgReadoutConfiguration.readcPeriod(20);
	  _trgReadoutConfiguration.readPeriod(200);
#else
	_trgReadoutConfiguration.readcPeriod(10);
	_trgReadoutConfiguration.readPeriod(100);
#endif

	// Bit 5 indicates faked trigger
	if(u.bit(5)) {
	    
	  // Software trigger
	  if(u.bits(0,4)==0) {
	    _trgReadoutConfiguration.beTrgSoftTrigger(true);

            // Oscillator trigger
	  } else {
	  }
	}  
       

	break;

      }

	// COSMICS RUNS

      case DaqRunType::trgCosmics:
	
      case DaqRunType::emcCosmics:
      case DaqRunType::emcCosmicsHoldScan:
	
      case DaqRunType::sceCosmics:
      case DaqRunType::sceCosmicsHoldScan:
	
      case DaqRunType::ahcCosmics:
      case DaqRunType::ahcCosmicsHoldScan:
	
      case DaqRunType::dhcCosmics:
	
      case DaqRunType::dheCosmics:
	
      case DaqRunType::tcmCosmics:
      case DaqRunType::tcmCosmicsHoldScan:
	
      case DaqRunType::cosmicsTest:
      case DaqRunType::cosmicsNoise:
      case DaqRunType::cosmicsData:
      case DaqRunType::cosmicsHoldScan: {
	
	_trgReadoutConfiguration.clearBeTrgTrigger(true);
	_trgReadoutConfiguration.beTrgSoftTrigger(false);
	_trgReadoutConfiguration.beTrgSquirt(false);
	_trgReadoutConfiguration.beTrgVlink(true);
	//_trgReadoutConfiguration.beTrgVlink(false);

	// Configurations 0 and 1 are pedestals and calibration
	if((iCfg%3)!=2) {
	  _trgReadoutConfiguration.readcPeriod(1);
	  _trgReadoutConfiguration.readPeriod(16);
	  _trgReadoutConfiguration.readcPeriod(1);
	  _trgReadoutConfiguration.readPeriod(0);

	  // Bit 6?

	  // Oscillator trigger
	  if(u.bit(7)) {

	  // Software trigger
	  } else {
	    _trgReadoutConfiguration.beTrgSoftTrigger(true);
	  }

	// Configuration 2 is data
	} else {
	  _trgReadoutConfiguration.readcPeriod(1);
	  _trgReadoutConfiguration.readPeriod(1);
	  _trgReadoutConfiguration.readcPeriod(1);
	  _trgReadoutConfiguration.readPeriod(1);

	  // Bit 5 indicates faked trigger
	  if(u.bit(5)) {
	    
	    // Software trigger
	    if(u.bits(0,4)==0) {
	      _trgReadoutConfiguration.beTrgSoftTrigger(true);

            // Oscillator trigger
	    } else {
	    }
	  }
	}

	break;
      }
	
      default: {

	// We've missed something!
	assert(false);
	break;
      }
      }; // switch(type)
    }
      
    // Load configuration into record
    SubInserter inserter(r);
    inserter.insert<TrgReadoutConfigurationData>(_trgReadoutConfiguration);
    
    if(doPrint(r.recordType(),1)) {
      std::cout << " Number of TrgReadoutConfigurationData"
		<< " subrecords inserted = 1" << std::endl << std::endl;
      _trgReadoutConfiguration.print(std::cout,"  ") << std::endl;
    }

    return true;
  }
    
    
  bool trgConfiguration(RcdRecord &r, const DaqConfigurationStart &d) {

    // Only put a configuration object into the record when enabled
    if(!_trgReadoutConfiguration.enable()) return true;

    CrcLocationData<CrcBeTrgConfigurationData> tcd(_location);

    // Set some generally useful parameters
    tcd.data()->inputEnable(0);
    tcd.data()->generalEnable(1);
    tcd.data()->fifoIdleDepth(200);

    // For DHCALE, set longer readout times
    if(_location.crateNumber()==0xde) {
      tcd.data()->qdrConfiguration((8151<<19)+(3<<16)+(8101));
    }
    
    // Invert spill input to avoid beam for all calibration runs
#ifdef SPILL_INPUT
    tcd.data()->inputInvert(1<<SPILL_INPUT);
#endif

    // Get the configuration number and version
    const unsigned iCfg(d.configurationNumberInRun());
    //const unsigned char v(_runType.version());
    const UtlPack u(_runType.version());
      

    switch(_runType.type()) {

    case DaqRunType::crcNoise: {
      break;
    }

    case DaqRunType::trgTest: {
      break;
    }
    case DaqRunType::trgReadout: {
      break;
    }
    case DaqRunType::trgParameters: {
      break;
    }
    case DaqRunType::trgNoise: {
      tcd.data()->oscillatorEnable(true);
      tcd.data()->oscillationPeriod(4000); // 0.0001 sec
      break;
    }
    case DaqRunType::trgSpill: {
      tcd.data()->busyTimeout(8000); // 0.0002 sec
      tcd.data()->oscillatorEnable(true);
      tcd.data()->oscillationPeriod(4000); // 0.0001 sec
      break;
    }

    case DaqRunType::emcTrgTiming:
    case DaqRunType::emcTrgTimingScan: {
      break;
    }

    case DaqRunType::sceCmNoise:
    case DaqRunType::scePmNoise:
    case DaqRunType::sceExpert: {
      // Bit 0 = BE s/w trigger, otherwise BeTrg s/w trigger
      break;
    }
    case DaqRunType::sceTest:
    case DaqRunType::sceDacScan:
    case DaqRunType::sceAnalogOut:
    case DaqRunType::sceCmAsic:
    case DaqRunType::sceCmAsicVcalibScan:
    case DaqRunType::sceCmAsicHoldScan:
    case DaqRunType::scePmAsic:
    case DaqRunType::scePmAsicVcalibScan:
    case DaqRunType::scePmAsicHoldScan:
    case DaqRunType::sceScintillatorHoldScan: {
      // Always use BeTrg software trigger
      break;
    }

    case DaqRunType::ahcCmNoise:
    case DaqRunType::ahcPmNoise:
    case DaqRunType::ahcExpert: {
      // Bit 0 = BE s/w trigger, otherwise BeTrg s/w trigger
      break;
    }
    case DaqRunType::ahcTest:
    case DaqRunType::ahcDacScan:
    case DaqRunType::ahcAnalogOut:
    case DaqRunType::ahcCmAsic:
    case DaqRunType::ahcCmAsicVcalibScan:
    case DaqRunType::ahcCmAsicHoldScan:
    case DaqRunType::ahcPmAsic:
    case DaqRunType::ahcPmAsicVcalibScan:
    case DaqRunType::ahcPmAsicHoldScan:
    case DaqRunType::ahcCmLed:
    case DaqRunType::ahcGain:  
    case DaqRunType::ahcCmLedVcalibScan:
    case DaqRunType::ahcCmLedHoldScan:
    case DaqRunType::ahcPmLed:
    case DaqRunType::ahcPmLedVcalibScan:
    case DaqRunType::ahcPmLedHoldScan:
    case DaqRunType::ahcScintillatorHoldScan: {
      // Always use BeTrg software trigger
      break;
    }

    case DaqRunType::dhcTest:
    case DaqRunType::dhcNoise: {
      break;
    }

    case DaqRunType::dheTest:
    case DaqRunType::dheNoise: {
      // Always use BeTrg software trigger
      break;
    }

    case DaqRunType::bmlNoise: {
      break;
    }

      // external LED trigger input
    case DaqRunType::sceCmLed:
    case DaqRunType::sceGain:  
    case DaqRunType::sceCmLedVcalibScan:
    case DaqRunType::sceCmLedHoldScan:
    case DaqRunType::scePmLed:
    case DaqRunType::scePmLedVcalibScan:
    case DaqRunType::scePmLedHoldScan: {
      tcd.data()->inputInvert(0);
      tcd.data()->inputEnable(1<<11); //LED trigger input

      break;
    }


    // All the beam runs

    case DaqRunType::trgBeam:

    case DaqRunType::emcBeam:
    case DaqRunType::emcBeamHoldScan:

    case DaqRunType::sceBeam:
      //  case DaqRunType::sceBeamHoldScan:
    case DaqRunType::sceBeamStage:
    case DaqRunType::sceBeamStageScan:
      
    case DaqRunType::ahcBeam:
      //  case DaqRunType::ahcBeamHoldScan:
    case DaqRunType::ahcBeamStage:
    case DaqRunType::ahcBeamStageScan:
      
    case DaqRunType::dhcBeam:
      
    case DaqRunType::dheBeam:
      
    case DaqRunType::tcmBeam:
    case DaqRunType::tcmBeamHoldScan:

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

      // Configurations 0 and 1 are pedestals and calibration
      if((iCfg%3)!=2) {
	tcd.data()->inputEnable(0);

	// Bit 6?

        // Oscillator trigger
	if(u.bit(7)) {
	  tcd.data()->oscillatorEnable(true);
#ifdef FNAL_SETTINGS
	  tcd.data()->oscillationPeriod( 8000); // 0.2ms period, 0.1ms average wait
#else
	  tcd.data()->oscillationPeriod(40000); // 1kHz
#endif
	// Software trigger
	} else {
	}

      // Configuration 2 is data
      } else {

	// Make sure spill signal is not inverted
	tcd.data()->inputInvert(0);

	// Bit 5 indicates faked trigger
	if(u.bit(5)) {
	  tcd.data()->inputEnable(0);
	  
	  // Software trigger
	  if(u.bits(0,4)==0) {
	    
	  // Oscillator trigger
	  } else {
	    tcd.data()->oscillatorEnable(true);
	    tcd.data()->oscillationPeriod(1<<(u.bits(0,4)));
	  }

	// Real triggers
	} else {

	  // Single input trigger
	  if(!u.bit(4)) {
	    tcd.data()->inputEnable((1<<24)+(1<<u.halfByte(0)));

	    if(u.word()==6) tcd.data()->inputInvert(1<<6);

	  // Special case -v 31
	  } else if(u.halfByte(0)==15) {

#ifdef CERN_SETTINGS
	    // An .OR. of the 10x10s and the 20x20
	    tcd.data()->inputEnable((1<<24)+(1<<11)+(1<<10)+(1<<2));
#endif
#ifdef FNAL_SETTINGS
	    std::cout << "Setting Cherenkov veto (inputs 7 & 8 & !13)" << std::endl;
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));
	    // Cherenkov veto; .AND. of bits 7, 8 and not-13
	    //tcd.data()->andEnable(0,(1<<7)+(1<<8)+(1<<13)+(1<<(13+16)));

	    // Changed by Alex: Cherenkov veto; .AND. of bits 7 and 8 and not 12
	    tcd.data()->andEnable(0,(1<<7)+(1<<8)+(1<<13)+(1<<(13+16))); //NAND 13
	    //tcd.data()->andEnable(0,(1<<7)+(1<<8)+(1<<12));//AND
	    //	    tcd.data()->inputInvert(1<<13);

	  // Special case -v 30
	  } else if (u.halfByte(0)==14) {
	    std::cout << "Setting Cherenkov veto (inputs 7 & 8 & 13)" << std::endl;
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));

	    tcd.data()->andEnable(0,(1<<7)+(1<<8)+(1<<13)); //AND 13

	  // Special case -v 29
	  } else if (u.halfByte(0)==13) {
	    std::cout << "Setting Cherenkov veto" << std::endl;
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));

	    tcd.data()->andEnable(0,(1<<7)+(1<<8)+(1<<12)+(1<<(12+16))); //NAND 12

	  // Special case -v 27
	  } else if (u.halfByte(0)==11) {
	    std::cout << "Setting Cherenkov veto" << std::endl;
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));

	    tcd.data()->andEnable(0,(1<<7)+(1<<8)+(1<<12)); //AND 12
	  // Special case -v 25
	  } else if (u.halfByte(0)==9) {
	    std::cout << "Setting Cherenkov veto and Muon veto" << std::endl;
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));

	    // 7 & 8 & (!13) & (!10)
	    tcd.data()->andEnable( 0,   (1<<7)
                                      + (1<<8)
                                      + (1<<13) + (1<<(13+16))
                                     // + (1<<12) + (1<<(12+16)) );
                                      + (1<<10) + (1<<(10+16)) );
#endif
 
	  // Internal coincidence of neighbouring inputs
	  } else {
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));
	    tcd.data()->andEnable(0,3<<u.halfByte(0));
	    //tcd.data()->andEnable(0,259<<u.halfByte(0));
	 } 

	  // Always run oscillator at a low level
	  tcd.data()->oscillatorEnable(true);      // turn on oscillator in spill for CERN
#ifdef DESY_SETTINGS
	  tcd.data()->oscillationPeriod(40000000); // 1Hz 05.12.06 changed for DESY test beam
	  //tcd.data()->oscillatorEnable(false);      // 15.12.06 turn oscillator off for DESY test beam
#endif
#ifdef CERN_SETTINGS
	  //tcd.data()->oscillationPeriod( 400000); // 100Hz CERN setting
	  //tcd.data()->oscillationPeriod(2000000); // 20Hz
	  tcd.data()->oscillationPeriod(4000000); // 10Hz 
#endif
#ifdef FNAL_SETTINGS
	  tcd.data()->oscillationPeriod(4000000); // 10Hz 
#endif
	}
      }
      break;
    }


      // ahcBeamHoldScan: no configuration ped-led-beam loop
    case DaqRunType::sceBeamHoldScan:
    case DaqRunType::ahcBeamHoldScan: {

      // Bit 5 indicates faked trigger
      if(u.bit(5)) {
	tcd.data()->inputEnable(0);
	  
	// Software trigger
	if(u.bits(0,4)==0) {
	  
	  // Oscillator trigger
	} else {
	  tcd.data()->oscillatorEnable(true);
	  tcd.data()->oscillationPeriod(1<<(u.bits(0,4))); // 1kHz
	}

	// Real triggers
      } else {
	
	// Single input trigger
	if(!u.bit(4)) {
	  tcd.data()->inputEnable(1<<u.halfByte(0));

	  // Internal coincidence of neighbouring inputs
	} else {
	  tcd.data()->inputEnable(1<<25);
	  tcd.data()->generalEnable(1+(1<<8));
	  tcd.data()->andEnable(0,3<<u.halfByte(0));
	}


	// Always run oscillator at a low level
	tcd.data()->oscillatorEnable(true);      // turn on oscillator in spill for CERN
#ifdef DESY_SETTINGS
	tcd.data()->oscillationPeriod(40000000); // 1Hz 05.12.06 changed for DESY test beam
#endif
#ifdef CERN_SETTINGS
	tcd.data()->oscillationPeriod(4000000); // 10Hz 
#endif
#ifdef FNAL_SETTINGS
	tcd.data()->oscillationPeriod(4000000); // 10Hz 
#endif

      }
    
      break;

    }

      // COSMICS

    case DaqRunType::trgCosmics:

    case DaqRunType::emcCosmics:
    case DaqRunType::emcCosmicsHoldScan:

    case DaqRunType::sceCosmics:
    case DaqRunType::sceCosmicsHoldScan:
      
    case DaqRunType::ahcCosmics:
    case DaqRunType::ahcCosmicsHoldScan:
      
    case DaqRunType::dhcCosmics:
	
    case DaqRunType::dheCosmics:
	
    case DaqRunType::tcmCosmics:
    case DaqRunType::tcmCosmicsHoldScan:

    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {

      // Configurations 0 and 1 are pedestals and calibration
      if((iCfg%3)!=2) {
	tcd.data()->inputEnable(0);

	// Bit 6?

        // Oscillator trigger
	if(u.bit(7)) {
	  tcd.data()->oscillatorEnable(true);
	  tcd.data()->oscillationPeriod(40000); // 1kHz
	  

	// Software trigger
	} else {
	}

      // Configuration 2 is data
      } else {

	// Bit 5 indicates faked trigger
	if(u.bit(5)) {
	  tcd.data()->inputEnable(0);
	  
	  // Software trigger
	  if(u.bits(0,4)==0) {
	    
	  // Oscillator trigger
	  } else {
	    tcd.data()->oscillatorEnable(true);
	    tcd.data()->oscillationPeriod(1<<(u.bits(0,4)));
	  }

	// Real triggers
	} else {

	  // Single input trigger
	  if(!u.bit(4)) {
	    tcd.data()->inputEnable((1<<24)+(1<<u.halfByte(0)));

	  // Special case; here and .OR. of both (20x20.AND.100x100)'s
	  } else if(u.halfByte(0)==15) {
	    tcd.data()->inputEnable((1<<26)+(1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));
	    tcd.data()->andEnable(0,(1<<2)+(1<<3));
	    tcd.data()->andEnable(1,(1<<2)+(1<<4));

	  // Internal coincidence of neighbouring inputs
	  } else {
	    tcd.data()->inputEnable((1<<25)+(1<<24));
	    tcd.data()->generalEnable(1+(1<<8));
	    tcd.data()->andEnable(0,3<<u.halfByte(0));
	  }

	  // Always run oscillator at a low level
	  tcd.data()->oscillationPeriod(400000000); // 0.1Hz
	}
      }
      break;
    }

    default: {
      
      // We've missed something!
      assert(false);
      break;
    }
    }; // switch(type)
    
    
    // Load configuration into record
    SubInserter inserter(r);
    inserter.insert< CrcLocationData<CrcBeTrgConfigurationData> >(tcd);
    
    if(doPrint(r.recordType(),1)) {
      std::cout << " Number of CrcBeTrgConfigurationData"
		<< " subrecords inserted = 1" << std::endl << std::endl;
      tcd.print(std::cout,"  ") << std::endl;
    }

    return true;
  }

/*
bool pedestalTrigger(unsigned pedType) {
  if(pedType==0) {
    vTcd[t].data()->inputEnable(1<<v);

  } else if(pedType==254) {
    vTrd[0].beTrgSoftTrigger(true);
    vTcd[t].data()->inputEnable(0);

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


protected:
  const CrcLocation _location;
  DaqRunType _runType;
  TrgReadoutConfigurationData _trgReadoutConfiguration;
//CrcBeTrgConfigurationData _crcBeTrgConfiguration;
};

#endif
