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

#include "menu_whatson.h"
#include "epgsearchext.h"
#include "menu_event.h"
#include "menu_myedittimer.h"
#include "menu_searchresults.h"
#include "menu_search.h" 
#include "menu_commands.h"
#include "epgsearchcfg.h"
#include "tools.h"
#include "switchtimer.h"
#include "epgsearchcats.h"
#include <math.h>
#include <vdr/menu.h>

#define HOURS(x) ((x)/100)
#define MINUTES(x) ((x)%100)

extern int exitToMainMenu;

extern char menuWhatsOnNowTemplate[]; 
extern char menuWhatsOnNextTemplate[];
extern char menuWhatsOnElseTemplate[];
extern char menuScheduleTemplate[]; 
extern int menuWhatsOnNowTabs[];
extern int menuWhatsOnNextTabs[];
extern int menuWhatsOnElseTabs[];

// --- cMenuMyScheduleItem ------------------------------------------------------
cMenuMyScheduleItem::cMenuMyScheduleItem(const cEvent *Event, cChannel *Channel, int Progress, showMode Mode)
{
  event = Event;
  channel = Channel;
  progress = Progress;
  mode = Mode;
  timerMatch = tmNone;
  inSwitchList = false;
  Update(true);
}

bool cMenuMyScheduleItem::Update(bool Force)
{
    char* menutemplate = NULL;
    if (mode == showNow)
	menutemplate = menuWhatsOnNowTemplate;
    if (mode == showNext)
	menutemplate = menuWhatsOnNextTemplate;
    if (mode > showNext)
	menutemplate = menuWhatsOnElseTemplate;
    if (!channel)
	menutemplate = menuScheduleTemplate;	

    if (!menutemplate || strlen(menutemplate) == 0)
	return false;

    bool result = false;

    int OldTimerMatch = timerMatch;
    bool OldInSwitchList = inSwitchList;
    bool hasMatch = false; 
    cTimer* timer = NULL;
    if (event) timer = Timers.GetMatch(event, &timerMatch);
    if (event) inSwitchList = (SwitchTimers.InSwitchList(event)!=NULL);
    if (timer) hasMatch = true;
    
    if (Force || timerMatch != OldTimerMatch || inSwitchList != OldInSwitchList) 
    {
	char szChannelNr[6] = "";
	if (channel)
	    sprintf(szChannelNr, "%d", channel->Number());
	
	char szProgressPart[12] = "";
	char szProgressPartT2S[12] = "";
	if (channel)
	{
	    if (event)
	    {
		int frac = 0;
		if (mode == showNow)
		    frac = (int)roundf( (float)(time(NULL) - event->StartTime()) / (float)(event->Duration()) * 8.0 );
		if (mode == showNext)
		    frac = (int)roundf( (float)(1 - min(float(30*60), float(event->StartTime() - time(NULL))) / (30*60)) * 8.0 );
		frac = min(8,max(0, frac));
		
		char szProgressT2S[9] = "";
		for(int i = 0; i < frac; i++) szProgressT2S[i] = '|';
		szProgressT2S[frac]=0;
		sprintf(szProgressPartT2S, "%c%-8s%c", '[', szProgressT2S, ']');

		char szProgress[9] = {130,131,131,131,131,131,131,132,0};
		for(int i = 0; i < frac; i++) szProgress[i] = 127;
		sprintf(szProgressPart, "%-8s", szProgress);
	    }
	}
      
      char t[2]="",v[2]="",r[2]="";
      char szStatus[4] = "";
      if (EPGSearchConfig.WarEagle)
      {
	  sprintf(t, "%c", event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?249:253) : 't' : ' ');
	  sprintf(v, "%c", event && event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ');
	  sprintf(r, "%c", event && event->IsRunning() ? 251 : ' ');
      }
      else
      {
	  sprintf(t, "%c", event && hasMatch ? (timerMatch == tmFull) ? ((timer && timer->Recording())?'R':'T') : 't' : ' ');
	  sprintf(v, "%c", event && event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ');
	  sprintf(r, "%c", event && event->IsRunning() ? '*' : ' ');
      }

      if (event && inSwitchList)
      {
	  cSwitchTimer* s = SwitchTimers.InSwitchList(event);
	  sprintf(t, "%c", (s && s->announceOnly)?'s':'S');
      }
      sprintf(szStatus, "%s%s%s", t,v,r);

      char day[3] = "";
      char date[9] = "";
      char dateshort[7] = "";
      if (event)
      {
	  struct tm tm_r;
	  const time_t t = event->StartTime();
	  tm *tm = localtime_r(&t, &tm_r);
	  strftime(day, sizeof(day), "%d", tm);
	  strftime(date, sizeof(date), "%d.%m.%y", tm);
	  strftime(dateshort, sizeof(dateshort), "%d.%m.", tm);
      }

      char* buffer = strdup(menutemplate);
      char* tmp = strreplaceall(buffer, '|', "\t");
      free(buffer);
      buffer = tmp;
      while(strcasestr(buffer, "%colon%"))
	  buffer = strreplacei(buffer, "%colon%", ":");
      buffer = strreplacei(buffer, "%time%", event?GETTIMESTRING(event):"");
      buffer = strreplacei(buffer, "%time_w%", event?WEEKDAYNAME(event->StartTime()):"");
      buffer = strreplacei(buffer, "%time_d%", event?day:"");
      buffer = strreplacei(buffer, "%date%", event?date:"");
      buffer = strreplacei(buffer, "%datesh%", event?dateshort:"");
      buffer = strreplacei(buffer, "%title%", event?event->Title():tr(">>> no info! <<<"));
      buffer = strreplacei(buffer, "%subtitle%", (event && event->ShortText())?event->ShortText():"");
      buffer = strreplacei(buffer, "%status%", szStatus);
      buffer = strreplacei(buffer, "%t_status%", t);
      buffer = strreplacei(buffer, "%v_status%", v);
      buffer = strreplacei(buffer, "%r_status%", r);
      if (SearchExtCats.Count() > 0)
      {
	  cSearchExtCat *SearchExtCat = SearchExtCats.First();
	  while (SearchExtCat) 
	  {
	      char* catvalue = NULL;
	      if (event)
		  catvalue = GetExtEPGValue(event->Description(), SearchExtCat->name);
	      char* catname = NULL;
	      asprintf(&catname, "%%%s%%", SearchExtCat->name);
	      buffer = strreplacei(buffer, catname, catvalue?catvalue:"");
	      if (catvalue) free(catvalue);
	      free(catname);
	      SearchExtCat = SearchExtCats.Next(SearchExtCat);
	  }
      }
      
      if (channel)
      {
	  buffer = strreplacei(buffer, "%chnr%", szChannelNr);
#if VDRVERSNUM >= 10315    
	  buffer = strreplacei(buffer, "%chsh%", channel?channel->ShortName(true):"");
#endif
	  buffer = strreplacei(buffer, "%chlng%", channel?channel->Name():"");
	  buffer = strreplacei(buffer, "%progr%", szProgressPart);
	  buffer = strreplacei(buffer, "%progrT2S%", szProgressPartT2S);
      }

      buffer = FixSeparators(buffer, '~');
      buffer = FixSeparators(buffer, ':');
      buffer = FixSeparators(buffer, '-');

      SetText(buffer, false);
      return true;
  }
  return result;
}

// --- cMenuWhatsOnSearch ----------------------------------------------------------

int cMenuWhatsOnSearch::currentChannel = 0;
showMode cMenuWhatsOnSearch::currentShowMode = showNow;
cChannel *cMenuWhatsOnSearch::scheduleChannel = NULL;
extern const char *ShowModes[];

cMenuWhatsOnSearch::cMenuWhatsOnSearch(const cSchedules *Schedules, int CurrentChannelNr)
    :cOsdMenu(EPGSearchConfig.ShowModes[currentShowMode].GetDescription(), GetTab(1), GetTab(2), GetTab(3), GetTab(4), GetTab(5))
{
    shiftTime = 0;
    schedules = Schedules;

    // do a font patch, if necessary
    if (strcasestr(menuWhatsOnNowTemplate, "%progr%") ||
	strcasestr(menuWhatsOnNextTemplate, "%progr%"))
    {
	if(Setup.UseSmallFont==2)  
	    PatchFont(fontSml);
	else
	    PatchFont(fontOsd);	
    }

    LoadSchedules();

    currentChannel = CurrentChannelNr;
    
    char* szTitle = NULL;
    asprintf(&szTitle, "%s - %s", tr("Overview"), EPGSearchConfig.ShowModes[currentShowMode].GetDescription());
    SetTitle(szTitle);
    free(szTitle);
    SetHelpKeys();
}

cMenuWhatsOnSearch::~cMenuWhatsOnSearch()
{
}

int cMenuWhatsOnSearch::GetTab(int Tab)
{
    if (currentShowMode == showNow && strlen(menuWhatsOnNowTemplate) > 0)
	return menuWhatsOnNowTabs[Tab-1];
    if (currentShowMode == showNext && strlen(menuWhatsOnNextTemplate) > 0)
	return menuWhatsOnNextTabs[Tab-1];
    if (currentShowMode > showNext && strlen(menuWhatsOnElseTemplate) > 0)
	return menuWhatsOnElseTabs[Tab-1];
    else
	return 0;
}

void cMenuWhatsOnSearch::LoadSchedules()
{
    Clear();

    time_t SeekTime;
    char* szTitle = NULL;
    if (shiftTime != 0)
    {
	if (currentShowMode == showNow || currentShowMode == showNext)
	    SeekTime = time(NULL);
	else
	    SeekTime = GetTimeT(EPGSearchConfig.ShowModes[currentShowMode].GetTime());
	SeekTime += shiftTime*60;

	struct tm tm_r;
	time_t now = time(NULL);
	tm tm_seek = *localtime_r(&SeekTime, &tm_r);
	tm tm_now = *localtime_r(&now, &tm_r);
	if (tm_seek.tm_mday != tm_now.tm_mday)
	    asprintf(&szTitle, "%s - %s", tr("Overview"), DAYDATETIME(SeekTime));
	else
	    asprintf(&szTitle, "%s - %02d:%02d", tr("Overview"), tm_seek.tm_hour, tm_seek.tm_min);
    }
    else
	asprintf(&szTitle, "%s - %s", tr("Overview"), EPGSearchConfig.ShowModes[currentShowMode].GetDescription());
    
    SetTitle(szTitle);
    free(szTitle);
	
    for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
	if (!Channel->GroupSep()) {
	    if (EPGSearchConfig.showRadioChannels == 0 && ISRADIO(Channel))
		continue;
	    const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
	    const cEvent *Event = NULL;
	    if (Schedule) 
	    {		
		if (shiftTime != 0)
		    Event = Schedule->GetEventAround(SeekTime);
		else
		{
		    switch(currentShowMode)
		    {  
			default:
			case showNow: 
			    Event = Schedule->GetPresentEvent();
			    break;
			case showNext:
			    Event = Schedule->GetFollowingEvent();
			    break;
			case showUserMode1:
			case showUserMode2:
			case showUserMode3:
			case showUserMode4:
			    time_t SeekTime = GetTimeT(EPGSearchConfig.ShowModes[currentShowMode].GetTime());
			    Event = Schedule->GetEventAround(SeekTime);
			    break;
		    }
		}
	     }
	     if (!EPGSearchConfig.showEmptyChannels && !Event)
		 continue;
	     int iProgress = 0;
/*	     if (currentShowMode==showNow)
		 iProgress = EPGSearchConfig.showProgress;
	     if (currentShowMode==showNext)
		 iProgress = EPGSearchConfig.showProgressNext;
*/	     Add(new cMenuMyScheduleItem(Event, Channel, iProgress, currentShowMode), Channel->Number() == currentChannel);
	}
	else
	{
	    if (EPGSearchConfig.showChannelGroups)
	    {
		char* szGroup = NULL;
		asprintf(&szGroup, "----------------------------------------\t %s ----------------------------------------------------------------------------------------------", Channel->Name());
		cOsdItem* pGroupItem = new cOsdItem(szGroup);
		free(szGroup);
		pGroupItem->SetSelectable(false);
		Add(pGroupItem);
	    }
	}
    }
}

time_t cMenuWhatsOnSearch::GetTimeT(int iTime)
{
    struct tm tm_r;
    time_t t = time(NULL);
    tm* tmnow = localtime_r(&t, &tm_r);
    tmnow->tm_hour = HOURS(iTime);
    tmnow->tm_min = MINUTES(iTime);
    return mktime(tmnow);
}

showMode cMenuWhatsOnSearch::GetNextMode()
{
    showMode nextShowMode = currentShowMode;
    time_t now = time(NULL);
    do
    {
	nextShowMode = (showMode)((nextShowMode+1) % showModeMax);
	if (nextShowMode >= showUserMode1)
	{
	    if (!EPGSearchConfig.ShowModes[nextShowMode].GetUsage())
		continue;

	    time_t TestTime = GetTimeT(EPGSearchConfig.ShowModes[nextShowMode].GetTime());    
	    if (TestTime < now)
		continue;
	    break;
	}
	else
	    break;
    }
    while(true);
    return nextShowMode;
}
cChannel *cMenuWhatsOnSearch::ScheduleChannel(void)
{
  cChannel *ch = scheduleChannel;
  scheduleChannel = NULL;
  return ch;
}


eOSState cMenuWhatsOnSearch::Switch(void)
{
  cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current());
  if (item && item->channel) {
     if (cDevice::PrimaryDevice()->SwitchChannel(item->channel, true))
        return osEnd;
     }
  Skins.Message(mtInfo, tr("Can't switch channel!")); 
  return osContinue;
}

eOSState cMenuWhatsOnSearch::Record(void)
{
  cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current());
  if (item) 
  {
      if (item->timerMatch == tmFull) 
      {
	  int tm = tmNone;
	  cTimer *timer = Timers.GetMatch(item->event, &tm);
	  if (timer)
#if VDRVERSNUM && VDRVERSNUM >= 10331
	      if (EPGSearchConfig.useVDRTimerEditMenu)
		  return AddSubMenu(new cMenuEditTimer(timer));
	      else
#endif
		  return AddSubMenu(new cMenuMyEditTimer(timer, false, item->event, item->channel));
      }

      cTimer *timer = NULL;
      if (item->event)
      {
          timer = new cTimer(item->event);
          PrepareTimerFile(item->event, timer);
      }
      else
      {
          time_t now = time(NULL); // thanks to nordlicht@vdrportal for the following code, that
          char *buffer=NULL;       // allows setting the channel for a timer without event
          int starthh,startmm,stophh,stopmm;
          //for getting the day of month
	  struct tm tm_t_store;
	  struct tm *tm_t = localtime_r(&now, &tm_t_store);
          //we have to get away the ':' from the time string
          sscanf(TIMESTRING(now),"%2d:%2d",&starthh,&startmm);
          sscanf(TIMESTRING(now+Setup.InstantRecordTime*60),"%2d:%2d",&stophh,&stopmm);
          //active:channel:day_of_month:starttime:endtime:priority:durability:title:
          asprintf(&buffer,"1:%d:%d:%d%d:%d%d:%d:%d:%s:",item->channel->Number(),tm_t->tm_mday,starthh,startmm,stophh,stopmm,Setup.DefaultPriority,Setup.DefaultLifetime,item->channel->Name());
          timer=new cTimer(false,false);
          if(timer->Parse(buffer))
              free(buffer);
      }
      cTimer *t = Timers.GetTimer(timer);
      if (EPGSearchConfig.onePressTimerCreation == 0 || t || !item->event || (!t && item->event && item->event->StartTime() - (Setup.MarginStart+2) * 60 < time(NULL))) 
      {
	  if (t)
	  {
	      delete timer;
	      timer = t;      
	  }
	  timer->SetFlags(tfActive);
#if VDRVERSNUM && VDRVERSNUM >= 10331
	  if (EPGSearchConfig.useVDRTimerEditMenu)
	      return AddSubMenu(new cMenuEditTimer(timer, !t));
	  else
#endif
	      return AddSubMenu(new cMenuMyEditTimer(timer, !t, item->event, item->channel));
      }
      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
	  if (HasSubMenu())
	      CloseSubMenu();
	  if (Update())
	      Display();
	  SetHelpKeys();
      }
  }
  return osContinue;
}

bool cMenuWhatsOnSearch::Update(void)
{
  bool result = false;
  for (cOsdItem *item = First(); item; item = Next(item)) {
      if (item->Selectable() && ((cMenuMyScheduleItem *)item)->Update())
         result = true;
      }
  return result;
}

eOSState cMenuWhatsOnSearch::Commands(eKeys Key)
{
    if (HasSubMenu() || Count() == 0)
	return osContinue;

    cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current());
    if (mi) 
    {
	if (!mi->event) 
	{
	    if (Key == k3)
		return Switch();
	    else if (Key == k2)
		return Record();
	    else
		return osContinue;
	}
        cMenuSearchCommands *menu;
        eOSState state = AddSubMenu(menu = new cMenuSearchCommands(tr("EPG Commands"), mi->event, true));
        if (Key != kNone)
	    state = menu->ProcessKey(Key);
        return state;
    }
    return osContinue;
}

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

void cMenuWhatsOnSearch::SetHelpKeys()
{
    cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current());
    bool hasTimer = item && item->Selectable() && item->timerMatch == tmFull;

    showMode nextShowMode = GetNextMode();    
    char* szButtonGreen = EPGSearchConfig.ShowModes[nextShowMode].GetDescription();
  if (toggleKeys==0)
      SetHelp((EPGSearchConfig.redkeymode==0?(hasTimer?tr("Button$Timer"):tr("Button$Record")):tr("Button$Commands")), szButtonGreen, tr("Button$Schedule"), EPGSearchConfig.bluekeymode==0?tr("Button$Switch"):tr("Button$Search"));
  else
      SetHelp((EPGSearchConfig.redkeymode==1?(hasTimer?tr("Button$Timer"):tr("Button$Record")):tr("Button$Commands")), (EPGSearchConfig.toggleGreenYellow==0?szButtonGreen:"<<"), (EPGSearchConfig.toggleGreenYellow==0?tr("Button$Schedule"):">>"), EPGSearchConfig.bluekeymode==1?tr("Button$Switch"):tr("Button$Search"));
}

eOSState cMenuWhatsOnSearch::Shift(int iMinutes)
{
    shiftTime += iMinutes;
    cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current());
    int TempChannel = currentChannel;
    if (mi) 
    {
	currentChannel = mi->channel->Number();
	scheduleChannel = Channels.GetByNumber(currentChannel);
    }
    LoadSchedules();
    Display();
    currentChannel = TempChannel;
    SetHelpKeys();
    return osContinue;
}

eOSState cMenuWhatsOnSearch::ShowSummary()
{
    if (Count())
    {
	const cEvent *ei = ((cMenuMyScheduleItem *)Get(Current()))->event;
	if (ei) 
	{
	    cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true);
	    if (channel)
		return AddSubMenu(new cMenuEventSearch(ei, channel->Number() != cDevice::CurrentChannel(), GetNextChannelWithEPG(-1), GetNextChannelWithEPG(1)));
	}
    }
    return osContinue;
}

const cChannel* cMenuWhatsOnSearch::GetNextChannelWithEPG(int direction)
{
    int currentOld = Current();
    int current = currentOld;
    do
    {	
	if (direction>0) current++; else current--;
	if (current<0 || current>=Count()) return NULL;
	cMenuMyScheduleItem* item = (cMenuMyScheduleItem *)Get(current);
	if (!item) return NULL;

	if (currentOld == current) // no move
	    return NULL;
	if (item->Selectable() && item->event)
	    return item->channel;
    }
    while(true);
}

void cMenuWhatsOnSearch::MoveToChannelWithEPG(int direction)
{
    
    const cChannel* ch = NULL;
    do
    {
	int currentOld = Current();
	if (direction>0)
	    CursorDown();
	else
	    CursorUp();
	if (currentOld == Current()) // no move
	    return;
	const cEvent *event = ((cMenuMyScheduleItem *)Get(Current()))->event;	
	if (event)
	    return;
	else
	    ch = ((cMenuMyScheduleItem *)Get(Current()))->channel;
    }
    while(ch);
}


eOSState cMenuWhatsOnSearch::ProcessKey(eKeys Key)
{
    exitToMainMenu = 0;
    if (!HasSubMenu() && Key == kBack)
    {
	exitToMainMenu = 1;
	return osBack;
    }

    bool HadSubMenu = HasSubMenu();
    eOSState state = cOsdMenu::ProcessKey(Key);

    if (state == osUnknown) {
	switch (Key) {
	    case kFastRew:
		if(HasSubMenu()) 	     
		{
		    MoveToChannelWithEPG(-1);
		    return ShowSummary();
		}
		else
		    return Shift(-EPGSearchConfig.timeShiftValue);
	    case kFastFwd:
		if(HasSubMenu()) 	     
		{
		    MoveToChannelWithEPG(1);
		    return ShowSummary();
		}
		else
		    return Shift(EPGSearchConfig.timeShiftValue);
	    case kRecord:
	    case kRed:
		if(HasSubMenu()) {
                        state = Record();
                        break;
                     } 
      		if (Count())
		{
			if (EPGSearchConfig.redkeymode==toggleKeys)
				state = Record();
			else
			{
				cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current());
	                        if (mi) {
        	                  if (mi->event) 
				     return AddSubMenu(new cMenuSearchCommands(tr("EPG Commands"),mi->event));
				  else
				      return osContinue;
				}
			}
		}
		break;

	 case k0:
	     if(!HasSubMenu()) 
	     {
		 toggleKeys = 1 - toggleKeys;
		 SetHelpKeys();
	     }
	     state = osContinue;
	     break;
	 case k1...k9: return Commands(Key);
	 case kYellow: 
	     if(HasSubMenu()) 	     
	     {
		 MoveToChannelWithEPG(1);
		 return ShowSummary();
	     }
	     else if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0))
	     {
		 cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current());
		 if (mi && mi->channel)
		 {
		     const cSchedule *Schedule = schedules->GetSchedule(mi->channel->GetChannelID());
		     if (Schedule)
		     {
			 time_t now = time(NULL);
			 bool hasFutureEvents = false;
			 for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e))
			     if (e->StartTime() > now)
			     {
				 hasFutureEvents = true;
				 break;
			     }
			 if (!hasFutureEvents)
			     return osContinue;
		     }
		     else
			 return osContinue;
		 }
		 state = osBack;
		 // continue with kGreen
	     }
	     else
		 return Shift(EPGSearchConfig.timeShiftValue);
	 case kGreen:  
	 {
	     if(HasSubMenu()) 	     
	     {
		 MoveToChannelWithEPG(-1);
		 return ShowSummary();
	     }
	     else if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0))
	     {
		 if (Key == kYellow)
		     currentShowMode = showNow;
		 else
		     currentShowMode = GetNextMode();
		 cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current());
		 if (mi) 
		 {
		     currentChannel = mi->channel->Number();
		     scheduleChannel = Channels.GetByNumber(currentChannel);
		 }
	     }
	     else
		 return Shift(-EPGSearchConfig.timeShiftValue);
	 }
	 break;
	 case kBlue:   
	     if (HasSubMenu())
		 return Switch();
	     if (EPGSearchConfig.bluekeymode==toggleKeys)
		 return Switch();
	     else
		 return ExtendedSearch();
	   break;
	 case kOk:
	 {
	     cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current());
	     if (!mi->event) // no EPG, so simply switch to channel
		 return Switch();
	     else
		 return ShowSummary();
	 }
	 break;
       default:      break;
     }
    }
    if (!HasSubMenu()) 
    {
	if ((HadSubMenu || gl_TimerProgged) && Update())
	{
	    if (gl_TimerProgged) // when using epgsearch's timer edit menu, update is delayed because of SVDRP
	    {
		gl_TimerProgged = 0;
		SetHelpKeys();
	    }
	    Display();
	}
	if (Key != kNone)
	    SetHelpKeys();
    }
    
    return state;
}


