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

#include <vdr/thread.h>

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

#include <vdr/remote.h>
#include <vdr/lirc.h>
#include <vdr/rcu.h>

#include "externalplayer-player.h"

cRemotesDisable::cRemotesDisable(char * nLircDevice, char * nRcuDevice) {
  lircDevice = nLircDevice;
  rcuDevice  = nRcuDevice;
  kbdFound  = false;
  lircFound = false;
  rcuFound  = false;
  deactivated = false;
}

cRemotesDisable::~cRemotesDisable() {
  if (deactivated) {
    reactivateRemotes();
  }
}

void cRemotesDisable::deactivateRemotes() {
  isyslog("externalplayer-plugin: deactivating remotes");

  cRemote * i = Remotes.First();
  while (i != NULL) {
    if (strcmp(i->Name(), "KBD") == 0) {
      kbdFound = true;
      cRemote * j = i;
      i = Remotes.Next(i);
      Remotes.Del(j);
    }
    else if (strcmp(i->Name(), "LIRC") == 0) {
      lircFound = true;
      cRemote * j = i;
      i = Remotes.Next(i);
      Remotes.Del(j);
    }
    else if (strcmp(i->Name(), "RCU") == 0) {
      rcuFound = true;
      cRemote * j = i;
      i = Remotes.Next(i);
      Remotes.Del(j);
    }
    else {
      i = Remotes.Next(i);
    }
  }

  deactivated = true;
}

void cRemotesDisable::reactivateRemotes() {
  isyslog("externalplayer-plugin: reactivating remotes");

  if (kbdFound) {
    new cKbdRemote();
  }
  if (lircFound) {
    new cLircRemote(lircDevice);
  }
  if (rcuFound) {
    new cRcuRemote(rcuDevice);
  }
  deactivated = false;
}

cPlayerExternalplayer::cPlayerExternalplayer(ePlayMode playMode, cRemotesDisable * nRemotesDisable, char * nPlayerCommand)
    : cPlayer(playMode) {
  remotesLock    = nRemotesDisable;
  playerCommand  = nPlayerCommand;
  pid            = 0;
}

cPlayerExternalplayer::~cPlayerExternalplayer() {
  Activate(false);
  delete remotesLock;
}

void cPlayerExternalplayer::Activate(bool On) {
  if (On) {
    if (remotesLock != NULL) {
      remotesLock->deactivateRemotes();
    }

    int nPid = fork();
    if (nPid == 0) {
      isyslog("externalplayer-plugin: executing: %s", playerCommand);
      execle("/bin/sh", "sh", "-c", playerCommand, 0, environ);
      isyslog("externalplayer-plugin: execution (of /bin/sh) failed");
      exit(0);
    }
    else {
      pid = nPid;
    }
  }
  else {
    if (remotesLock != NULL) {
      remotesLock->reactivateRemotes();
    }

    if (pid != 0) {
      kill(pid, SIGTERM);
    }
  }
}

bool cPlayerExternalplayer::isActive() {
  return (waitpid(pid, 0, WNOHANG) == 0);
}

cControlExternalplayer::cControlExternalplayer(ePlayMode playMode, cRemotesDisable * remotesDisable, char * playerCommand)
    : cControl(player = new cPlayerExternalplayer(playMode, remotesDisable, playerCommand)) {
}

eOSState cControlExternalplayer::ProcessKey(eKeys key) {
  if (!(((cPlayerExternalplayer *)player)->isActive())) {
    isyslog("externalplayer-plugin: shutting down player");
    delete player;
    delete this;
    return osEnd;
  }

  return osContinue;
}
