#ifndef UtlPackHalf_HH
#define UtlPackHalf_HH

#include <string>
#include <iostream>


class UtlPackHalf {

public:
  UtlPackHalf();  
  UtlPackHalf(unsigned short w);
  
  bool bit(unsigned b) const;
  void bit(unsigned b, bool c);

  unsigned bits(unsigned bLo, unsigned bHi) const;
  void     bits(unsigned bLo, unsigned bHi, unsigned b);
  
  unsigned char halfByte(unsigned b) const;  
  void          halfByte(unsigned b, unsigned char c);
  
  unsigned char byte(unsigned b) const;
  void          byte(unsigned b, unsigned char c);

  unsigned short halfWord() const;
  void           halfWord(unsigned short s);
  
  bool operator==(const UtlPackHalf &d) const;  
  bool operator!=(const UtlPackHalf &d) const;  

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


private:
  unsigned short _halfWord;
};


#ifdef CALICE_DAQ_ICC

#include <assert.h>

#include "UtlPrintHex.hh"


UtlPackHalf::UtlPackHalf() : _halfWord(0) {
}

UtlPackHalf::UtlPackHalf(unsigned short w) : _halfWord(w) {
}

bool UtlPackHalf::bit(unsigned b) const {
  assert(b<16);
  return (_halfWord>>b)&0x1;
}
  
void UtlPackHalf::bit(unsigned b, bool c) {
  assert(b<16);
  _halfWord&=~(1<<b);
  if(c) _halfWord|=1<<b;
}

unsigned UtlPackHalf::bits(unsigned bLo, unsigned bHi) const {
  assert(bHi<16 && bHi>=bLo);

  unsigned short temp(_halfWord<<(15-bHi));
  temp>>=(15-bHi+bLo);

  return temp;
    //return (_halfWord<<(15-bHi))>>(15-bHi+bLo);
}

void UtlPackHalf::bits(unsigned bLo, unsigned bHi, unsigned b) {
  assert(bHi<16 && bHi>=bLo);

  unsigned short temp0(_halfWord>>bHi);
  temp0<<=bHi;

  unsigned short temp1(b<<(15-bHi+bLo));
  temp1>>=(15-bHi);

  unsigned short temp2(_halfWord<<(15-bLo));
  temp2>>=(15-bLo);

  _halfWord=temp0|temp1|temp2;
  //_halfWord=((_halfWord>>bHi)<<bHi) | (b<<(15-bHi+bLo))>>(15-bHi) | ((_halfWord<<(15-bLo))>>(15-bLo));
}

unsigned char UtlPackHalf::halfByte(unsigned b) const {
  assert(b<4);
  return (_halfWord>>(4*b))&0xf;
}
  
void UtlPackHalf::halfByte(unsigned b, unsigned char c) {
  assert(b<4);
  _halfWord&=~(0xf<<(4*b));
  _halfWord|=(c&0xf)<<(4*b);
}
  
unsigned char UtlPackHalf::byte(unsigned b) const {
  assert(b<2);
  return (_halfWord>>(8*b))&0xff;
}
  
void UtlPackHalf::byte(unsigned b, unsigned char c) {
  assert(b<2);
    _halfWord&=~(0xff<<(8*b));
    _halfWord|=c<<(8*b);
}

unsigned short UtlPackHalf::halfWord() const {
  return _halfWord;
}

void UtlPackHalf::halfWord(unsigned short s) {
  _halfWord=s;
}

bool UtlPackHalf::operator==(const UtlPackHalf &d) const {
  return _halfWord==d._halfWord;
}
  
bool UtlPackHalf::operator!=(const UtlPackHalf &d) const {
  return _halfWord!=d._halfWord;
}

std::ostream& UtlPackHalf::print(std::ostream &o, std::string s) {
  o << s << "UtlPackHalf::print()" << std::endl;
  o << s << " Half word: "
    << printHex(halfWord()) << std::endl;
  o << s << " Bytes: "
    << printHex(byte(1)) << ", "
    << printHex(byte(0)) << std::endl;
  o << s << " Half bytes: "
    << printHex(halfByte(3)) << ", "
    << printHex(halfByte(2)) << ", "
    << printHex(halfByte(1)) << ", "
    << printHex(halfByte(0)) << std::endl;
  return o;
}

std::string printHex(UtlPackHalf n, bool b=true) {
  return printHex(n.halfWord(),b);
}

#endif
#endif
