#ifndef MpsUsbDaqBunchTrainDatum_HH
#define MpsUsbDaqBunchTrainDatum_HH

#include <iostream>
#include <fstream>

#include "UtlPack.hh"


class MpsUsbDaqBunchTrainDatum {

public:
  MpsUsbDaqBunchTrainDatum();
  MpsUsbDaqBunchTrainDatum(unsigned d);

  bool channel(unsigned c) const;
  void channel(unsigned c, bool b);

  unsigned short channels() const;
  void           channels(unsigned short c);

  unsigned timeStamp() const;
  void     timeStamp(unsigned t);
  unsigned short fullTimeStampGray() const;
  void           fullTimeStampGray(unsigned short t);
  unsigned short fullTimeStamp() const;
  void           fullTimeStamp(unsigned short t);

  void datum(unsigned d);

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


private:
  unsigned grayToBinary(unsigned g) const;
  unsigned binaryToGray(unsigned b) const;

  UtlPack _datum;
};


#ifdef CALICE_DAQ_ICC

#include <cstring>

#include "UtlPrintHex.hh"


MpsUsbDaqBunchTrainDatum::MpsUsbDaqBunchTrainDatum() {
}

MpsUsbDaqBunchTrainDatum::MpsUsbDaqBunchTrainDatum(unsigned d) : _datum(d) {
}

bool MpsUsbDaqBunchTrainDatum::channel(unsigned c) const {
  assert(c<16);
  return _datum.bit(c+16);
}

void MpsUsbDaqBunchTrainDatum::channel(unsigned c, bool b) {
  assert(c<16);
  _datum.bit(c+16,b);
}

unsigned short MpsUsbDaqBunchTrainDatum::channels() const {
  return _datum.halfWord(1);
}

void MpsUsbDaqBunchTrainDatum::channels(unsigned short c) {
  return _datum.halfWord(1,c);
}

unsigned short MpsUsbDaqBunchTrainDatum::fullTimeStampGray() const {
  return _datum.halfWord(0);
}

void MpsUsbDaqBunchTrainDatum::fullTimeStampGray(unsigned short t) {
  _datum.halfWord(0,t);
}

unsigned short MpsUsbDaqBunchTrainDatum::fullTimeStamp() const {
  return grayToBinary(fullTimeStampGray());
}

void MpsUsbDaqBunchTrainDatum::fullTimeStamp(unsigned short t) {
  fullTimeStampGray(binaryToGray(t));
}

unsigned MpsUsbDaqBunchTrainDatum::timeStamp() const {
  return fullTimeStamp()/8;
}

void MpsUsbDaqBunchTrainDatum::timeStamp(unsigned t) {
  assert(t<8192);
  fullTimeStamp(8*t);
}

void MpsUsbDaqBunchTrainDatum::datum(unsigned d) {
  _datum.word(d);
}

unsigned MpsUsbDaqBunchTrainDatum::grayToBinary(unsigned g) const {
  g^=(g>>16);
  g^=(g>> 8);
  g^=(g>> 4);
  g^=(g>> 2);
  g^=(g>> 1);
  return g;
}

unsigned MpsUsbDaqBunchTrainDatum::binaryToGray(unsigned b) const {
  unsigned g((b>>1)^b);
  return g;
}

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

  o << s << " Datum = " << printHex(_datum.word()) << std::endl;
  o << s << "  Channels = " << printHex(channels())
    << std::endl;
  o << s << "  Full timestamp in graycode = " << fullTimeStampGray()
    << ", in binary = " << fullTimeStamp()
    << ",  timestamp = " << timeStamp() << std::endl;

  return o;
}

#endif
#endif
