#ifndef CrcAdm1025ConfigurationData_HH
#define CrcAdm1025ConfigurationData_HH

#include <string>
#include <iostream>

#include "CrcAdm1025Voltages.hh"


class CrcAdm1025ConfigurationData {

public:
  enum {
    versionNumber=0
  };

  CrcAdm1025ConfigurationData();

  char localHighLimit() const;
  void localHighLimit(char n);
  
  char localLowLimit() const;
  void localLowLimit(char n);
  
  char remoteHighLimit() const;
  void remoteHighLimit(char n);

  char remoteLowLimit() const;
  void remoteLowLimit(char n);

  unsigned char configuration() const;
  void          configuration(unsigned char n);
  
  unsigned char vid() const;
  void          vid(unsigned char n);
  
  unsigned char test() const;
  void          test(unsigned char n);
  
  unsigned char offset() const;
  void          offset(unsigned char n);

  CrcAdm1025Voltages voltageHighLimits() const;
  void               voltageHighLimits(CrcAdm1025Voltages v);

  CrcAdm1025Voltages voltageLowLimits() const;
  void               voltageLowLimits(CrcAdm1025Voltages v);
  
  std::ostream& print(std::ostream &o, std::string s="") const;
  
private:
  unsigned _general;
  CrcAdm1025Voltages _voltages[2];
  unsigned _temperatures;
};

#ifdef CALICE_DAQ_ICC

#include <cstring>

#include "UtlPrintHex.hh"

CrcAdm1025ConfigurationData::CrcAdm1025ConfigurationData() {
  memset(this,0,sizeof(CrcAdm1025ConfigurationData));
  configuration(0x01);
  offset(0x01);
  remoteHighLimit(0x7f);
  remoteLowLimit(0x80);
  localHighLimit(0x7e);
  localLowLimit(0x81);
  _voltages[0].maximum();
  _voltages[1].minimum();
}

char CrcAdm1025ConfigurationData::localHighLimit() const {
  return (_temperatures&0xff000000)>>24;
}

void CrcAdm1025ConfigurationData::localHighLimit(char n) {
  _temperatures&=0x00ffffff;
  _temperatures|=((n&0xff)<<24);
}

char CrcAdm1025ConfigurationData::localLowLimit() const {
  return (_temperatures&0x00ff0000)>>16;
}

void CrcAdm1025ConfigurationData::localLowLimit(char n) {
  _temperatures&=0xff00ffff;
  _temperatures|=((n&0xff)<<16);
}

char CrcAdm1025ConfigurationData::remoteHighLimit() const {
  return (_temperatures&0x0000ff00)>>8;
}

void CrcAdm1025ConfigurationData::remoteHighLimit(char n) {
  _temperatures&=0xffff00ff;
  _temperatures|=((n&0xff)<<8);
}

char CrcAdm1025ConfigurationData::remoteLowLimit() const {
  return _temperatures&0x000000ff;
}

void CrcAdm1025ConfigurationData::remoteLowLimit(char n) {
  _temperatures&=0xffffff00;
  _temperatures|=n&0xff;
}

unsigned char CrcAdm1025ConfigurationData::configuration() const {
  return (_general&0xff000000)>>24;
}

void CrcAdm1025ConfigurationData::configuration(unsigned char n) {
  _general&=0x00ffffff;
  _general|=(n&0xff)<<24;
}

unsigned char CrcAdm1025ConfigurationData::vid() const {
  return (_general&0x00ff0000)>>16;
}

void CrcAdm1025ConfigurationData::vid(unsigned char n) {
  _general&=0xff00ffff;
  _general|=(n&0xff)<<16;
}
  
unsigned char CrcAdm1025ConfigurationData::test() const {
  return (_general&0x0000ff00)>>8;
}

void CrcAdm1025ConfigurationData::test(unsigned char n) {
  _general&=0xffff00ff;
  _general|=(n&0xff)<<8;
}

unsigned char CrcAdm1025ConfigurationData::offset() const {
  return _general&0x000000ff;
}

void CrcAdm1025ConfigurationData::offset(unsigned char n) {
  _general&=0xffffff00;
  _general|=n&0xff;
}

CrcAdm1025Voltages CrcAdm1025ConfigurationData::voltageHighLimits() const {
  return _voltages[0];
}

void CrcAdm1025ConfigurationData::voltageHighLimits(CrcAdm1025Voltages v) {
  _voltages[0]=v;
}

CrcAdm1025Voltages CrcAdm1025ConfigurationData::voltageLowLimits() const {
  return _voltages[1];
}

void CrcAdm1025ConfigurationData::voltageLowLimits(CrcAdm1025Voltages v) {
  _voltages[1]=v;
}

std::ostream& CrcAdm1025ConfigurationData::print(std::ostream &o, std::string s) const {
  o << s << "CrcAdm1025ConfigurationData::print()" << std::endl;
  o << s << " Configuration   " << printHex(configuration()) << std::endl;
  o << s << " VID register    " << printHex(vid()) << std::endl;
  o << s << " Test register   " << printHex(test()) << std::endl;
  o << s << " Offset register " << printHex(offset()) << std::endl;
  o << s << " Local temperature high limit  " << std::setw(4) << (int)localHighLimit() << " C" << std::endl;
  o << s << " Local temperature low limit   " << std::setw(4) << (int)localLowLimit() << " C" << std::endl;
  o << s << " Remote temperature high limit " << std::setw(4) << (int)remoteHighLimit() << " C" << std::endl;
  o << s << " Remote temperature low limit  " << std::setw(4) << (int)remoteLowLimit() << " C" << std::endl;
  o << s << " Voltage high limits ";
  voltageHighLimits().print(o,s+" ");
  o << s << " Voltage low limits ";
  voltageLowLimits().print(o,s+" ");
  return o;
}
  
#endif
#endif
