#ifndef BmlCaen767RunData_HH
#define BmlCaen767RunData_HH

#include <iostream>
#include <fstream>

#include "UtlPack.hh"


class BmlCaen767RunData {

public:
  enum {
    versionNumber=0
  };

  BmlCaen767RunData();

  unsigned char crRom(unsigned c) const;
  void          crRom(unsigned c, unsigned char r);

  UtlPack configurationRomId() const;
  UtlPack manufacturerId() const;
  UtlPack boardId() const;
  UtlPack revisionId() const;

  UtlPack serialNumber() const;
  void    serialNumber(unsigned h, unsigned char s);

  unsigned short addressDecoder() const;
  void           addressDecoder(unsigned h, unsigned char a);

  unsigned short mcstAddress() const;
  void           mcstAddress(unsigned short a);

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


private:
  UtlPack _crRom[16];
  /*
    UtlPack _baseAddress;
    UtlPack _configurationRomId;
    UtlPack _manufacturerId;
    UtlPack _boardId;
    UtlPack _revisionId;
  */
  UtlPack _serialNumber;
  UtlPack _addresses;
};


#ifdef CALICE_DAQ_ICC

#include <cstring>

#include "UtlPrintHex.hh"


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

unsigned char BmlCaen767RunData::crRom(unsigned c) const {
  assert(c<64);
  return _crRom[c/4].byte(c%4);
}

void BmlCaen767RunData::crRom(unsigned c, unsigned char r) {
  assert(c<64);
  _crRom[c/4].byte(c%4,r);
}

UtlPack BmlCaen767RunData::configurationRomId() const {
  UtlPack reply;
  reply.byte(0,_crRom[1].byte(3));
  reply.byte(1,_crRom[2].byte(0));
  return reply;
}

UtlPack BmlCaen767RunData::manufacturerId() const {
  UtlPack reply;
  reply.byte(0,_crRom[2].byte(3));
  reply.byte(1,_crRom[2].byte(2));
  reply.byte(2,_crRom[2].byte(1));
  return reply;
}

UtlPack BmlCaen767RunData::boardId() const {
  UtlPack reply;
  reply.byte(0,_crRom[3].byte(3));
  reply.byte(1,_crRom[3].byte(2));
  reply.byte(2,_crRom[3].byte(1));
  reply.byte(3,_crRom[3].byte(0));
  return reply;
}

UtlPack BmlCaen767RunData::revisionId() const {
  UtlPack reply;
  reply.byte(0,_crRom[4].byte(3));
  reply.byte(1,_crRom[4].byte(2));
  reply.byte(2,_crRom[4].byte(1));
  reply.byte(3,_crRom[4].byte(0));
  return reply;
}

UtlPack BmlCaen767RunData::serialNumber() const {
  UtlPack reply;
  reply.byte(0,_serialNumber.byte(3));
  reply.byte(1,_serialNumber.byte(2));
  reply.byte(2,_serialNumber.byte(1));
  reply.byte(3,_serialNumber.byte(0));
  return reply;
}

void BmlCaen767RunData::serialNumber(unsigned h, unsigned char c) {
  assert(h<4);
  _serialNumber.byte(h,c);
}

unsigned short BmlCaen767RunData::addressDecoder() const {
  return _addresses.halfWord(0);
}

void BmlCaen767RunData::addressDecoder(unsigned h, unsigned char a) {
  assert(h<2);
  _addresses.byte(h,a);
}

unsigned short BmlCaen767RunData::mcstAddress() const {
  return _addresses.halfWord(1);
}

void BmlCaen767RunData::mcstAddress(unsigned short a) {
  _addresses.halfWord(1,a);
}

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

  for(unsigned i(0);i<16;i++) {
    o << s << " CR ROM word " << std::setw(4) << i << " = " << printHex(_crRom[i]) << std::endl;
    if(i==1) {
      o << s << "  CR ROM Id       = " << printHex(configurationRomId()) << std::endl;
    }
    if(i==2) {
      o << s << "  Manufacturer Id = " << printHex(manufacturerId()) << std::endl;
    }
    if(i==3) {
      o << s << "  Board Id        = " << printHex(boardId()) << std::endl;
    }
    if(i==4) {
      o << s << "  Revision Id     = " << printHex(revisionId()) << std::endl;
    }
  }

  o << s << " Serial Number        = " << printHex(serialNumber()) << std::endl;

  o << s << " Addresses = " << printHex(_addresses) << std::endl;
  o << s << "  Address decoder = " << printHex(addressDecoder()) << std::endl;
  o << s << "  MCST address    = " << printHex(mcstAddress()) << std::endl;

  return o;
}

#endif
#endif
