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


#define __PTV__C
#include <vdr/plugin.h>


#include <stdlib.h>
#include <vdr/device.h>
#include <vdr/player.h>
#include <vdr/config.h>
#include <time.h>
#include <sys/utsname.h>
#include "i18n.h"
#include "helpfunc.h"
#include "menusetup.h"
#include "ptv.h"
#include "device.h"

static const char *VERSION        = "20051117";
static const char *DESCRIPTION    = tr("Setup.PTV_$Watch analogue TV with PVR");

const char* cPluginPTV::Version(void)     { return VERSION; }
const char* cPluginPTV::Description(void) { return DESCRIPTION; }


cPluginPTV::cPluginPTV(void) {
  // 1. VDR call: Initialize any member variables here.
  // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
  // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
  int i;  
  ptvsetup.logger = STDOUT;
  ptvsetup.debug = 0;
  ptvsetup.linuxver = LinuxVersion();
  ptvsetup.volume = 91;
  ptvsetup.brightness = ptvsetup.contrast = ptvsetup.color = ptvsetup.hue = 17;
  ptvsetup.aspect = 1;
  ptvsetup.pulldown = 0;     
  ptvsetup.dnr_spatial = ptvsetup.dnr_temporal = 0;
  d(1, "ptv is derived from analogTV-0.9.37 by Andreas Kool (akool@gmx.de)");
  d(1, "and changed for optimal performance with PVR cards by wirbel. Therefore");
  d(1, "only Hardware-Encoder cards are supported by this version.");
  for (i=0; i < MAX_DEV_NUM; i++) PTV_Dev[i] = NULL;
  }

cPluginPTV::~cPluginPTV()  // Clean up after yourself! 
  {
  int i;
  for (i=0; i < MAX_DEV_NUM; i++) {
    if (PTV_Dev[i]) {
      PTV_Dev[i] = NULL;
      PTV_VideoDev[i]=-1;
      }
    else
      break;
    }
  }

bool cPluginPTV::Initialize(void) {
  // early initialization, 3. VDR call
  // Initialize any background activities the plugin shall perform.
  int i, j = 0;
  d(3, "cPluginPTV_::Initialize()");
  if (!ChkIvtv()) {
    d(0, "ERROR: ivtv not loaded, ptv cannot continue;");
    return false;
    }
  RegisterI18n(PTV_Phrases);
  for (i=0; i < MAX_DEV_NUM; i++) {
    if (ChkPvr(i)) {
      d(1,"creating PTV_Dev[%d]", j);
      PTV_Dev[j] = new cPTV_Device(j,i);
      PTV_VideoDev[j]=i;
      j++;
      }
    if (j == MAX_DEV_NUM)
      break;   
    }   
  return true;
  }

bool cPluginPTV::Start(void) {
  // final initialization, 5. VDR call
  // Start any background activities the plugin shall perform.
  d(3, "cPluginPTV::Start()");
  RegisterI18n(PTV_Phrases);
  fast_memcpy = memcpy;
  return true;
  }

void cPluginPTV::Stop(void)
{
  // Stop any background activities the plugin shall perform.
}

void cPluginPTV::Housekeeping(void)
  {// Perform any cleanup or other regular tasks.  
  int i;
  for (i=0; i < MAX_DEV_NUM; i++) {
    if (PTV_Dev[i])
      if (PTV_Dev[i]->HasEncoder()) {
        if (PTV_Dev[i]->EncoderIsRunning() && !PTV_Dev[i]->EncoderIsNeeded()) {
          d(2, "PTV_Dev[%d]: stopping encoder, not needed",i);
          PTV_Dev[i]->StopEncoder();
          }
        }       
    }
  }


cMenuSetupPage *cPluginPTV::SetupMenu(void) {
  return new cMenuSetupPTV(this);
  }

bool cPluginPTV::SetupParse(const char *Name, const char *Value) {
  // 2. VDR call
  // Parse your own setup parameters and store their values.
  if (!strcasecmp(Name, "debug"))
    ptvsetup.debug = atoi(Value);
  else if (!strcasecmp(Name, "Logger"))
    ptvsetup.logger = atoi(Value);
  else if (!strcasecmp(Name, "MixerVolume"))
    ptvsetup.volume = atoi(Value);
  else if (!strcasecmp(Name, "Brightness"))
    ptvsetup.brightness = atoi(Value);
  else if (!strcasecmp(Name, "Hue"))
    ptvsetup.hue = atoi(Value);
  else if (!strcasecmp(Name, "Color"))
    ptvsetup.color = atoi(Value);
  else if (!strcasecmp(Name, "Contrast"))
    ptvsetup.contrast = atoi(Value);
  else if (!strcasecmp(Name, "DNRspatial"))
    ptvsetup.dnr_spatial = atoi(Value);
  else if (!strcasecmp(Name, "DNRtemporal"))
    ptvsetup.dnr_temporal = atoi(Value);
  else if (!strcasecmp(Name, "Aspect"))
    ptvsetup.aspect = atoi(Value);
  else if (!strcasecmp(Name, "Pulldown"))
    ptvsetup.pulldown = atoi(Value);
  else
    return false;
  return true;
  }

bool cPluginPTV::ChkIvtv(void) {
  char buffer[256];
  int ivtv = 0;
  FILE *f = fopen("/proc/modules", "r");
  if (f) {  
    while (fgets(buffer, sizeof(buffer), f) > 0) {
      if (!memcmp(buffer, "ivtv", 4)) {
        ivtv++;
        break;             
        }
      }
    fclose(f);
    }
  else {
    d(0, "ivtv check failed, couldn't open /proc/modules.");
    }
  if (!ivtv) {
    d(0, "ptv plugin: ERROR IVTV NOT LOADED -> i'll try to load it now..");
    SystemExec("modprobe ivtv");
    usleep(5000000);
    f = fopen("/proc/modules", "r");
    if (f) {  
      while (fgets(buffer, sizeof(buffer), f) > 0) {
        if (!memcmp(buffer, "ivtv", 4)) {
          ivtv++;
          break;             
          }
        }
      fclose(f);
      }    
    }
  return (ivtv)? true : false;
  }

bool cPluginPTV::ChkPvr(int index) {
  auto struct v4l2_capability  v4l2cap;
  int vid_dev;
  sprintf(video_device, "/dev/video%d", index);
  if ((vid_dev = open(video_device, O_RDWR)) >= 0) {
    if (IOCTL(vid_dev, VIDIOC_QUERYCAP, &v4l2cap) > -1) {       
      if (!memcmp(v4l2cap.driver, "ivtv", 4)) {
        close(vid_dev);
        d(1,"/dev/video%d = %s", index, v4l2cap.card);
        return true;
        }
      }
    else
      close(vid_dev);
    }
  return false;
  }

int cPluginPTV::LinuxVersion(void) {
  auto struct utsname u;
  if (!uname(&u)) {
    if (!memcmp(u.release, "2.6", 3))
      return 6;
    if (!memcmp(u.release, "2.4", 3))
      return 4;
    }
  return -1;
  }


VDRPLUGINCREATOR(cPluginPTV); // Don't touch this!
