#ifndef CrcVlinkTrailer_HH
#define CrcVlinkTrailer_HH

#include <string>
#include <iostream>

#include "UtlPack.hh"


class CrcVlinkTrailer {

public:
  CrcVlinkTrailer();

  unsigned char eoe() const;
  unsigned char reservedUpper() const;
  unsigned eventLength() const;
  unsigned short crCode() const;
  unsigned char reservedMiddle() const;
  unsigned char fragmentStatus() const;
  unsigned char tts() const;
  bool lastTrailer() const;
  unsigned char reservedLower() const;

  bool verify() const;

  void data(unsigned m, unsigned l);

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


private:
  UtlPack _data[2];
};

#ifdef CALICE_DAQ_ICC

CrcVlinkTrailer::CrcVlinkTrailer() {
}

unsigned char CrcVlinkTrailer::eoe() const {
  return _data[0].halfByte(7);
}

unsigned char CrcVlinkTrailer::reservedUpper() const {
  return _data[0].halfByte(6);
}

unsigned CrcVlinkTrailer::eventLength() const {
  return _data[0].word()&0xffffff;
}

unsigned short CrcVlinkTrailer::crCode() const {
  return _data[1].halfWord(1);
}

unsigned char CrcVlinkTrailer::reservedMiddle() const {
  return _data[1].halfByte(3);
}

unsigned char CrcVlinkTrailer::fragmentStatus() const {
  return _data[1].halfByte(2);
}

unsigned char CrcVlinkTrailer::tts() const {
  return _data[1].halfByte(1);
}

bool CrcVlinkTrailer::lastTrailer() const {
  return !_data[1].bit(3);
}

unsigned char CrcVlinkTrailer::reservedLower() const {
  return _data[1].halfByte(0)&0x7;
}

void CrcVlinkTrailer::data(unsigned m, unsigned l) {
  _data[0].word(m);
  _data[1].word(l);
}

bool CrcVlinkTrailer::verify() const {
  return eoe()==0x0a && reservedUpper()==0 && reservedMiddle()==0 &&
    fragmentStatus()==0 && tts()==0 && !lastTrailer() && reservedLower()==0;
}

std::ostream& CrcVlinkTrailer::print(std::ostream &o, std::string s) const {
  o << s << "CrcVlinkTrailer::print()" << std::endl;
  o << s << " MS bytes = " << printHex(_data[0].word()) << std::endl;
  o << s << "  EoE label       = " << printHex(eoe()) << std::endl;
  o << s << "  Reserved bits   = " << printHex(reservedUpper()) << std::endl;
  o << s << "  Event length    = " << eventLength() << " long words" << std::endl;
  o << s << " LS bytes = " << printHex(_data[1].word()) << std::endl;
  o << s << "  CR code         = " << printHex(crCode()) << std::endl;
  o << s << "  Reserved bits   = " << printHex(reservedMiddle()) << std::endl;
  o << s << "  Fragment status = " << printHex(fragmentStatus()) << std::endl;
  o << s << "  TTS bits        = " << printHex(tts()) << std::endl;
  if(lastTrailer()) o << s << "  Last trailer" << std::endl;
  else              o << s << "  Trailer following" << std::endl;
  o << s << "  Reserved bits   = " << printHex(reservedLower()) << std::endl;

  return o;
}

#endif
#endif
