#ifndef MpsLocation_HH
#define MpsLocation_HH

#include <string>
#include <iostream>

#include "UtlPack.hh"


class MpsLocation {

public:
  enum Site {
    test,
    birmingham,
    imperial,
    ralmeg,
    ralppd,
    desy,
    simulation
  };


  MpsLocation();  
  MpsLocation(unsigned char c, unsigned char s, unsigned char f);  
  MpsLocation(unsigned char c, unsigned char s, unsigned char f, unsigned char l);
  
  unsigned char siteNumber() const;  
  void          siteNumber(unsigned char n);
  
  unsigned char usbDaqAddress() const;
  void          usbDaqAddress(unsigned char n);
  bool          usbDaqMaster() const;  
  void          usbDaqMaster(bool e);

  bool          usbDaqMasterBroadcast() const;  
  void          usbDaqMasterBroadcast(bool e);
  bool          usbDaqSlaveBroadcast() const;  
  void          usbDaqSlaveBroadcast(bool e);
  bool          usbDaqBroadcast() const;  
  void          usbDaqBroadcast(bool e);
  
  unsigned char sensorId() const;  
  void          sensorId(unsigned char n);
  bool          sensorBroadcast() const;  
  void          sensorBroadcast(bool e);
  bool          sensorV11() const;
  
  unsigned char label() const;
  void          label(unsigned char n);

  bool          write() const;
  void          write(bool w);

  bool          ignore() const;

  bool operator==(const MpsLocation &d) const;
  bool operator!=(const MpsLocation &d) const;

  UtlPack location() const;
  void    location(UtlPack l);

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


private:
  UtlPack _location;
};


#ifdef CALICE_DAQ_ICC

MpsLocation::MpsLocation() : _location(0) {
}

MpsLocation::MpsLocation(unsigned char c, unsigned char s, unsigned char f) : _location(0) {
  siteNumber(c);
  usbDaqAddress(s);
  sensorId(f);
}
  
MpsLocation::MpsLocation(unsigned char c, unsigned char s, unsigned char f, unsigned char l) {
  siteNumber(c);
  usbDaqAddress(s);
  sensorId(f);
  label(l);
}
  
unsigned char MpsLocation::siteNumber() const {
  return _location.byte(3);
}

void MpsLocation::siteNumber(unsigned char n) {
  _location.byte(3,n);
}

unsigned char MpsLocation::usbDaqAddress() const {
  return _location.halfByte(4);
}

void MpsLocation::usbDaqAddress(unsigned char n) {
  _location.halfByte(4,n&0xf);
}

bool MpsLocation::usbDaqMaster() const {
  return _location.bit(23);
}

void MpsLocation::usbDaqMaster(bool e) {
  _location.bit(23,e);
}

bool MpsLocation::usbDaqMasterBroadcast() const {
  return _location.bit(22); 
}

void MpsLocation::usbDaqMasterBroadcast(bool e) {
  _location.bit(22,e);
}

bool MpsLocation::usbDaqSlaveBroadcast() const {
  return _location.bit(21); 
}

void MpsLocation::usbDaqSlaveBroadcast(bool e) {
  _location.bit(21,e);
}

bool MpsLocation::usbDaqBroadcast() const {
  return usbDaqMasterBroadcast() && usbDaqSlaveBroadcast();
}

void MpsLocation::usbDaqBroadcast(bool e) {
  usbDaqMasterBroadcast(e);
  usbDaqSlaveBroadcast(e);
}

unsigned char MpsLocation::sensorId() const {
  return _location.byte(1);
}

void MpsLocation::sensorId(unsigned char n) {
  _location.byte(1,n);
}

bool MpsLocation::sensorBroadcast() const {
  return (_location.byte(1)&0xff)==0xff;
}

void MpsLocation::sensorBroadcast(bool e) {
  if(e) _location.byte(1,0xff);
  else  _location.byte(1,0x00);
}

bool MpsLocation::sensorV11() const {
  assert(!sensorBroadcast());
  return (sensorId()>=21);
}

unsigned char MpsLocation::label() const {
  return _location.byte(0);
}

void MpsLocation::label(unsigned char n) {
  _location.byte(0,n);
}

bool MpsLocation::write() const {
  return _location.bit(0);
}

void MpsLocation::write(bool w) {
  _location.bit(0,w);
}

bool MpsLocation::ignore() const {
  return _location.bit(2);
}

bool MpsLocation::operator==(const MpsLocation &d) const {
  return _location==d._location;
}

bool MpsLocation::operator!=(const MpsLocation &d) const {
  return _location!=d._location;
}

UtlPack MpsLocation::location() const {
  return _location;
}

void MpsLocation::location(UtlPack l) {
  _location=l;
}

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

  o << s << " Site number    = "
    << printHex(siteNumber(),false) << std::endl;

  o << s << " UsbDaq address = "
    << printHex(usbDaqAddress(),false) << std::endl;

  o << s << " UsbDaq tags    = "
    << printHex((unsigned char)_location.halfByte(5),false);
  if(usbDaqMaster()) o << " = master";
  if(usbDaqBroadcast()) {
    o << " = broadcast";
  } else {
    if(usbDaqMasterBroadcast()) o << " = master broadcast";
    if(usbDaqSlaveBroadcast()) o << " = slave broadcast";
  }
  o << std::endl;

  o << s << " Sensor id      = " << std::setw(4)
    << printHex(sensorId(),false);
  if(sensorBroadcast()) o << " = broadcast";
  else {
    if(sensorV11()) o << " = sensor V1.1";
    else            o << " = sensor V1.0";
  }
  o << std::endl;

  o << s << " R/W label      = " << printHex(label());
  if(write()) o << " = write";
  else        o << " = read";
  if(ignore()) o << ", ignore";
  o << std::endl;

  return o;
}

#endif

#endif
