#ifndef DaqSequenceType_HH
#define DaqSequenceType_HH

/**********************************************************************
 * DaqSequenceType - defines run types available
 *
 * Whenever you add or change the run types, you must also edit the
 * DaqConfiguration.hh and corresponding XxxConfiguration.hh file
 *
 **********************************************************************/

#include <string>
#include <iostream>

#include "UtlPack.hh"
#include "DaqRunType.hh"


class DaqSequenceType {

public:
  enum Type {
    // daq
    daqTest=0x10*DaqRunType::daq,
    daqSimple,
    endOfDaqTypeEnum,

    // crc
    crcTest=0x10*DaqRunType::crc,
    crcNoise,
    crcBeParameters,
    crcFeParameters,
    crcIntDac,
    crcIntDacScan,
    crcExtDac,
    crcExtDacScan,
    crcFakeEvent,

    // trg
    trgTest=0x10*DaqRunType::trg,
    trgReadout,
    trgParameters,
    trgNoise,
    trgSpill,

    // emc
    emcTest=0x10*DaqRunType::emc,
    emcNoise,
    emcFeParameters,
    emcVfeDac,
    emcVfeDacScan,
    emcVfeHoldScan,
    emcTrgTiming,
    emcTrgTimingScan,
    emcBeam,
    emcBeamHoldScan,
    emcCosmics,
    emcCosmicsHoldScan,

    // ahc
    ahcTest=0x10*DaqRunType::ahc,
    ahcDacScan,
    ahcCmNoise,
    ahcPmNoise,
    ahcAnalogOut,
    ahcCmAsic,
    ahcCmAsicVcalibScan,
    ahcCmAsicHoldScan,
    ahcPmAsic,
    ahcPmAsicVcalibScan,
    ahcPmAsicHoldScan,
    ahcCmLed,
    ahcCmLedVcalibScan,
    ahcCmLedHoldScan,
    ahcPmLed,
    ahcPmLedVcalibScan,
    ahcPmLedHoldScan,
    ahcScintillatorHoldScan,
    ahcBeam,
    ahcBeamHoldScan,
    ahcBeamStage,
    ahcBeamStageScan,
    ahcCosmics,
    ahcCosmicsHoldScan,
    ahcExpert,
    ahcGain,

    // dhc
    dhcTest=0x10*DaqRunType::dhc,
    dhcNoise,
    dhcBeam,

    // tcm
    tcmTest=0x10*DaqRunType::tcm,
    tcmNoise,
    tcmBeam,
    tcmBeamHoldScan,

    // bml
    bmlTest=0x10*DaqRunType::bml,
    bmlNoise,
    bmlInternalTest,

    // slow
    slowTest=0x10*DaqRunType::slow,
    slowMonitor,

    // beam
    beamTest=0x10*DaqRunType::beam,
    beamNoise,
    beamData,
    beamHoldScan,
    beamStage,
    beamStageScan,

    // cosmics
    cosmicsTest=0x10*DaqRunType::cosmics,
    cosmicsNoise,
    cosmicsData,
    cosmicsHoldScan,

    endOfTypeEnum
  };


  DaqSequenceType();
  DaqSequenceType(Type t, unsigned char m=0, unsigned char v=0);
  DaqSequenceType(std::string s, unsigned char m=0, unsigned char v=0);

  Type type() const;
  void type(Type s);

  DaqRunType::MajorType majorType() const;

  std::string        typeName() const;
  static std::string typeName(Type t);

  std::string        majorTypeName() const;
  static std::string majorTypeName(DaqRunType::MajorType t);

  bool        knownType() const;
  static bool knownType(Type t);

  static Type typeNumber(std::string s);

  unsigned char printLevel() const;
  void          printLevel(unsigned char m);

  unsigned char switches() const;
  void          switches(unsigned char m);

  bool bufferRun() const;
  void bufferRun(bool b);

  bool spillRun() const;
  void spillRun(bool b);

  bool transferRun() const;
  void transferRun(bool b);

  bool histogramRun() const;
  void histogramRun(bool b);

  bool ascWriteRun() const;
  void ascWriteRun(bool b);

  bool writeRun() const;
  void writeRun(bool b);

  unsigned char version() const;
  void          version(unsigned char v);

  unsigned char        defaultVersion() const;
  static unsigned char defaultVersion(Type t);

  UtlPack data() const;
  void    data(UtlPack n);

  std::ostream& print(std::ostream &o, std::string s="") const;


private:
  static const std::string _typeName[endOfTypeEnum];
  static const unsigned char _defaultVersion[endOfTypeEnum];

  // Byte 0 = version number
  // Byte 1 = bit switches (bits 8-10, 13-15)
  // Byte 2 = print level
  // Byte 3 = type (major type = bits 28-31)
  UtlPack _data;
};


#ifdef CALICE_DAQ_ICC


DaqSequenceType::DaqSequenceType() : _data(0) {
}

DaqSequenceType::DaqSequenceType(Type t, unsigned char m, unsigned char v) :
  _data(0) {
  type(t);
  switches(m);
  version(v);
}

DaqSequenceType::DaqSequenceType(std::string s, unsigned char m, unsigned char v) :
  _data(0) {
  type(typeNumber(s));
  switches(m);
  version(v);
}

DaqSequenceType::Type DaqSequenceType::type() const {
  return (Type)_data.byte(3);
}

void DaqSequenceType::type(Type n) {
  _data.byte(3,(unsigned char)n);
  _data.byte(0,defaultVersion(n));
}

DaqRunType::MajorType DaqSequenceType::majorType() const {
  DaqRunType::MajorType m((DaqRunType::MajorType)_data.halfByte(7));
  if(m==DaqRunType::ahc1) m=DaqRunType::ahc; // Catch second range of AHCAL
  return m;
}

std::string DaqSequenceType::typeName() const {
  return typeName(type());
}
 
std::string DaqSequenceType::typeName(Type t) {
  if(t<endOfTypeEnum) return _typeName[t];
  return "unknown";
}

std::string DaqSequenceType::majorTypeName() const {
  return DaqRunType::majorTypeName(majorType());
}
 
bool DaqSequenceType::knownType() const {
  return knownType(type());
}

bool DaqSequenceType::knownType(Type t) {
  return typeName(t)!="unknown";
}

DaqSequenceType::Type DaqSequenceType::typeNumber(std::string s) {
  for(unsigned t(0);t<endOfTypeEnum;t++) {
    if(s==typeName((Type)t)) return (Type)t;
  }
  return (Type)255;
}

unsigned char DaqSequenceType::printLevel() const {
  return _data.byte(2);
}

void DaqSequenceType::printLevel(unsigned char m) {
  _data.byte(2,m);
}

unsigned char DaqSequenceType::switches() const {
  return _data.byte(1);
}

void DaqSequenceType::switches(unsigned char m) {
  _data.byte(1,m);
}

bool DaqSequenceType::bufferRun() const {
  return _data.bit(8);
}

void DaqSequenceType::bufferRun(bool b) {
  return _data.bit(8,b);
}

bool DaqSequenceType::spillRun() const {
  return _data.bit(9);
}

void DaqSequenceType::spillRun(bool b) {
  return _data.bit(9,b);
}

bool DaqSequenceType::transferRun() const {
  return _data.bit(10);
}

void DaqSequenceType::transferRun(bool b) {
  return _data.bit(10,b);
}

bool DaqSequenceType::histogramRun() const {
  return _data.bit(13);
}

void DaqSequenceType::histogramRun(bool b) {
  return _data.bit(13,b);
}

bool DaqSequenceType::ascWriteRun() const {
  return _data.bit(14);
}

void DaqSequenceType::ascWriteRun(bool b) {
  return _data.bit(14,b);
}

bool DaqSequenceType::writeRun() const {
  return _data.bit(15);
}

void DaqSequenceType::writeRun(bool b) {
  return _data.bit(15,b);
}

unsigned char DaqSequenceType::version() const {
  return _data.byte(0);
}

void DaqSequenceType::version(unsigned char v) {
  _data.byte(0,v);
}

unsigned char DaqSequenceType::defaultVersion() const {
  return defaultVersion(type());
}
 
unsigned char DaqSequenceType::defaultVersion(Type t) {
  if(t<endOfTypeEnum) return _defaultVersion[t];
  return 0;
}

UtlPack DaqSequenceType::data() const {
  return _data;
}
 
void DaqSequenceType::data(UtlPack d) {
  _data=d;
}

std::ostream& DaqSequenceType::print(std::ostream &o, std::string s) const {
  o << s << "DaqSequenceType::print()" << std::endl;
  o << s << " Data = " << printHex(_data) << std::endl;
  o << s << "  Type    = " << std::setw(3) << type()
    << " = " << typeName();
  o << ", Major type = " << std::setw(3) << majorType()
    << " = " << majorTypeName() << std::endl;
  o << s << "  Version = " << std::setw(5) << (unsigned)version()
    << " (default = " << std::setw(5) << (unsigned)defaultVersion() << ")";
  o << ", Print level = " << std::setw(3) << (unsigned)printLevel() << std::endl;

  o << s << "  Switches  = " << printHex(switches()) << std::endl;

  if(majorType()!=DaqRunType::slow) {
    //o << s << "   Data run" << std::endl;
    if(bufferRun()) {
      o << s << "   Buffering data run" << std::endl;
      if(spillRun())    o << s << "   Multi-event spill run" << std::endl;
      else              o << s << "   Single-event spill run" << std::endl;
      if(transferRun()) o << s << "   Multi-event transfer run" << std::endl;
      else              o << s << "   Single-event transfer run" << std::endl;
    } else {
      o << s << "   Single event data run" << std::endl;
    }
  } else {
    o << s << "   Slow monitoring run" << std::endl;
  }

  if(writeRun()) {
    //o << s << "   Write run" << std::endl;
    if(ascWriteRun()) o << s << "   Ascii write run" << std::endl;
    else              o << s << "   Binary write run" << std::endl;
  } else {
    o << s << "   Dummy write run" << std::endl;
  }

  if(histogramRun()) o << s << "   Histogram filling enabled" << std::endl;
  else               o << s << "   Histogram filling disabled" << std::endl;

  return o;
}

const std::string DaqSequenceType::_typeName[]={
  "daqTest",
  "daqSimple",
  "unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "crcTest",
  "crcNoise",
  "crcBeParameters",
  "crcFeParameters",
  "crcIntDac",
  "crcIntDacScan",
  "crcExtDac",
  "crcExtDacScan",
  "crcFakeEvent",
  "unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "trgTest",
  "trgReadout",
  "trgParameters",
  "trgNoise",
  "trgSpill",
  "unknown",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",
  
  "emcTest",
  "emcNoise",
  "emcFeParameters",
  "emcVfeDac",
  "emcVfeDacScan",
  "emcVfeHoldScan",
  "emcTrgTiming",
  "emcTrgTimingScan",
  "emcBeam",
  "emcBeamHoldScan",
  "emcCosmics",
  "emcCosmicsHoldScan",
  "unknown","unknown","unknown","unknown",

  "ahcTest",
  "ahcDacScan",
  "ahcCmNoise",
  "ahcPmNoise",
  "ahcAnalogOut",
  "ahcCmAsic",
  "ahcCmAsicVcalibScan",
  "ahcCmAsicHoldScan",
  "ahcPmAsic",
  "ahcPmAsicVcalibScan",
  "ahcPmAsicHoldScan",
  "ahcCmLed",
  "ahcCmLedVcalibScan",
  "ahcCmLedHoldScan",
  "ahcPmLed",
  "ahcPmLedVcalibScan",

  "ahcPmLedHoldScan",
  "ahcScintillatorHoldScan",
  "ahcBeam",
  "ahcBeamHoldScan",
  "ahcBeamStage",
  "ahcBeamStageScan",
  "ahcCosmics",
  "ahcCosmicsHoldScan",
  "ahcExpert",
  "ahcGain",
  "unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "dhcTest",
  "dhcNoise",
  "dhcBeam",
  "unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "tcmTest",
  "tcmNoise",
  "tcmBeam",
  "tcmBeamHoldScan",
  "unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "bmlTest",
  "bmlNoise",
  "bmlInternalTest",
  "unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "slowTest",
  "slowMonitor",
  "unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "beamTest",
  "beamNoise",
  "beamData",
  "beamHoldScan",
  "beamStage",
  "beamStageScan",
  "unknown","unknown","unknown","unknown","unknown",
  "unknown","unknown","unknown","unknown","unknown",

  "cosmicsTest",
  "cosmicsNoise",
  "cosmicsData",
  "cosmicsHoldScan"
};

const unsigned char DaqSequenceType::_defaultVersion[]={
  // daq
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // crc
    0,  5,  4,  2, 16, 63, 32, 63,  0,  0,  0,  0,  0,  0,  0,  0,
  // trg
    0, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // emc
    0,  0,  0,  4, 31, 31,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // ahc
    0,  0,  5,  5,  1, 32, 10,255, 32, 10, 63, 38, 30, 30, 50, 30,
   65,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // dhc
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // tcm
    0,  0, 13, 13,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // bml
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // slow
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // beam
    0,  0, 13, 13, 13, 13,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // cosmics
    0,  0, 13, 13
};

#endif
#endif
