#ifndef BmlCaen767EventDatum_HH
#define BmlCaen767EventDatum_HH

#include <iostream>
#include <fstream>

#include "UtlPack.hh"


class BmlCaen767EventDatum {

public:
  BmlCaen767EventDatum();

  enum Label {
    datum,
    eob,
    header,
    invalid
  };

  Label label() const;
  
  unsigned char geoAddress() const;

  unsigned short eventNumber() const;

  unsigned char channelNumber() const;

  bool startTime() const;

  bool leadingEdge() const;

  unsigned time() const;

  unsigned short eventDataCounter() const;

  unsigned char status() const;

  void setHeader(unsigned g, unsigned e);

  void setDatum(unsigned c, bool s, bool l, unsigned t);

  void setEob(unsigned g, unsigned s, unsigned e);

  void setInvalid();

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


private:
  UtlPack _datum;
};


#ifdef CALICE_DAQ_ICC

#include <cstring>

#include "UtlPrintHex.hh"


BmlCaen767EventDatum::BmlCaen767EventDatum() {
  memset(this,0,sizeof(BmlCaen767EventDatum));
}


BmlCaen767EventDatum::Label BmlCaen767EventDatum::label() const {
  return (Label)_datum.bits(21,22);
}

unsigned char BmlCaen767EventDatum::geoAddress() const {
  if(label()!=header && label()!=eob) return 0;
  return _datum.bits(27,31);
}

unsigned short BmlCaen767EventDatum::eventNumber() const {
  if(label()!=header) return 0;
  return _datum.bits(0,11);
}

unsigned char BmlCaen767EventDatum::channelNumber() const {
  if(label()!=datum) return 0;
  return _datum.bits(24,30);
}

bool BmlCaen767EventDatum::startTime() const {
  if(label()!=datum) return false;
  return _datum.bit(23);
}

bool BmlCaen767EventDatum::leadingEdge() const {
  if(label()!=datum) return false;
  return _datum.bit(20);
}

unsigned BmlCaen767EventDatum::time() const {
  if(label()!=datum) return 0;
  return _datum.bits(0,19);
}

unsigned short BmlCaen767EventDatum::eventDataCounter() const {
  if(label()!=eob) return 0;
  return _datum.halfWord(0);
}

unsigned char BmlCaen767EventDatum::status() const {
  if(label()!=eob) return 0;
  return _datum.bits(24,26);
}

void BmlCaen767EventDatum::setHeader(unsigned g, unsigned e) {
  _datum.word(0);
  _datum.bits(0,11,e);
  _datum.bits(21,22,header);
  _datum.bits(27,31,g);
}

void BmlCaen767EventDatum::setDatum(unsigned c, bool s, bool l, unsigned t) {
  _datum.word(0);
  _datum.bits(0,19,t);
  _datum.bit(20,l);
  _datum.bits(21,22,datum);  
  _datum.bit(23,s);
  _datum.bits(24,30,c);
}

void BmlCaen767EventDatum::setEob(unsigned g, unsigned s, unsigned e) {
  _datum.word(0);
  _datum.bits(0,15,e);
  _datum.bits(21,22,eob);
  _datum.bits(24,26,s);
  _datum.bits(27,31,g);
}

void BmlCaen767EventDatum::setInvalid() {
  _datum.word(0);
  _datum.bits(21,22,invalid);
}

std::ostream& BmlCaen767EventDatum::print(std::ostream &o, std::string s) const {
  o << s << "BmlCaen767EventDatum::print()" << std::endl;
  o << s << " Data word = " << printHex(_datum) << std::endl;
  
  // Header 
  if(label()==header) {
    o << s << "  Header:  Geo address = " << (unsigned)geoAddress()
      << ", event number = " << eventNumber() << std::endl;
  }
  
  // Data
  if(label()==datum) {
    o << s << "  Datum:   Channel number = " << std::setw(3)
      << (unsigned)channelNumber();
    if(startTime()) o << ", start time";
    if(leadingEdge()) o << ", leading";
    else              o << ", falling";
    o << ", time = " << time() << std::endl;
  }

  // EOB
  if(label()==eob) {
    o << s << "  EOB:     Geo address = " << (unsigned)geoAddress()
      << ", status = " << (unsigned)status()
      << ", event data counter = " << eventDataCounter() << std::endl;
  }
  
  // Invalid
  if(label()==invalid) {
    o << s << "  Invalid: No data" << std::endl;
  }
  return o;
}

#endif
#endif
