#ifndef EmcStageRunData_HH
#define EmcStageRunData_HH

#include <string>
#include <iostream>

// dual/inc/utl
#include "UtlPack.hh"


class EmcStageRunData {

public:
  enum {
    versionNumber=0
  };

  EmcStageRunData();

  unsigned magicNumber() const;
  void magicNumber(unsigned char m);

  unsigned numberOfWords() const;
  void numberOfWords(unsigned char m);

  unsigned surveillanceCounter() const;
  void surveillanceCounter(unsigned char m);

  bool pcStatus() const;
  void pcStatus(bool e);

  bool setStatus() const;
  void setStatus(bool e);

  bool headerError() const;


  bool xIndexerStatus() const;
  void xIndexerStatus(bool e);

  unsigned xMotorStandby() const;
  void xMotorStandby(unsigned char z);

  unsigned xMotorCurrent() const;
  void xMotorCurrent(unsigned char z);

  unsigned xMajorRevision() const;
  void xMajorRevision(unsigned char z);

  unsigned xMinorRevision() const;
  void xMinorRevision(unsigned char z);

  unsigned xMotorResolution() const;
  void xMotorResolution(unsigned char z);

  unsigned xMotorVelocity() const;
  void xMotorVelocity(unsigned char z);

  unsigned xStandPosition() const;
  void xStandPosition(unsigned short z);

  int xBeamPosition() const;
  void xBeamPosition(int short z);


  bool yIndexerStatus() const;
  void yIndexerStatus(bool e);

  unsigned yMotorStandby() const;
  void yMotorStandby(unsigned char z);

  unsigned yMotorCurrent() const;
  void yMotorCurrent(unsigned char z);

  unsigned yMajorRevision() const;
  void yMajorRevision(unsigned char z);

  unsigned yMinorRevision() const;
  void yMinorRevision(unsigned char z);

  unsigned yMotorResolution() const;
  void yMotorResolution(unsigned char z);

  unsigned yMotorVelocity() const;
  void yMotorVelocity(unsigned char z);

  unsigned yStandPosition() const;
  void yStandPosition(unsigned short z);

  int yBeamPosition() const;
  void yBeamPosition(int short z);

  unsigned checksum() const;
  void checksum(unsigned c);
  bool validateChecksum() const;
  void setChecksum();

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


private:
  UtlPack _header;
  UtlPack _xStatus;
  UtlPack _xValue[3];
  UtlPack _yStatus;
  UtlPack _yValue[3];
  unsigned _checksum;
};


#ifdef CALICE_DAQ_ICC

EmcStageRunData::EmcStageRunData() {
}

unsigned EmcStageRunData::magicNumber() const {
  return _header.byte(3);
}

void EmcStageRunData::magicNumber(unsigned char m) {
  _header.byte(3,m);
}

unsigned EmcStageRunData::numberOfWords() const {
  return _header.byte(2);
}

void EmcStageRunData::numberOfWords(unsigned char m) {
  _header.byte(2,m);
}

unsigned EmcStageRunData::surveillanceCounter() const {
  return _header.byte(1);
}

void EmcStageRunData::surveillanceCounter(unsigned char m) {
  _header.byte(1,m);
}

bool EmcStageRunData::pcStatus() const {
  return _header.bit(0);
}

void EmcStageRunData::pcStatus(bool e) {
  _header.bit(0,e);
}

bool EmcStageRunData::setStatus() const {
  return _header.bit(1);
}

void EmcStageRunData::setStatus(bool e) {
  _header.bit(1,e);
}

bool EmcStageRunData::headerError() const {
  return _header.word()==0x5a5a5a5a;
}


bool EmcStageRunData::xIndexerStatus() const {
  return _xStatus.bit(0);
}

void EmcStageRunData::xIndexerStatus(bool e) {
  _xStatus.bit(0,e);
}

unsigned EmcStageRunData::xMotorStandby() const {
  return _xValue[0].byte(3);
}

void EmcStageRunData::xMotorStandby(unsigned char z) {
  _xValue[0].byte(3,z);
}

unsigned EmcStageRunData::xMotorCurrent() const {
  return _xValue[0].byte(2);
}

void EmcStageRunData::xMotorCurrent(unsigned char z) {
  _xValue[0].byte(2,z);
}

unsigned EmcStageRunData::xMajorRevision() const {
  return _xValue[0].byte(1);
}

void EmcStageRunData::xMajorRevision(unsigned char z) {
  _xValue[0].byte(1,z);
}

unsigned EmcStageRunData::xMinorRevision() const {
  return _xValue[0].byte(0);
}

void EmcStageRunData::xMinorRevision(unsigned char z) {
  _xValue[0].byte(0,z);
}

unsigned EmcStageRunData::xMotorResolution() const {
  return _xValue[1].byte(3);
}

void EmcStageRunData::xMotorResolution(unsigned char z) {
  _xValue[1].byte(3,z);
}

unsigned EmcStageRunData::xMotorVelocity() const {
  return _xValue[1].byte(2);
}

void EmcStageRunData::xMotorVelocity(unsigned char z) {
  _xValue[1].byte(2,z);
}

unsigned EmcStageRunData::xStandPosition() const {
  return _xValue[1].halfWord(0);
}

void EmcStageRunData::xStandPosition(unsigned short z) {
  _xValue[1].halfWord(0,z);
}

int EmcStageRunData::xBeamPosition() const {
  if(_xValue[2].bit(15)) return -(_xValue[2].halfWord(0)&0x7fff);
  else                   return  (_xValue[2].halfWord(0)&0x7fff);
}

void EmcStageRunData::xBeamPosition(int short z) {
  _xValue[2].halfWord(0,abs(z));
  if(z<0) _xValue[2].bit(15,true);
}

bool EmcStageRunData::yIndexerStatus() const {
  return _yStatus.bit(0);
}

void EmcStageRunData::yIndexerStatus(bool e) {
  _yStatus.bit(0,e);
}

unsigned EmcStageRunData::yMotorStandby() const {
  return _yValue[0].byte(3);
}

void EmcStageRunData::yMotorStandby(unsigned char z) {
  _yValue[0].byte(3,z);
}

unsigned EmcStageRunData::yMotorCurrent() const {
  return _yValue[0].byte(2);
}

void EmcStageRunData::yMotorCurrent(unsigned char z) {
  _yValue[0].byte(2,z);
}

unsigned EmcStageRunData::yMajorRevision() const {
  return _yValue[0].byte(1);
}

void EmcStageRunData::yMajorRevision(unsigned char z) {
  _yValue[0].byte(1,z);
}

unsigned EmcStageRunData::yMinorRevision() const {
  return _yValue[0].byte(0);
}

void EmcStageRunData::yMinorRevision(unsigned char z) {
  _yValue[0].byte(0,z);
}

unsigned EmcStageRunData::yMotorResolution() const {
  return _yValue[1].byte(3);
}

void EmcStageRunData::yMotorResolution(unsigned char z) {
  _yValue[1].byte(3,z);
}

unsigned EmcStageRunData::yMotorVelocity() const {
  return _yValue[1].byte(2);
}

void EmcStageRunData::yMotorVelocity(unsigned char z) {
  _yValue[1].byte(2,z);
}

unsigned EmcStageRunData::yStandPosition() const {
  return _yValue[1].halfWord(0);
}

void EmcStageRunData::yStandPosition(unsigned short z) {
  _yValue[1].halfWord(0,z);
}

int EmcStageRunData::yBeamPosition() const {
  if(_yValue[2].bit(15)) return -(_yValue[2].halfWord(0)&0x7fff);
  else                   return  (_yValue[2].halfWord(0)&0x7fff);
}

void EmcStageRunData::yBeamPosition(int short z) {
  _yValue[2].halfWord(0,abs(z));
  if(z<0) _yValue[2].bit(15,true);
}

unsigned EmcStageRunData::checksum() const {
  return _checksum;
}

void EmcStageRunData::checksum(unsigned c) {
  _checksum=c;
}

bool EmcStageRunData::validateChecksum() const {
  unsigned sum(0);
  sum+=_header.word();
  sum+=_xStatus.word();
  sum+=_xValue[0].word();
  sum+=_xValue[1].word();
  sum+=_xValue[2].word();
  sum+=_yStatus.word();
  sum+=_yValue[0].word();
  sum+=_yValue[1].word();
  sum+=_yValue[2].word();
  return sum==_checksum;
}

void EmcStageRunData::setChecksum() {
  unsigned sum(0);
  sum+=_header.word();
  sum+=_xStatus.word();
  sum+=_xValue[0].word();
  sum+=_xValue[1].word();
  sum+=_xValue[2].word();
  sum+=_yStatus.word();
  sum+=_yValue[0].word();
  sum+=_yValue[1].word();
  sum+=_yValue[2].word();
  _checksum=sum;
}

std::ostream& EmcStageRunData::print(std::ostream &o, std::string s) const {
  o << s << "EmcStageRunData::print()" << std::endl;
  
  o << s << " Header    = " << printHex(_header.word()) << std::endl;
  o << s << "  Magic number = " << printHex((unsigned char)magicNumber())
    << std::endl;
  o << s << "  Number of words = " << numberOfWords() << std::endl;
  o << s << "  Surveillance counter = " << surveillanceCounter()
    << std::endl;
  if(pcStatus()) o << s << "  PC status OK" << std::endl;
  else           o << s << "  PC status not OK" << std::endl;
  if(setStatus()) o << s << "  Set status OK" << std::endl;
  else            o << s << "  Set status not OK" << std::endl;
  o << s << "  Unused bits = "
    << printHex((unsigned char)(_header.halfWord(0)&0xfc)) << std::endl;
  
  o << s << " X status  = " << printHex(_xStatus.word()) << std::endl;
  if(xIndexerStatus()) o << s << "  X indexer status OK" << std::endl;
  else                 o << s << "  X indexer status not OK" << std::endl;
  o << s << "  Unused bits = "
    << printHex((unsigned short)(_xStatus.halfWord(1)&0xfffc)) << std::endl;
  
  o << s << " X value 0 = " << printHex(_xValue[0].word()) << std::endl;
  o << s << "  X motor standby = " << std::setw(3) << xMotorStandby()
    << "%" << std::endl;
  o << s << "  X motor current = " << std::setw(3) << xMotorCurrent()
    << "%" << std::endl;
  o << s << "  X software revision = " << xMajorRevision() << "." 
    << xMinorRevision() << std::endl;
  
  o << s << " X value 1 = " << printHex(_xValue[1].word()) << std::endl;
  o << s << "  X motor resolution = " << xMotorResolution() 
    << " x 100 = " << 100.0*xMotorResolution() << std::endl;
  o << s << "  X motor velocity = " << xMotorVelocity()
    << "/100 = " << 0.01*xMotorVelocity() << std::endl;
  o << s << "  X stand position = " << xStandPosition() 
    << " x 0.1 mm = " << 0.1*xStandPosition() << " mm" << std::endl;
  
  o << s << " X value 2 = " << printHex(_xValue[2].word()) << std::endl;
  o << s << "  X beam position = " << xBeamPosition() 
    << " x 0.1 mm = " << 0.1*xBeamPosition() << " mm" << std::endl;
  o << s << "  Unused bits = " << printHex(_xValue[2].halfWord(1))
    << std::endl;
  
  o << s << " Y status  = " << printHex(_yStatus.word()) << std::endl;
  if(yIndexerStatus()) o << s << "  Y indexer status OK" << std::endl;
  else                 o << s << "  Y indexer status not OK" << std::endl;
  o << s << "  Unused bits = "
    << printHex((unsigned short)(_yStatus.halfWord(1)&0xfffc)) << std::endl;
  
  o << s << " Y value 0 = " << printHex(_yValue[0].word()) << std::endl;
  o << s << "  Y motor standby = " << std::setw(3) << yMotorStandby() 
    << "%" << std::endl;
  o << s << "  Y motor current = " << std::setw(3) << yMotorCurrent() 
    << "%" << std::endl;
  o << s << "  Y software revision = " << yMajorRevision() << "." 
    << yMinorRevision() << std::endl;
  
  o << s << " Y value 1 = " << printHex(_yValue[1].word()) << std::endl;
  o << s << "  Y motor resolution = " << yMotorResolution() 
    << " x 100 = " << 100.0*yMotorResolution() << std::endl;
  o << s << "  Y motor velocity = " << yMotorVelocity()
    << "/10 = " << 0.1*yMotorVelocity() << std::endl;
  o << s << "  Y stand position = " << yStandPosition() 
    << " x 0.1 mm = " << 0.1*yStandPosition() << " mm" << std::endl;
  
  o << s << " Y value 2 = " << printHex(_yValue[2].word()) << std::endl;
  o << s << "  Y beam position = " << yBeamPosition() 
    << " x 0.1 mm = " << 0.1*yBeamPosition() << " mm" << std::endl;
  o << s << "  Unused bits = " << printHex(_yValue[2].halfWord(1))
    << std::endl;
  
  o << s << " Checksum = " << _checksum << std::endl;
  if(validateChecksum()) o << s << "  Validated OK" << std::endl;
  else                   o << s << "  Not validated OK" << std::endl;
  
  return o;
}

#endif
#endif
