/*
 * ipc.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id$
 */


#include <errno.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

#include <vdr/tools.h>

#include "ipc.h"





// --- cConsSimplePipe -------------------------------------------------------



cConsSimplePipe::cConsSimplePipe() {
  _pipe[0] = -1;
  _pipe[1] = -1;
}



cConsSimplePipe::~cConsSimplePipe() {
  Close();
}



bool cConsSimplePipe::Open() {

  if (IsOpen())
    return true;

  return (pipe(_pipe) == 0);
}



void cConsSimplePipe::Close() {

  for (int i = 0; i < 2; ++i) {

    if (_pipe[i] >= 0) {
      close(_pipe[i] );
      _pipe[i] = -1;
    }
  }
}







// --- cConsWaitableList -----------------------------------------------------



cConsWaitableList::cConsWaitableList()
: _list(NULL),
  _listCount(0)
{
  FD_ZERO(&_wait);
}



cConsWaitableList::~cConsWaitableList() {
  free(_list);
}



void cConsWaitableList::Add(IConsWaitable* pObj) {

  for (int i = 0; i < _listCount; ++i) {
    if (_list[i] == pObj)
      return;
  }

  _list = (IConsWaitable**) realloc((void*) _list, sizeof(IConsWaitable*) * ++_listCount);
  _list[_listCount - 1] = pObj;
}



void cConsWaitableList::Remove(IConsWaitable* pObj) {

  for (int i = 0; i < _listCount; ++i) {
    if (_list[i] == pObj) {
      // Object found
      for (int j = i + 1; j < _listCount; ++j) {
        _list[j - 1] = _list[j];
      }
      _list = (IConsWaitable**) realloc((void*) _list, sizeof(IConsWaitable*) * --_listCount);
      return;
    }
  }

  // object not found
}



bool cConsWaitableList::Wait(int timeoutMs) {

  int maxHandle = 0;

  FD_ZERO(&_wait);
  for (int i = 0; i < _listCount; ++i) {

    int handle = _list[i]->SignalToWaitFor();
    if (handle >= 0) {

      FD_SET(handle, &_wait);

      if (handle > maxHandle)
        maxHandle = handle;
    }
  }

  if (timeoutMs >= 0) {
    timeval timeout;
    timeout.tv_sec  = timeoutMs / 1000;
    timeout.tv_usec = (timeoutMs % 1000) * 1000;

    return (select(maxHandle + 1, &_wait, NULL, NULL, &timeout) > 0);

  } else {
    return (select(maxHandle + 1, &_wait, NULL, NULL, NULL) > 0);
  }
}







// --- cConsSignal -----------------------------------------------------------



cConsSignal::cConsSignal() {
  Open();
}



void cConsSignal::Signal() {

  // If the pipe is empty then put a char into the pipe
  // so that the receiver will be signalled.
  if (! IsSignalled())
    write(getWriter(), " ", 1);
}



void cConsSignal::Reset() {

  // remove the pending char from the pipe
  char buf;

  if (IsSignalled())
    read(getReader(), &buf, 1);
}



bool cConsSignal::IsSignalled() {

  cPoller poll(getReader());
  return poll.Poll(0);
}


