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

#include <vdr/plugin.h>
#include <vdr/status.h>
#include <vdr/epg.h>
#include <getopt.h>
#include "menu_event.h"
#include "menu_main.h"
#include "menu_whatson.h"
#include "i18n.h"
#include "epgsearchsetup.h"
#include "epgsearchcfg.h"
#include "epgsearchext.h"
#include "epgsearchcats.h"
#include "menu_searchresults.h"
#include "searchtimer_thread.h"
#include "menu_myedittimer.h"
#include "tools.h"
#include "rcfile.h"
#include "changrp.h"

static const char *VERSION        = "0.9.7";
static const char *DESCRIPTION    = "search the EPG for repeats and more";
static const char *MAINMENUENTRY  = "Search";
const char *SVDRPSendCmd = "svdrpsend.pl";
char *ConfigDir = NULL;
int PluginIndex = -1;

class cPluginEpgsearch : public cPlugin {
private:
  // Add any member variables or functions you may need here.
public:
  cPluginEpgsearch(void);
  virtual ~cPluginEpgsearch();
  virtual const char *Version(void) { return VERSION; }
  virtual const char *Description(void) { return tr(DESCRIPTION); }
  virtual const char *CommandLineHelp(void);
  virtual bool ProcessArgs(int argc, char *argv[]);
  virtual bool Initialize(void);
  virtual bool Start(void);
  virtual void Stop(void);
  virtual void Housekeeping(void);
  virtual const char *MainMenuEntry(void) {  return (EPGSearchConfig.hidemenu ? NULL : tr(MAINMENUENTRY)); }
  virtual cOsdObject *MainMenuAction(void);
  virtual cMenuSetupPage *SetupMenu(void);
  virtual bool SetupParse(const char *Name, const char *Value);
  cOsdObject *DoInitialSearch(char* rcFilename);
#if VDRVERSNUM >= 10330 || defined(PATCH_CUSTOMSERVICES)
  bool Service(const char *Id, void *Data);
#endif
};

cPluginEpgsearch::cPluginEpgsearch(void)
{
  // 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!
}

cPluginEpgsearch::~cPluginEpgsearch()
{
    cSearchTimerThread::Exit();
}

const char *cPluginEpgsearch::CommandLineHelp(void)
{
  return "  -f file,  --svdrpsendcmd=file  the path to svdrpsend.pl for external\n"
         "                           SVDRP communitcation (default is internal\n"
         "                           communication)\n"
         "  -c path,  --config=path  to specify a specific config dir for epgsearch\n";
}


bool cPluginEpgsearch::ProcessArgs(int argc, char *argv[])
{
  // Implement command line argument processing here if applicable.


  if (argc==5 && !strcmp(argv[0], "timermenu"))
  { // yes, this is an ugly hack!
      argv[1] = (char*) new cMenuMyEditTimer((cTimer*) argv[2], (bool) argv[3], (const cEvent*) argv[4]);
      return true;
  }

  if (argc==8 && !strcmp(argv[0], "searchepg"))
  {
      cSearchExt* SearchExt = new cSearchExt;
      strcpy(SearchExt->search,argv[2]);
      if (atoi(argv[3]) > 0)
      {
	  SearchExt->useChannel = true;
	  SearchExt->channelMin = Channels.GetByNumber(atoi(argv[3]));
	  SearchExt->channelMax = Channels.GetByNumber(atoi(argv[3]));
      }
      SearchExt->mode = atoi(argv[4]);
      SearchExt->useTitle = atoi(argv[5]);
      SearchExt->useSubtitle = atoi(argv[6]);
      SearchExt->useDescription = atoi(argv[7]);
      argv[1] = (char*) new cMenuSearchResults(SearchExt);
      return true;
  }

  static struct option long_options[] = {
    { "svdrpsendcmd",          required_argument, NULL, 'f' },
    { "config",           required_argument, NULL, 'c' },
    { NULL }
  };

  int c=0,i=0;

  while ((c = getopt_long(argc, argv, "f:c:", long_options, &i)) != -1) {
        switch (c) {
          case 'f': 
	      SVDRPSendCmd = optarg;
	      EPGSearchConfig.useExternalSVDRP = 1;
	      break;
          case 'c': 
	      ConfigDir = optarg;
	      esyslog("CONFIGDIR: %s", ConfigDir);
	      break;
          default:  return false;
          }
        }

  if (EPGSearchConfig.useExternalSVDRP && access(SVDRPSendCmd, F_OK) != 0)
  {
      esyslog("EPGSearch: ERROR - can't find SVDRPSend script: '%s'", SVDRPSendCmd);
      SVDRPSendCmd = NULL;
  }

  return true;
}

#if VDRVERSNUM >= 10330 || defined(PATCH_CUSTOMSERVICES)

#include "services.h"

bool cPluginEpgsearch::Service(const char *Id, void *Data)
{
  if (strcmp(Id, "Epgsearch-search-v1.0") == 0) {
     if (Data == NULL)
        return true;
      cSearchExt* SearchExt = new cSearchExt;
      
      Epgsearch_search_v1_0* searchData = (Epgsearch_search_v1_0*) Data;
      searchData->pResultMenu = NULL;
      strcpy(SearchExt->search,searchData->query);
      if (searchData->channelNr > 0)
      {
	  SearchExt->useChannel = true;
	  SearchExt->channelMin = Channels.GetByNumber(searchData->channelNr);
	  SearchExt->channelMax = Channels.GetByNumber(searchData->channelNr);
      }
      SearchExt->mode = searchData->mode;
      SearchExt->useTitle = searchData->useTitle;
      SearchExt->useSubtitle = searchData->useSubTitle;
      SearchExt->useDescription = searchData->useDescription;
      searchData->pResultMenu = new cMenuSearchResults(SearchExt);

      return true;
  }
  if (strcmp(Id, "Epgsearch-exttimeredit-v1.0") == 0) {
     if (Data == NULL)
        return true;
      
      Epgsearch_exttimeredit_v1_0* serviceData = (Epgsearch_exttimeredit_v1_0*) Data;
      serviceData->pTimerMenu = new cMenuMyEditTimer(serviceData->timer, serviceData->bNew, serviceData->event);

      return true;
  }
  return false;
}
#endif

bool cPluginEpgsearch::Initialize(void)
{
  // Initialize any background activities the plugin shall perform.
  RegisterI18n(Phrases);

  return true;
}

bool cPluginEpgsearch::Start(void)
{
    if (EPGSearchConfig.showProgress >= 2)
    {
	isyslog("EPGSearch: fontpatch started");
	PatchFont(fontOsd);
	PatchFont(fontSml);
	isyslog("EPGSearch: fontpatch done");
    }

    SearchExtCats.Load(AddDirectory(CONFIGDIR, "epgsearchcats.conf"), true);
    ChannelGroups.Load(AddDirectory(CONFIGDIR, "epgsearchchangrps.conf"), true);
    SearchExts.Load(AddDirectory(CONFIGDIR, "epgsearch.conf"));
    
    cSearchTimerThread::Init();
    
    return true;
}

void cPluginEpgsearch::Stop(void)
{
    cSearchTimerThread::Exit();
}

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

cOsdObject *cPluginEpgsearch::DoInitialSearch(char* rcFilename)
{
    cRCFile rcFile;
    if (rcFile.Load(rcFilename))
    {
	esyslog(rcFile.Search);
	cSearchExt* SearchExt = new cSearchExt;
	strcpy(SearchExt->search,rcFile.Search);
	if (rcFile.ChannelNr != -1)
	{
	    SearchExt->useChannel = true;
	    SearchExt->channelMin = Channels.GetByNumber(rcFile.ChannelNr);
	    SearchExt->channelMax = Channels.GetByNumber(rcFile.ChannelNr);
	}
	SearchExt->mode = rcFile.SearchMode;
	SearchExt->useTitle = rcFile.UseTitle;
	SearchExt->useSubtitle = rcFile.UseSubtitle;
	SearchExt->useDescription = rcFile.UseDescr;
	remove(rcFilename);
	return new cMenuSearchResults(SearchExt);
    }
    else
	esyslog("EPGSearch: could not load %s", rcFilename);
	
    return NULL;
}

cOsdObject *cPluginEpgsearch::MainMenuAction(void)
{
    if (PluginIndex != -1)
    {
	cPlugin *p = cPluginManager::GetPlugin("timeline");
	PluginIndex = -1;
	if (p)
	    return p->MainMenuAction();
    }

    // Perform the action when selected from the main VDR menu.
    cOsdObject* pMenu = NULL;
    char* rcFilename = strdup(AddDirectory(CONFIGDIR, ".epgsearchrc"));
    if (access(rcFilename, F_OK) == 0)
	pMenu = DoInitialSearch(rcFilename);
    else
	pMenu = new cMenuSearchMain();
    
    free(rcFilename);
    return pMenu;
}

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

bool cPluginEpgsearch::SetupParse(const char *Name, const char *Value)
{
  // Parse your own setup parameters and store their values.

  if	  (!strcasecmp(Name, "IsOrgSchedule")) return (EPGSearchConfig.ReplaceOrgSchedule == false);

  if      (!strcasecmp(Name, "HideMenu"))       EPGSearchConfig.hidemenu         = atoi(Value);
  if      (!strcasecmp(Name, "ReplaceOrgSchedule"))  EPGSearchConfig.ReplaceOrgSchedule = atoi(Value);
  if      (!strcasecmp(Name, "StartMenu"))       EPGSearchConfig.StartMenu        = atoi(Value);
  if      (!strcasecmp(Name, "RedKeyMode"))     EPGSearchConfig.redkeymode       = atoi(Value);
  if      (!strcasecmp(Name, "BlueKeyMode"))     EPGSearchConfig.bluekeymode       = atoi(Value);
  if      (!strcasecmp(Name, "ShowProgress"))     EPGSearchConfig.showProgress   = atoi(Value);
  if      (!strcasecmp(Name, "ShowProgressNext"))     EPGSearchConfig.showProgressNext = atoi(Value);
  if      (!strcasecmp(Name, "ProgressWidth"))     EPGSearchConfig.ProgressWidth = atoi(Value);
  if      (!strcasecmp(Name, "ShowChannelNr"))     EPGSearchConfig.showChannelNr = atoi(Value);

  if      (!strcasecmp(Name, "UserMode1Description"))   EPGSearchConfig.ShowModes[showUserMode1].SetDescription(Value);
  if      (!strcasecmp(Name, "UserMode1Time"))   EPGSearchConfig.ShowModes[showUserMode1].SetTime(atoi(Value));
  if      (!strcasecmp(Name, "UserMode1UseIt"))   EPGSearchConfig.ShowModes[showUserMode1].SetUsage(atoi(Value));

  if      (!strcasecmp(Name, "UserMode2Description"))   EPGSearchConfig.ShowModes[showUserMode2].SetDescription(Value);
  if      (!strcasecmp(Name, "UserMode2Time"))   EPGSearchConfig.ShowModes[showUserMode2].SetTime(atoi(Value));
  if      (!strcasecmp(Name, "UserMode2UseIt"))   EPGSearchConfig.ShowModes[showUserMode2].SetUsage(atoi(Value));

  if      (!strcasecmp(Name, "UserMode3Description"))   EPGSearchConfig.ShowModes[showUserMode3].SetDescription(Value);
  if      (!strcasecmp(Name, "UserMode3Time"))   EPGSearchConfig.ShowModes[showUserMode3].SetTime(atoi(Value));
  if      (!strcasecmp(Name, "UserMode3UseIt"))   EPGSearchConfig.ShowModes[showUserMode3].SetUsage(atoi(Value));

  if      (!strcasecmp(Name, "UserMode4Description"))   EPGSearchConfig.ShowModes[showUserMode4].SetDescription(Value);
  if      (!strcasecmp(Name, "UserMode4Time"))   EPGSearchConfig.ShowModes[showUserMode4].SetTime(atoi(Value));
  if      (!strcasecmp(Name, "UserMode4UseIt"))   EPGSearchConfig.ShowModes[showUserMode4].SetUsage(atoi(Value));

  if      (!strcasecmp(Name, "UseSearchTimers"))  EPGSearchConfig.useSearchTimers = atoi(Value);
  if      (!strcasecmp(Name, "UpdateIntervall"))  EPGSearchConfig.UpdateIntervall = atoi(Value);
  if      (!strcasecmp(Name, "SVDRPPort"))  EPGSearchConfig.SVDRPPort = atoi(Value);
  if      (!strcasecmp(Name, "CheckTimerConflicts"))  EPGSearchConfig.checkTimerConflicts = atoi(Value);

  if      (!strcasecmp(Name, "TimeIntervallFRFF"))  EPGSearchConfig.timeShiftValue = atoi(Value);
  if      (!strcasecmp(Name, "ToggleGreenYellow"))  EPGSearchConfig.toggleGreenYellow = atoi(Value);

  if      (!strcasecmp(Name, "ShortChannelNames"))  EPGSearchConfig.useShortChNames = atoi(Value);

  if      (!strcasecmp(Name, "DefPriority"))  EPGSearchConfig.DefPriority = atoi(Value);
  if      (!strcasecmp(Name, "DefLifetime"))  EPGSearchConfig.DefLifetime = atoi(Value);
  if      (!strcasecmp(Name, "DefMarginStart"))  EPGSearchConfig.DefMarginStart = atoi(Value);
  if      (!strcasecmp(Name, "DefMarginStop"))  EPGSearchConfig.DefMarginStop = atoi(Value);

  if      (!strcasecmp(Name, "IgnorePayTV"))  EPGSearchConfig.ignorePayTV = atoi(Value);

  EPGSearchConfig.ShowModes[showNow].SetDescription(tr("Now"));
  EPGSearchConfig.ShowModes[showNext].SetDescription(tr("Next"));

  return true;
}

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