#ifndef EmcVfeControl_HH
#define EmcVfeControl_HH

#include <string>
#include <iostream>

#include "UtlPack.hh"

#include "CrcFeConfigurationData.hh"


class EmcVfeControl {

public:
  EmcVfeControl();
  EmcVfeControl(UtlPack v);
  EmcVfeControl(unsigned v);

  UtlPack data() const;
  void    data(UtlPack v);

  bool vfeEnable(CrcFeConfigurationData::Connector c, unsigned g) const;
  void vfeEnable(CrcFeConfigurationData::Connector c, unsigned g, bool e);

  bool vfeLowGain(CrcFeConfigurationData::Connector c) const;
  void vfeLowGain(CrcFeConfigurationData::Connector c, bool e);

  static unsigned vfeGroup(unsigned chip, unsigned chan);

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


private:
  static const unsigned _vfeGroup[36];
  UtlPack _data;
};


#ifdef CALICE_DAQ_ICC


EmcVfeControl::EmcVfeControl() : _data(0) {
  _data.bit(13,true);
  _data.bit(15,true);
}

EmcVfeControl::EmcVfeControl(UtlPack v) : _data(v) {
}

EmcVfeControl::EmcVfeControl(unsigned v) : _data(v) {
}

UtlPack EmcVfeControl::data() const {
  return _data;
}

void EmcVfeControl::data(UtlPack v) {
  _data=v;
}
                                                                                // VFE calibration group enables

bool EmcVfeControl::vfeEnable(CrcFeConfigurationData::Connector c, unsigned g) const {
  assert(g<6);
  if(c==CrcFeConfigurationData::bot) return _data.bit(g+6);
  else                               return _data.bit(g  );
}
 
void EmcVfeControl::vfeEnable(CrcFeConfigurationData::Connector c, unsigned g, bool e) {
  assert(g<6);
  if(c==CrcFeConfigurationData::bot) _data.bit(g+6,e);
  else                               _data.bit(g  ,e);
}
 
// VFE gains; x1 or x8

bool EmcVfeControl::vfeLowGain(CrcFeConfigurationData::Connector c) const {
  if(c==CrcFeConfigurationData::bot) return _data.bit(15);
  else                               return _data.bit(13);
}

void EmcVfeControl::vfeLowGain(CrcFeConfigurationData::Connector c, bool e) {
  if(c==CrcFeConfigurationData::bot) _data.bit(15,e);
  else                               _data.bit(13,e);
}

// VFE calibration group for a chip and channel

unsigned EmcVfeControl::vfeGroup(unsigned chip, unsigned chan) {
  assert(chip<12);
  assert(chan<18);
  return _vfeGroup[(18*chip+chan)%36];
}

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

  o << s << " VFE information = " << printHex(_data) << std::endl;

  for(unsigned i(0);i<2;i++) {
    CrcFeConfigurationData::Connector c((CrcFeConfigurationData::Connector)i);

    if(c==CrcFeConfigurationData::bot) o << s << "  Bot";
    else                           o << s << "  Top";
    o << " VFE enable groups; enabled ";    

    bool first(true);
    for(unsigned i(0);i<6;i++) {
      if(vfeEnable(c,i)) {
	if(first) o << i;
	else      o << ", " << i;
	first=false;
      }
    }
    if(first) o << "none";
    
    o << "; disabled ";
    first=true;
    for(unsigned i(0);i<6;i++) {
      if(!vfeEnable(c,i)) {
	if(first) o << i;
	else      o << ", " << i;
	first=false;
      }
    }
    if(first) o << "none";
    o << s << std::endl;
  }
  
  if(vfeLowGain(CrcFeConfigurationData::bot)) {
    o << s << "  Bot gain bit set = x1,";
  } else {
    o << s << "  Bot gain bit not set = x8,";
  }

  if(vfeLowGain(CrcFeConfigurationData::top)) {
    o <<       " Top gain bit set = x1" << std::endl;
  } else {
    o <<       " Top gain bit not set = x8" << std::endl;
  }

  return o;
}

std::string printHex(EmcVfeControl v, bool b=true) {
  return printHex(v.data(),b);
}

const unsigned EmcVfeControl::_vfeGroup[]={
  0,3,0,1,4,1,2,5,2,0,3,0,1,4,1,2,5,2,
  3,0,3,4,1,4,5,2,5,3,0,3,4,1,4,5,2,5
};

#endif
#endif
