#ifndef CrcAdm1025Voltages_HH
#define CrcAdm1025Voltages_HH

#include <string>
#include <iostream>


class CrcAdm1025Voltages {

public:
  enum Voltage {
    v25,vccp,v33,v50,v120,vcc,
    endOfVoltageEnum
  };
  
  CrcAdm1025Voltages();
  
  unsigned char voltage(Voltage v) const;
  void voltage(Voltage v, unsigned char c);
  
  double dVoltage(Voltage v) const;
  void dVoltage(Voltage v, double d);
  
  void nominal();
  void maximum();
  void minimum();

  std::ostream& print(std::ostream &o, std::string s="") const;
  
  
private:
  unsigned _voltages[2];
  static const double _nominal[6];
};

#ifdef CALICE_DAQ_ICC

#include <cstring>
#include "UtlPrintHex.hh"


CrcAdm1025Voltages::CrcAdm1025Voltages() {
  memset(this,0,sizeof(CrcAdm1025Voltages));
  nominal();
}
  
unsigned char CrcAdm1025Voltages::voltage(Voltage v) const {
  unsigned n((unsigned)v);
  return (_voltages[n/3]>>(8*(n%3)))&0xff;
}

void CrcAdm1025Voltages::voltage(Voltage v, unsigned char c) {
  unsigned n((unsigned)v);
  _voltages[n/3]&=~(0xff<<(8*(n%3)));
  _voltages[n/3]|=(c<<(8*(n%3)));
}

double CrcAdm1025Voltages::dVoltage(Voltage v) const {
  return _nominal[v]*(voltage(v)+0.5)/192.0;
}

void CrcAdm1025Voltages::dVoltage(Voltage v, double d) {
  int c(int(192.0*d/_nominal[v]));
  
  if(c<0) {
    voltage(v,0);
    return;
  }
  
  if(c>255) {
    voltage(v,255);
    return;
  }
  
  voltage(v,c);
}

void CrcAdm1025Voltages::nominal() {
  dVoltage(v25,_nominal[0]);
  dVoltage(vccp,_nominal[1]);
  dVoltage(v33,_nominal[2]);
  dVoltage(v50,_nominal[3]);
  dVoltage(v120,_nominal[4]);
  dVoltage(vcc,_nominal[5]);
}

void CrcAdm1025Voltages::maximum() {
  _voltages[0]=0x00ffffff;
  _voltages[1]=0x00ffffff;
}

void CrcAdm1025Voltages::minimum() {
  _voltages[0]=0;
  _voltages[1]=0;
}

std::ostream& CrcAdm1025Voltages::print(std::ostream &o, std::string s) const {
  o << s << "CrcAdm1025Voltages::print()" << std::endl;
  o << s << " 2.5V voltage " << std::setw(3) << (unsigned)voltage(v25)  << " = " << std::setw(6) << dVoltage(v25) << " V" << std::endl;
  o << s << " Vcpp voltage " << std::setw(3) << (unsigned)voltage(vccp) << " = " << dVoltage(vccp) << " V" << std::endl;
  o << s << " 3.3V voltage " << std::setw(3) << (unsigned)voltage(v33)  << " = " << dVoltage(v33) << " V" << std::endl;
  o << s << " 5.0V voltage " << std::setw(3) << (unsigned)voltage(v50)  << " = " << dVoltage(v50) << " V" << std::endl;
  o << s << " 12V  voltage " << std::setw(3) << (unsigned)voltage(v120) << " = " << dVoltage(v120) << " V" << std::endl;
  o << s << " Vcc  voltage " << std::setw(3) << (unsigned)voltage(vcc)  << " = " << dVoltage(vcc) << " V" << std::endl;
  return o;
}

const double CrcAdm1025Voltages::_nominal[]={2.5,2.249,3.3,5.0,12.0,3.3};

#endif
#endif
