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

#include "menu_commands.h"
#include <vdr/interface.h>
#include <vdr/menu.h>
#include <vdr/plugin.h>
#include "menu_searchresults.h"
#include "menu_myedittimer.h"
#include "menu_search.h" 
#include "menu_searchedit.h" 
#include "epgsearchcfg.h"
#include "recdone.h"
#include "tools.h"
#include "switchtimer.h"
#include "switchtimer_thread.h"
#include "blacklist.h"
#include "menu_blacklistedit.h"
#include <vdr/menu.h>

// --- cMenuSearchCommands ---------------------------------------------------------

cMenuSearchCommands::cMenuSearchCommands(const char *Title, const cEvent* Event, bool DirectCall, cSearchExt* Search)
:cOsdMenu(Title)
{
    directCall = DirectCall;
    SetHasHotkeys();
    LoadCommands();
    
    search = Search;
    event = Event;
    Add(new cOsdItem(hk(tr("Repeats"))));
    Add(new cOsdItem(hk(tr("Button$Record"))));
    Add(new cOsdItem(hk(tr("Button$Switch"))));
    Add(new cOsdItem(hk(tr("Create search"))));
    Add(new cOsdItem(hk(tr("Search in recordings"))));
    Add(new cOsdItem(hk(tr("Mark as 'already recorded'?"))));
    Add(new cOsdItem(hk(tr("Add/Remove to/from switch list?"))));
    Add(new cOsdItem(hk(tr("Create blacklist"))));
    for (cCommand *command = commands.First(); command; command = commands.Next(command))
	Add(new cOsdItem(hk(command->Title())));
    if (event)
    {
	char* szTitle = NULL;
	asprintf(&szTitle, "%s: %s", tr("EPG Commands"), event->Title());
	SetTitle(szTitle);
	free(szTitle);
    }
}

cMenuSearchCommands::~cMenuSearchCommands()
{
}

void cMenuSearchCommands::LoadCommands()
{
    const char* szLanguageCode = I18nLanguageCode(Setup.OSDLanguage);
    char *pstrSearchToken, *pptr;
    char *pstrSearch=strdup(szLanguageCode);
    pstrSearchToken=strtok_r(pstrSearch, ",", &pptr);
    bool bLoaded = false;
    while(pstrSearchToken) // may contain multiple code, e.g. 'ger,deu'
    {
	char* cmdFile = NULL;
	asprintf(&cmdFile, "%s-%s.conf", ADDDIR(CONFIGDIR, "epgsearchcmds"), pstrSearchToken);
	if (access(cmdFile, F_OK) == 0) 	
	{
	    commands.Load(cmdFile, true);
	    free(cmdFile);
	    bLoaded = true;
	    break;
	}
	free(cmdFile);
	pstrSearchToken=strtok_r(NULL, ",", &pptr);
    }
    if (!bLoaded)
	commands.Load(AddDirectory(CONFIGDIR, "epgsearchcmds.conf"), true);
    free(pstrSearch);
}

eOSState cMenuSearchCommands::Switch(void)
{
    cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
    if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
        return osEnd;
     else
     {
	 Skins.Message(mtInfo, tr("Can't switch channel!")); 
	 return osContinue;
     }
}

eOSState cMenuSearchCommands::ExtendedSearch(void)
{
    return AddSubMenu(new cMenuEPGSearchExt());
}

eOSState cMenuSearchCommands::Record(void)
{
    if (!event) return osContinue;

    int timerMatch = tmNone;
    cTimer* timer = Timers.GetMatch(event, &timerMatch);
    if (timerMatch == tmFull) 
    {
#if VDRVERSNUM && VDRVERSNUM >= 10331
	if (EPGSearchConfig.useVDRTimerEditMenu)
	    return AddSubMenu(new cMenuEditTimer(timer));
	else
#endif
	    return AddSubMenu(new cMenuMyEditTimer(timer, false, event, timer->Channel()));
    }

    timer = new cTimer(event);
    PrepareTimerFile(event, timer);
    cTimer *t = Timers.GetTimer(timer);
    
    if (EPGSearchConfig.onePressTimerCreation == 0 || t || (!t && event->StartTime() - (Setup.MarginStart+2) * 60 < time(NULL))) 
    {
	if (t)
	{
	    delete timer;
	    timer = t;      
	}
#if VDRVERSNUM && VDRVERSNUM >= 10331
	if (EPGSearchConfig.useVDRTimerEditMenu)
	    return AddSubMenu(new cMenuEditTimer(timer, !t));
	else
#endif
	    return AddSubMenu(new cMenuMyEditTimer(timer, !t, event));     
    }
    else
    {
	Timers.Add(timer);
	timer->Matches();
#if VDRVERSNUM && VDRVERSNUM >= 10315
	Timers.SetModified();
#endif
	
#if VDRVERSNUM && VDRVERSNUM >= 10323
	isyslog("timer %s added (active)", *timer->ToDescr());
#else
	isyslog("timer %d added (active)", timer->Index()+1);
#endif
	return osBack;
    }
    return osContinue;
}

eOSState cMenuSearchCommands::MarkAsRecorded(void)
{
     if (!event) return osContinue;
     if (!Interface->Confirm(tr("Mark as 'already recorded'?")))
	 return osContinue;
     cTimer* dummyTimer = new cTimer(event);
     RecsDone.Add(new cRecDone(dummyTimer, event, search));
     RecsDone.Save();
     delete dummyTimer;
     return osBack;
}

eOSState cMenuSearchCommands::AddToSwitchList(void)
{
     if (!event) return osContinue;
     
     time_t now = time(NULL);
     if (now >= event->StartTime())
     {
	 Skins.Message(mtError, tr("Already running!"));
	 return osBack;
     }
     cSwitchTimer* switchTimer = SwitchTimers.InSwitchList(event);
     if (!switchTimer)
     {
	 if (!Interface->Confirm(tr("Add to switch list?")))
	     return osContinue;
	 SwitchTimers.Add(new cSwitchTimer(event));
	 cSwitchTimerThread::Init(); // asure the thread is running
     }
     else
     {
	 if (!Interface->Confirm(tr("Delete from switch list?")))
	     return osContinue;
	 SwitchTimers.Del(switchTimer);
	 if (SwitchTimers.Count() == 0)
	     cSwitchTimerThread::Exit(); 
     }
     SwitchTimers.Save();
     return osBack;
}

eOSState cMenuSearchCommands::CreateSearchTimer(void)
{
     if (!event) return osContinue;

     cSearchExt* pNew = new cSearchExt;
     strcpy(pNew->search, event->Title());
     return AddSubMenu(new cMenuEditSearchExt(pNew, true));
}

eOSState cMenuSearchCommands::CreateBlacklist(void)
{
     if (!event) return osContinue;

     cBlacklist* pNew = new cBlacklist;
     strcpy(pNew->search, event->Title());
     return AddSubMenu(new cMenuBlacklistEdit(pNew, true));
}

eOSState cMenuSearchCommands::Execute(void)
{
  int current = Current();
  if (current <= 7)
  {
     if (current == 0)
     	return AddSubMenu(new cMenuSearchResults(event->Title()));
     if (current == 1)
	return Record(); 
     if (current == 2)
	 return Switch();
     if (current == 3)
     	return CreateSearchTimer(); 
     if (current == 4)
     	return AddSubMenu(new cMenuSearchResults(event->Title(), true));
     if (current == 5)
	return MarkAsRecorded(); 
     if (current == 6)
	return AddToSwitchList(); 
     if (current == 7)
	return CreateBlacklist(); 
  }

  cCommand *command = commands.Get(current-8);
  if (command) {
     char *buffer = NULL;
     bool confirmed = true;
     if (command->Confirm()) {
        asprintf(&buffer, "%s?", command->Title());
        confirmed = Interface->Confirm(buffer);
        free(buffer);
        }
     if (confirmed) {
        asprintf(&buffer, "%s...", command->Title());
        Skins.Message(mtStatus, buffer);
        free(buffer);

        asprintf(&buffer, "\"%s\" %ld %ld %d \"%s\" \"%s\"", event->Title(), event->StartTime(), event->EndTime(), Channels.GetByChannelID(event->ChannelID())->Number(), Channels.GetByChannelID(event->ChannelID())->Name(), event->ShortText()?event->ShortText():"");
        const char *Result = command->Execute(buffer);
        free(buffer);
        Skins.Message(mtStatus, NULL);
        if (Result)
           return AddSubMenu(new cMenuText(command->Title(), Result, fontFix));
        return osBack;
        }
     }
  return osContinue;
}

eOSState cMenuSearchCommands::ProcessKey(eKeys Key)
{
    bool hadSubmenu = HasSubMenu();
    eOSState state = cOsdMenu::ProcessKey(Key);

    // jump back to calling menu, if a command was called directly with key '1' .. '9'
    if (directCall && hadSubmenu && !HasSubMenu())
	return osBack;

    if (state == osUnknown) {
	switch (Key) {
	    case kGreen:
	    case kYellow:
	    case kBlue:
		return osContinue;
	    case k1...k9:
	    case kOk:  
		return Execute();
	    default:   break;
	}
    }
    return state;
}
