#ifndef CrcBeConfigurationDataV1_HH
#define CrcBeConfigurationDataV1_HH

#include <string>
#include <iostream>

#include "UtlPack.hh"


class CrcBeConfigurationDataV1 {

public:
  enum {
    versionNumber=1
  };

  CrcBeConfigurationDataV1();

  unsigned char triggerSelect() const;
  void          triggerSelect(unsigned char n);

  unsigned char mode() const;
  void          mode(unsigned char n);

  unsigned char readoutControl() const;
  void          readoutControl(unsigned char n);

  unsigned char runControl() const;
  void          runControl(unsigned char n);

  unsigned char feDataEnable() const;
  void          feDataEnable(unsigned char n);

  unsigned short daqId() const;
  void           daqId(unsigned short n);

  unsigned char qdrAddress() const;
  void          qdrAddress(unsigned char n);

  unsigned char feTriggerEnable() const;
  void          feTriggerEnable(unsigned char n);

  bool j0TriggerEnable() const;
  void j0TriggerEnable(bool b);

  bool j0BypassEnable() const;
  void j0BypassEnable(bool b);

  bool trgDataFe0Enable() const;
  void trgDataFe0Enable(bool b);

  bool fastSyncEnable() const;
  void fastSyncEnable(bool b);

  unsigned trgEnables() const;
  void     trgEnables(unsigned n);

  unsigned short testLength() const;
  void           testLength(unsigned short n);

  unsigned test() const;
  void     test(unsigned n);

  unsigned char fePhase() const;
  void          fePhase(unsigned char n);

  unsigned short numberOfFeBytes() const;
  void           numberOfFeBytes(unsigned short n);

  bool operator!=(const CrcBeConfigurationDataV1 &c);
  bool operator==(const CrcBeConfigurationDataV1 &c);
 
  std::ostream& print(std::ostream &o, std::string s="") const;


private:
  UtlPack _control;
  UtlPack _enables;
  UtlPack _trgEnables;
  UtlPack _test;
};


#ifdef CALICE_DAQ_ICC

CrcBeConfigurationDataV1::CrcBeConfigurationDataV1() {
  _control=0x04020203;
  _enables=0xff000cec;
  _trgEnables=0x1ff;
  //_test=(512<<16);
  //_test=(1<<29)+(1<<28)+(512<<16);
  //_test=(2<<28)+(512<<16); // TCMT second run
  _test=(7<<4)+(512<<16);
  //_test=(6<<4)+(((2+64*7)*4)<<16); // TEMP FOR DHCALE
}

unsigned char CrcBeConfigurationDataV1::triggerSelect() const {
  return _control.byte(3);
}

void CrcBeConfigurationDataV1::triggerSelect(unsigned char n) {
  _control.byte(3,n);
}

unsigned char CrcBeConfigurationDataV1::mode() const {
  return _control.byte(2);
}

void CrcBeConfigurationDataV1::mode(unsigned char n) {
  _control.byte(2,n);
}

unsigned char CrcBeConfigurationDataV1::readoutControl() const {
  return _control.byte(1);
}

void CrcBeConfigurationDataV1::readoutControl(unsigned char n) {
  _control.byte(1,n);
}

unsigned char CrcBeConfigurationDataV1::runControl() const {
  return _control.byte(0);
}

void CrcBeConfigurationDataV1::runControl(unsigned char n) {
  _control.byte(0,n);
}

unsigned char CrcBeConfigurationDataV1::feDataEnable() const {
  return _enables.byte(3);
}

void CrcBeConfigurationDataV1::feDataEnable(unsigned char n) {
  _enables.byte(3,n);
}

unsigned short CrcBeConfigurationDataV1::daqId() const {
  return _enables.bits(0,11);
}

void CrcBeConfigurationDataV1::daqId(unsigned short n) {
  _enables.bits(0,11,n&0xfff);
}

unsigned char CrcBeConfigurationDataV1::qdrAddress() const {
  return _trgEnables.bits(10,11);
  //  return (_trgEnables>>10)&0x3;
}

void CrcBeConfigurationDataV1::qdrAddress(unsigned char n) {
  //_trgEnables&=0xfffff3ff;
  //_trgEnables|=(n&0x3)<<10;
  _trgEnables.bits(10,11,n);
}

unsigned char CrcBeConfigurationDataV1::feTriggerEnable() const {
  return _trgEnables.byte(0);
}

void CrcBeConfigurationDataV1::feTriggerEnable(unsigned char n) {
  _trgEnables.byte(0,n);
}

bool CrcBeConfigurationDataV1::j0TriggerEnable() const {
  return _trgEnables.bit(8);
}

void CrcBeConfigurationDataV1::j0TriggerEnable(bool b) {
  _trgEnables.bit(8,b);
}

bool CrcBeConfigurationDataV1::j0BypassEnable() const {
  return _trgEnables.bit(9);
}

void CrcBeConfigurationDataV1::j0BypassEnable(bool b) {
  _trgEnables.bit(9,b);
}

bool CrcBeConfigurationDataV1::trgDataFe0Enable() const {
  return _trgEnables.bit(12);
}

void CrcBeConfigurationDataV1::trgDataFe0Enable(bool b) {
  _trgEnables.bit(12,b);
}

bool CrcBeConfigurationDataV1::fastSyncEnable() const {
  return _trgEnables.bit(13);
}

void CrcBeConfigurationDataV1::fastSyncEnable(bool b) {
  _trgEnables.bit(13,b);
}

unsigned CrcBeConfigurationDataV1::trgEnables() const {
  return _trgEnables.word();
}

void CrcBeConfigurationDataV1::trgEnables(unsigned n) {
  _trgEnables.word(n);
}

unsigned short CrcBeConfigurationDataV1::testLength() const {
  //return (_testLength)&0xffff;
  return _trgEnables.halfWord(1);
}

void CrcBeConfigurationDataV1::testLength(unsigned short n) {
  //_testLength=n;
  _trgEnables.halfWord(1,n);
}

unsigned CrcBeConfigurationDataV1::test() const {
  return _test.word();
}

void CrcBeConfigurationDataV1::test(unsigned n) {
  _test=n;
}

unsigned char CrcBeConfigurationDataV1::fePhase() const {
  return _test.halfByte(1);
}

void CrcBeConfigurationDataV1::fePhase(unsigned char n) {
  _test.halfByte(1,n&0xf);
}

unsigned short CrcBeConfigurationDataV1::numberOfFeBytes() const {
  return _test.halfWord(1);
}

void CrcBeConfigurationDataV1::numberOfFeBytes(unsigned short n) {
  _test.halfWord(1,n);
}

bool CrcBeConfigurationDataV1::operator!=(const CrcBeConfigurationDataV1 &c) {
  if(_control!=c._control) return true;
  if(_enables.byte(3)!=c._enables.byte(3)) return true;
  if(_enables.bits(0,11)!=c._enables.bits(0,11)) return true;
  if(_trgEnables.halfWord(1)!=c._trgEnables.halfWord(1)) return true;
  if(_trgEnables.bits(0,13)!=c._trgEnables.bits(0,13)) return true;
  if(_test!=c._test) return true;
  return false;
}
 
bool CrcBeConfigurationDataV1::operator==(const CrcBeConfigurationDataV1 &c) {
  return !operator!=(c);
}

std::ostream& CrcBeConfigurationDataV1::print(std::ostream &o, std::string s) const {
  o << s << "CrcBeConfigurationDataV1::print()" << std::endl;

  o << s << " Control            = " << printHex(_control) << std::endl;
  o << s << "  Run control       = " << printHex(runControl()) << std::endl;
  o << s << "  Readout control   = " << printHex(readoutControl()) << std::endl;
  o << s << "  Mode              = " << printHex(mode()) << std::endl;
  o << s << "  Trigger select    = " << printHex(triggerSelect()) << std::endl;

  o << s << " Enables            = " << printHex(_enables) << std::endl;
  o << s << "  DAQ id            = " << printHex(daqId()) << std::endl;
  o << s << "  FE data enable    = " << printHex(feDataEnable()) << std::endl;

  o << s << " Trg enables        = " << printHex(_trgEnables) << std::endl;
  o << s << "  FE trigger enable = " << printHex(feTriggerEnable()) << std::endl;
  if(j0TriggerEnable())   o << s << "  J0 trigger enabled" << std::endl;
  else                    o << s << "  J0 trigger disabled" << std::endl;
  if(j0BypassEnable())    o << s << "  J0 bypass enabled" << std::endl;
  else                    o << s << "  J0 bypass disabled" << std::endl;
  if(trgDataFe0Enable())  o << s << "  Trg data into FE0 enabled" << std::endl;
  else                    o << s << "  Trg data into FE0 disabled" << std::endl;
  o << s << "  QDR address       = " << (unsigned)qdrAddress() << std::endl;
  o << s << "  Test length       = " << testLength() << std::endl;

  o << s << " Test               = " << printHex(_test) << std::endl;
  o << s << "  FE phase           = " << (unsigned)fePhase() << std::endl;
  o << s << "  Number of FE bytes = " << numberOfFeBytes() 
    << " = 4 * (2 + 7 * " << ((numberOfFeBytes()/4)-2)/7 << " )" << std::endl;
  return o;
}

#endif
#endif
