#ifndef DaqControl_HH
#define DaqControl_HH

#include <sys/types.h>
#include <signal.h>
#include <unistd.h>


class DaqControl {

public:
  enum {
    shmKey=0x76543210,
    maxCommand=4,
    maxCommandPid=254,
    maxStatusPid =254
  };

  DaqControl() : _wakeSignal(SIGUSR1),
		 _status(0), _nStatusPid(0), _nCommandPid(0) {
    for(unsigned i(0);i<maxCommand;i++) _command[i]=0xffffffff;
  }

  bool commandRegister() {
    if(_nCommandPid<maxCommandPid) {
      _commandPid[_nCommandPid]=getpid();
      _nCommandPid++;
    } else {
      std::cerr << "DaqControl::register()  Unable to add process id "
		<< getpid() << " to command list" << std::endl << std::flush;
      return false;
    }
    signal(_wakeSignal,sleepInterupt);
    return true;
  }

  bool statusRegister() {
    if(_nStatusPid<maxStatusPid) {
      _statusPid[_nStatusPid]=getpid();
      _nStatusPid++;
    } else {
      std::cerr << "DaqControl::register()  Unable to add process id "
		<< getpid() << " to status list" << std::endl << std::flush;
      return false;
    }
    signal(_wakeSignal,sleepInterupt);
    return true;
  }

  bool unregister() {
    const pid_t p(getpid());

    bool found(false);

    for(unsigned i(0);i<_nCommandPid;i++) {
      if(p==_commandPid[i]) {
	for(unsigned j(i+1);j<_nCommandPid;j++) {
	  _commandPid[i]=_commandPid[j];
	}
	_nCommandPid--;
	signal(_wakeSignal,SIG_IGN);
	found=true;
      }
    }

    for(unsigned i(0);i<_nStatusPid;i++) {
      if(p==_statusPid[i]) {
	for(unsigned j(i+1);j<_nStatusPid;j++) {
	  _statusPid[i]=_statusPid[j];
	}
	_nStatusPid--;
	signal(_wakeSignal,SIG_IGN);
	found=true;
      }
    }

    return found;
  }

  void wakeSignal(int s) {
    _wakeSignal=s;
  }

  static void sleepInterupt(int signal) {
    std::cerr << "DaqControl::sleepInterupt()  Process " << getpid() 
	      << " received signal " << signal << std::endl;
  }

  void statusSignal() const {
    for(unsigned i(0);i<_nStatusPid;i++) kill(_statusPid[i],_wakeSignal);
  }

  int status() const {
    return _status;
  }

  void status(int s, bool wake=true) {
    _status=s;
    if(wake) statusSignal();
  }

  void commandSignal() const {
    for(unsigned i(0);i<_nCommandPid;i++) kill(_commandPid[i],_wakeSignal);
  }

  unsigned command() const {
    unsigned c(_command[0]);
    for(unsigned i(1);i<maxCommand;i++) {
      if(_command[i]<c) c=_command[i];
    }
    return c;
  }

  void command(unsigned n, unsigned c, bool wake=true) {
    assert(n<maxCommand);
    if(c>=command()) wake=false;
    _command[n]=c;
    if(wake) commandSignal();
  }

  std::ostream& print(std::ostream& o, std::string s="") const {
    o << s << "DaqControl::print()" << std::endl;
    o << s << " Wake signal = " << _wakeSignal << std::endl;
    o << s << " Status  = " << _status << std::endl;

    for(unsigned i(0);i<maxCommand;i++) {
      if(_command[i]<0xffffffff) o << s << " Command " << i << " = "
				   << _command[i] << std::endl;
    }

    o << s << " Number of command processes = " 
      << std::setw(6) << _nCommandPid << std::endl;
    for(unsigned i(0);i<_nCommandPid;i++) {
      o << s << "  Pid " << std::setw(4) << i << " = "
	<< std::setw(8) << _commandPid[i] << std::endl;
    }

    o << s << " Number of status processes  = " 
      << std::setw(6) << _nStatusPid << std::endl;
    for(unsigned i(0);i<_nStatusPid;i++) {
      o << s << "  Pid " << std::setw(4) << i << " = "
	<< std::setw(8) << _statusPid[i] << std::endl;
    }

    return o;
  }


protected:
  int _wakeSignal;

  unsigned _status;
  unsigned _nStatusPid;
  pid_t _statusPid[maxStatusPid];

  unsigned _command[maxCommand];
  unsigned _nCommandPid;
  pid_t _commandPid[maxCommandPid];
};

#endif
