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

#include <getopt.h>
#include <stdlib.h>
#include <vdr/plugin.h>

#include "defs.h"
#include "filter.h"
#include "input.h"
#include "output.h"
#include "menu.h"
#include "setup.h"
#include "thread.h"
#include "whitecalibration.h"
#include "atmo.h"

#define BRIGHTNESSCORRECTION "BrightnessCorrection" // from menu.c

cPlugin *AtmoPlugin;

cAtmoSetup AtmoSetup;
cAtmoThread *AtmoThread;

// --- cPluginAtmo ------------------------------------------------------------

cPluginAtmo::cPluginAtmo()
{
  // 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!

  AtmoPlugin = this;
  AtmoThread = NULL;
}

cPluginAtmo::~cPluginAtmo()
{
  // Clean up after yourself!
}

const char *cPluginAtmo::CommandLineHelp(void)
{
  // Return a string that describes all known command line options.
  return "  -i INPUT_DEV               --input=INPUT_DEV\n"
         "     tells the plugin which input device to use\n"
         "     possible values:\n"
         "        FFDVB       use /dev/video (full-featured DVB-card)\n"
         "        SOFTDEVICE  use Softdevice-Plugin\n"
         "  -o OUTPUT_DEV=OUTPUT_ARG   --output=OUTPUT_DEV=OUTPUT_ARG\n"
         "     tells the plugin which output device to use\n"
         "     possible values:\n"
         "        NETWORK  use network (OUTPUT_ARG=IP:PORT e.g. 192.168.0.1:1234)\n"
         "        SERIAL   use serial port (OUTPUT_ARG=/dev/ttyXX e.g. /dev/ttyS1)";
}

bool cPluginAtmo::ProcessArgs(int argc, char *argv[])
{
  // Implement command line argument processing here if applicable.
  static struct option long_options[] = {
      { "input",  required_argument, NULL, 'i' },
      { "output", required_argument, NULL, 'o' },
      { NULL }
  };

  AtmoSetup.HasCmdLineArgs = true; // we use given command line arguments

  int c;
  while ((c=getopt_long(argc, argv, "i:o:", long_options, NULL)) != -1)
  {
    switch (c)
    {
      case 'i': // input
                if (strstr(optarg, "FFDVB"))
                {
                  AtmoSetup.AtmoInput = ffdvb;
                }
                else if (strstr(optarg, "SOFTDEVICE"))
                {
                  AtmoSetup.AtmoInput = softdevice;
                }
                else
                {
                  return false;
                }
      break;

      case 'o': // output
                if (strstr(optarg, "NETWORK"))
                {
                  AtmoSetup.AtmoOutput = network;
                  AtmoSetup.output_arg = strchr(optarg, '=') + 1;
                }
                else if (strstr(optarg, "SERIAL"))
                {
                  AtmoSetup.AtmoOutput = serial;
                  AtmoSetup.output_arg = strchr(optarg, '=') + 1;
                }
                else
                {
                  return false;
                }
      break;

      default: return false;
      break;
    }
  }
  return true;
}

bool cPluginAtmo::Initialize(void)
{
  // Initialize any background activities the plugin shall perform.
  return true;
}

bool cPluginAtmo::Start(void)
{
  // Start any background activities the plugin shall perform.
  AtmoThread = new cAtmoThread();
  AtmoThread->Start();
  return true;
}

void cPluginAtmo::Stop(void)
{
  // Stop any background activities the plugin shall perform.
  if (AtmoThread)
  {
    delete AtmoThread;
    AtmoThread = NULL;
  }
}

void cPluginAtmo::Housekeeping(void)
{
  // Perform any cleanup or other regular tasks.
}

void cPluginAtmo::MainThreadHook(void)
{
  // Perform actions in the context of the main program thread.
  // WARNING: Use with great care - see PLUGINS.html!
}

cString cPluginAtmo::Active(void)
{
  // Return a message string if shutdown should be postponed
  return NULL;
}

time_t cPluginAtmo::WakeupTime(void)
{
  // Return custom wakeup time for shutdown script
  return 0;
}

const char *cPluginAtmo::MainMenuEntry(void)
{
  if ((no_input == AtmoSetup.AtmoInput) ||
      (no_output == AtmoSetup.AtmoOutput))
  {
    return NULL;
  }
  else
  {
    if (true == AtmoSetup.atmo_on) { return tr("Atmolight off"); }
    else { return tr("Atmolight on"); }
  }
}

cOsdObject *cPluginAtmo::MainMenuAction(void)
{
  // Perform the action when selected from the main VDR menu.
  if (true == AtmoSetup.DoWhiteCalibration)
  {
    return new cAtmoWhiteCalibration;
  }
  else
  {
    AtmoSetup.atmo_on ? AtmoThread->SwitchOff() : AtmoThread->SwitchOn();
    return NULL;
  }
}

cMenuSetupPage *cPluginAtmo::SetupMenu(void)
{
  // Return a setup menu in case the plugin supports one.
  return new cMenuSetupAtmo;
}

bool cPluginAtmo::SetupParse(const char *Name, const char *Value)
{
  // Parse your own setup parameters and store their values.
       if (cMenuSetupAtmo::SetupParse(Name, Value)) ;
  else if (cMenuSetupMode::SetupParse(Name, Value)) ;
  else if (cMenuSetupFilter::SetupParse(Name, Value)) ;
  else if (cMenuSetupGamma::SetupParse(Name, Value)) ;
  else if (cAtmoWhiteCalibration::SetupParse(Name, Value)) ;
  else return false;

  return true;
}

bool cPluginAtmo::Service(const char *Id, void *Data)
{
  // Handle custom service requests from other plugins
  return false;
}

const char **cPluginAtmo::SVDRPHelpPages(void)
{
  // Return help text for SVDRP commands this plugin implements
  static const char *HelpPages[] = {
    "ON\n"
    "    Switch Atmolight on.",
    "OFF\n"
    "    Switch Atmolight off.",
    "STATUS\n"
    "    Print Atmolight status.",
    "LIVE_HSV\n"
    "    Switch Atmolight to \"live picture (HSV)\"-mode.",
    "pos\n"
    "    Atmolight shows the given \"RGB\"-color at the given position.\n"
    "    Possible values for 'pos': ALL, CENTER, LEFT, RIGHT, TOP, BOTTOM\n"
    "    Range for 'r', 'g', 'b': 0 - 255",
    "color\n"
    "    Atmolight shows the given color.\n"
    "    Possible values for 'color':\n"
    "    BLACK, WHITE, RED, GREEN, BLUE, YELLOW, CYAN, MAGENTA",
    "BRIGHT\n"
    "    Set brightness value.\n"
    "    Range for 'value': 50 - 300",
    NULL
    };
  return HelpPages;
}

cString cPluginAtmo::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
{
  // Process SVDRP commands this plugin implements
  tPosition pos = no_pos;
  int r = 0 , g = 0, b = 0;

  if (strcasecmp(Command, "ON") == 0)
  {
    AtmoThread->SwitchOn();
    return cString::sprintf("Atmolight: ON");
  }
  else if (strcasecmp(Command, "OFF") == 0)
  {
    AtmoThread->SwitchOff();
    return cString::sprintf("Atmolight: OFF");
  }
  else if (strcasecmp(Command, "STATUS") == 0)
  {
    if (true == AtmoSetup.atmo_on)
    {
      return cString::sprintf("Atmolight: ON");
    }
    else
    {
      return cString::sprintf("Atmolight: OFF");
    }
  }
  else if (strcasecmp(Command, "LIVE_HSV") == 0)
  {
    AtmoSetup.Mode = live_picture_hsv;
    return cString::sprintf("Atmolight: LIVE_HSV");
  }
  else if (strcasecmp(Command, "ALL") == 0)
  {
    pos = all;
  }
  else if (strcasecmp(Command, "CENTER") == 0)
  {
    pos = center;
  }
  else if (strcasecmp(Command, "LEFT") == 0)
  {
    pos = left;
  }
  else if (strcasecmp(Command, "RIGHT") == 0)
  {
    pos = right;
  }
  else if (strcasecmp(Command, "TOP") == 0)
  {
    pos = top;
  }
  else if (strcasecmp(Command, "BOTTOM") == 0)
  {
    pos = bottom;
  }
  else if (strcasecmp(Command, "BLACK") == 0)
  {
    AtmoSetup.SetDefault(black);
    return cString::sprintf("Atmolight color: BLACK");
  }
  else if (strcasecmp(Command, "WHITE") == 0)
  {
    AtmoSetup.SetDefault(white);
    return cString::sprintf("Atmolight color: WHITE");
  }
  else if (strcasecmp(Command, "RED") == 0)
  {
    AtmoSetup.SetDefault(red);
    return cString::sprintf("Atmolight color: RED");
  }
  else if (strcasecmp(Command, "GREEN") == 0)
  {
    AtmoSetup.SetDefault(green);
    return cString::sprintf("Atmolight color: GREEN");
  }
  else if (strcasecmp(Command, "BLUE") == 0)
  {
    AtmoSetup.SetDefault(blue);
    return cString::sprintf("Atmolight color: BLUE");
  }
  else if (strcasecmp(Command, "YELLOW") == 0)
  {
    AtmoSetup.SetDefault(yellow);
    return cString::sprintf("Atmolight color: YELLOW");
  }
  else if (strcasecmp(Command, "CYAN") == 0)
  {
    AtmoSetup.SetDefault(cyan);
    return cString::sprintf("Atmolight color: CYAN");
  }
  else if (strcasecmp(Command, "MAGENTA") == 0)
  {
    AtmoSetup.SetDefault(magenta);
    return cString::sprintf("Atmolight color: MAGENTA");
  }
  else if (strcasecmp(Command, "BRIGHT") == 0)
  {
    ReplyCode = 501;
    if (*Option)
    {
      if (1 == sscanf(Option, "%d", &r))
      {
        ReplyCode = 900;
        AtmoSetup.BrightCorrect = r;
        AtmoPlugin->SetupStore(BRIGHTNESSCORRECTION, AtmoSetup.BrightCorrect);
        return cString::sprintf("Atmolight: BRIGHT");
      }
      else
      {
        return cString::sprintf("Atmolight: Wrong number of parameters!");
      }
    }
    else
    {
      return cString::sprintf("Atmolight: Missing parameters!");
    }
  }
  else
  {
    return NULL;
  }

  if (pos != no_pos)
  {
    ReplyCode = 501;
    if (*Option)
    {
      if (3 == sscanf(Option, "%d %d %d", &r, &g, &b))
      {
        tRGBColor col = {r, g, b};
        ReplyCode = 900;
        AtmoSetup.SetStatic(pos, col);
        return cString::sprintf("Atmolight: %s", Command);
      }
      else
      {
        return cString::sprintf("Atmolight: Wrong number of parameters!");
      }
    }
    else
    {
      return cString::sprintf("Atmolight: Missing parameters!");
    }
  }
  
  return NULL; // erase compiler warning
}

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