#ifndef BmlLc1176EventData_HH
#define BmlLc1176EventData_HH

#include <string>
#include <iostream>

#include "BmlLc1176Csr.hh"
#include "BmlLc1176EventDatum.hh"

class BmlLc1176EventData {

public:
  enum {
    versionNumber=0
  };

  enum {
    maxLength=256,
    maxWordLength=maxLength+1
  };

  BmlLc1176EventData();

  BmlLc1176Csr csr() const;
  void         csr(BmlLc1176Csr c);

  unsigned numberOfWords() const;
  void     numberOfWords(unsigned n);

  unsigned bufferNumber() const;
  void     bufferNumber(unsigned n);

  const unsigned* data() const;
  unsigned*       data();

  unsigned channel(unsigned n) const;
  bool leadingEdge(unsigned n) const;
  unsigned short time(unsigned n) const;

  std::vector<const BmlLc1176EventDatum*> channelData(unsigned c, bool l=true) const;

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


private:
  BmlLc1176Csr _csr;
  UtlPack _numbers;
};

#ifdef CALICE_DAQ_ICC

#include <cstring>

#include "UtlPack.hh"
#include "UtlPrintHex.hh"
#include "BmlLc1176EventDatum.hh"


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

BmlLc1176Csr BmlLc1176EventData::csr() const {
  return _csr;
}

void BmlLc1176EventData::csr(BmlLc1176Csr c) {
  _csr=c;
}

unsigned BmlLc1176EventData::numberOfWords() const {
  return _numbers.halfWord(0);
}

void BmlLc1176EventData::numberOfWords(unsigned n) {
  assert(n<=maxLength);
  _numbers.halfWord(0,n);
}

unsigned BmlLc1176EventData::bufferNumber() const {
  return _numbers.halfWord(1);
}

void BmlLc1176EventData::bufferNumber(unsigned n) {
  assert(n<32);
  _numbers.halfWord(1,n);
}

const unsigned* BmlLc1176EventData::data() const {
  return (const unsigned*)(this+1);
}

unsigned* BmlLc1176EventData::data() {
  return (unsigned*)(this+1);
}

unsigned BmlLc1176EventData::channel(unsigned n) const {
  assert(n<numberOfWords());
  const UtlPack *p(&_numbers+1);
  return (p[n].byte(2)>>1)&0xf;
}

bool BmlLc1176EventData::leadingEdge(unsigned n) const {
  assert(n<numberOfWords());
  const UtlPack *p(&_numbers+1);
  return p[n].bit(16);
}

unsigned short BmlLc1176EventData::time(unsigned n) const {
  assert(n<numberOfWords());
  const UtlPack *p(&_numbers+1);
  return p[n].halfWord(0);
}

std::vector<const BmlLc1176EventDatum*> BmlLc1176EventData::channelData(unsigned c, bool l) const {
  std::vector<const BmlLc1176EventDatum*> v;

  const BmlLc1176EventDatum *p((const BmlLc1176EventDatum*)data());
  for(unsigned i(0);i<numberOfWords();i++) {
    if(p[i].leadingEdge()==l && p[i].channelNumber()==c) v.push_back(p+i);
  }

  return v;
}

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

  _csr.print(o,s+" ");

  o << s << " Number of words = " << numberOfWords() << std::endl;
  o << s << " Buffer number    = " << bufferNumber() << std::endl;
  
  //const unsigned *p(data());
  const BmlLc1176EventDatum *p((const BmlLc1176EventDatum*)data());

  for(unsigned i(0);i<numberOfWords();i++) {
    o << s << "   Word " << std::setw(4) << i << std::endl;// << " = " << printHex(p[i]) << std::endl;

    /*
    UtlPack pack(p[i]);
    //o << s << "    Channel " << std::setw(2) << ((p[i]>>17)&0x1f);
    o << s << "    Channel " << std::setw(2) << ((p[i]>>17)&0xf); // I think this is correct
    if(pack.bit(16)) o << ", leading";
    else             o << ", falling";
    o << ", time = " << std::setw(5) << pack.halfWord(0);
    if(!pack.bit(23)) o << ", last word";
    if(pack.bit(21)) o << ", INVALID!!!";
    o << std::endl;
    */
    p[i].print(o,s+" ");
  }
  
  return o;
}

#endif
#endif
