#
#  MerlinEPGCenter E2 Plugin
#
#  $Id: MerlinEPGCenter.py,v 1.0 2011-02-14 21:53:00 shaderman Exp $
#
#  Coded by Shaderman (c) 2011
#  Support: www.dreambox-tools.info
#
#  This plugin is licensed under the Creative Commons 
#  Attribution-NonCommercial-ShareAlike 3.0 Unported 
#  License. To view a copy of this license, visit
#  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
#  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
#
#  Alternatively, this plugin may be distributed and executed on hardware which
#  is licensed by Dream Property GmbH.

#  This plugin is NOT free software. It is open source, you are allowed to
#  modify it (if you keep the license), but it may not be commercially 
#  distributed other than under the conditions noted above.
#


# for localized messages
NUM_EPG_TABS = 5 # 0 based
NUM_CONFIG_TABS = 3 # 0 based

STYLE_SINGLE_LINE = "0"
STYLE_SHORT_DESCRIPTION = "1"

MODE_TV = 0
MODE_RADIO = 1

TIMER_TYPE_RECORD = 0
TIMER_TYPE_AUTOTIMER = 1

LIST_MODE_TIMER = 0
LIST_MODE_AUTOTIMER = 1

TAB_TEXT_EPGLIST = (_("Now"), _("Upcoming"), _("Single"), _("Prime Time"), _("Timer"), _("Search"))
TAB_TEXT_CONFIGLIST = [_("General"), _("Lists"), _("Event Info"), _("Keys"), "", ""]
	
# PYTHON IMPORTS
from time import localtime, strftime, mktime, time
from datetime import datetime

# ENIGMA IMPORTS
from Components.ActionMap import ActionMap, NumberActionMap
from Components.Button import Button
from Components.config import config, NoSave, ConfigText, KEY_0, KEY_LEFT, KEY_RIGHT, KEY_OK, KEY_DELETE, KEY_BACKSPACE
from Components.ConfigList import ConfigList
from Components.Label import Label, MultiColorLabel
from Components.MenuList import MenuList
from Components.Pixmap import Pixmap, MultiPixmap
from Components.ProgressBar import ProgressBar
from Components.Renderer.MiniTV import MiniTV # MiniTV - Merlin only
from Components.TimerSanityCheck import TimerSanityCheck
from Components.UsageConfig import preferredTimerPath
from Components.VideoWindow import VideoWindow
from Components.VolumeBar import VolumeBar
from enigma import eServiceReference, eServiceCenter, eEPGCache, getDesktop, eSize, eTimer, fontRenderClass, ePoint, gFont, gPixmapPtr
from enigma import iServiceInformation # MiniTV - Merlin only
from GlobalActions import globalActionMap
from math import fabs
import NavigationInstance
from RecordTimer import AFTEREVENT, RecordTimerEntry
from Screens.EpgSelection import EPGSelection
from Screens.Screen import Screen
from Screens.TimerEdit import TimerEditList, TimerSanityConflict
from Screens.TimerEntry import TimerEntry, TimerLog
from ServiceReference import ServiceReference
from skin import parseColor, loadSkin
from Tools.BoundFunction import boundFunction
from Tools.Directories import resolveFilename, SCOPE_CURRENT_PLUGIN, SCOPE_HDD
from Tools.LoadPixmap import LoadPixmap

# OWN IMPORTS
from Components.Sources.ServiceEventReference import ServiceEventReference # MiniTV - Merlin only
from Components.VolumeControl import VolumeControl
from ConfigTabs import KEEP_OUTDATED_TIME, ConfigBaseTab, ConfigGeneral, ConfigListSettings, ConfigEventInfo, ConfigKeys, SKINDIR, SKINLIST, STYLE_SIMPLE_BAR, STYLE_PIXMAP_BAR, STYLE_MULTI_PIXMAP, STYLE_PERCENT_TEXT, STYLE_SIMPLE_BAR_LIST_OFF, STYLE_PIXMAP_BAR_LIST_OFF, STYLE_MULTI_PIXMAP_LIST_OFF, STYLE_PERCENT_TEXT_LIST_OFF
from EpgActions import MerlinEPGActions
from EpgCenterList import EpgCenterList, EpgCenterTimerlist, MODE_FHD, MODE_HD, MODE_XD, MODE_SD, MULTI_EPG_NOW, MULTI_EPG_NEXT, SINGLE_EPG, MULTI_EPG_PRIMETIME, TIMERLIST, EPGSEARCH_HISTORY, EPGSEARCH_RESULT, EPGSEARCH_MANUAL, UPCOMING
from EpgTabs import EpgBaseTab, EpgNowTab, EpgNextTab, EpgSingleTab, EpgPrimeTimeTab, EpgTimerListTab, EpgSearchHistoryTab, EpgSearchManualTab, EpgSearchResultTab
from HelperFunctions import PiconLoader, findDefaultPicon, ResizeScrollLabel, BlinkTimer, LIST_TYPE_EPG, LIST_TYPE_UPCOMING, TimerListObject, EmbeddedVolumeControl
from SkinFinder import SkinFinder
from Components.ServiceRecordingSettings import ServiceRecordingSettings # Dr. Best ServiceRecordingSettings

# check for Autotimer support
try:
	from Plugins.Extensions.AutoTimer.plugin import autotimer
	from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer, XML_CONFIG
	from Plugins.Extensions.AutoTimer.AutoTimerConfiguration import buildConfig
	from Plugins.Extensions.AutoTimer.AutoTimerComponent import preferredAutoTimerComponent
	from Plugins.Extensions.AutoTimer.AutoTimerEditor import AutoTimerEditor, weekdays
	from Plugins.Extensions.AutoTimer.AutoTimerOverview import AutoTimerPreview
	from Plugins.Extensions.AutoTimer.AutoTimerImporter import AutoTimerImporter
	AUTOTIMER = True
	# now we need a ChoiceBox to select between timer and autotimer on green button
	from Screens.ChoiceBox import ChoiceBox
except ImportError:
	AUTOTIMER = False

# check for IMDb support
try:
	from Plugins.Extensions.IMDb.plugin import IMDB
	IMDB_INSTALLED = True
except ImportError:
	IMDB_INSTALLED = False

# check for YTTrailer support
try:
	from Plugins.Extensions.YTTrailer.plugin import YTTrailerList
	YTTRAILER_INSTALLED = True
except ImportError:
	YTTRAILER_INSTALLED = False
	

class MerlinEPGCenter(TimerEditList, MerlinEPGActions, EmbeddedVolumeControl):
	(skinFile, skinList) = SkinFinder.getSkinData(SKINLIST, SKINDIR, config.plugins.merlinEpgCenter.skin.value)
	if skinFile is not None:
		if config.plugins.merlinEpgCenter.skin.value != skinFile:
			config.plugins.merlinEpgCenter.skin.value = skinFile
			config.plugins.merlinEpgCenter.skin.save()
		config.plugins.merlinEpgCenter.skinSelection.setChoices(skinList, default = skinFile)
		loadSkin(skinFile, "")
		
	desktopSize = getDesktop(0).size()
	if desktopSize.width() == 1920:
		videoMode = MODE_FHD
	elif desktopSize.width() == 1280:
		videoMode = MODE_HD
	elif desktopSize.width() == 1024:
		videoMode = MODE_XD
	else: # SD/fallback
		videoMode = MODE_SD
		
	# TimerEditList timer key states
	# EMPTY = 0
	# ENABLE = 1
	# DISABLE = 2
	ADD_TIMER = 3
	REMOVE_TIMER = 4

	def __init__(self, session, servicelist, currentBouquet, bouquetList, currentIndex, startTab = None, doSearch = False):
		Screen.__init__(self, session)
		MerlinEPGActions.__init__(self) # note: this overwrites TimerEditList.["actions"]
		EmbeddedVolumeControl.__init__(self)
		
		self.session = session
		self.servicelist = servicelist
		self.currentBouquet = currentBouquet # eServiceReference of the current bouquet
		self.currentBouquetIndex = currentIndex # current bouquet index from InfoBar
		self.bouquetList = bouquetList # a list of tuples of all bouquets (Name, eServicereference)
		self.startTab = startTab
		self.doSearch = doSearch
		
		from Screens.InfoBar import InfoBar
		self.infoBarInstance = InfoBar.instance
		self.epgcache = eEPGCache.getInstance()
		
		self.piconLoader = PiconLoader()
		if config.plugins.merlinEpgCenter.piconSize.value == "0":
			self.piconSize = eSize(50,30)
		else:
			self.piconSize = eSize(100,60)
		
		self.blinkTimer = BlinkTimer(session)
		
		self.listStyle = config.plugins.merlinEpgCenter.listStyle.value
		
		# check Merlin 2 feature "Event tuner check in EPG list"
		# http://www.dreambox-tools.info/thread.php?postid=31822#post31822
		try:
			if config.merlin2.show_event_not_available.value:
				from Components.EpgList import EPGList
				self.epgList = EPGList(timer = self.session.nav.RecordTimer)
			else:
				self.epgList = None
		except KeyError:
			self.epgList = None
			
		# needed stuff for timerlist
		self.autoTimerPixmapLarge = None
		self.removeAutoTimerInstance = False
		self.timerListMode = LIST_MODE_TIMER
		list = [ ]
		self.list = list # TimerEditList property, needed
		
		self.key_green_choice = self.EMPTY
		self.key_red_choice = self.EMPTY # from TimerEditList
		self.key_yellow_choice = self.EMPTY # from TimerEditList
		self.key_blue_choice = self.EMPTY # from TimerEditList

		self["key_red"] = Button(" ") # from TimerEditList
		self["key_green"] = Button(" ") # from TimerEditList
		self["key_yellow"] = Button(" ") # from TimerEditList
		self["key_blue"] = Button(" ") # from TimerEditList
		
		self["tabbar"] = MultiPixmap()
		self["tabBackground"] = Pixmap()
		self["upcoming"] = EpgCenterList(self.blinkTimer, LIST_TYPE_UPCOMING, self.videoMode, self.piconLoader, bouquetList, currentIndex, self.piconSize, self.listStyle, self.epgList)
		self["upcoming"].mode = UPCOMING
		self["upcomingSeparator"] = Pixmap()
		self["list"] = EpgCenterList(self.blinkTimer, LIST_TYPE_EPG, self.videoMode, self.piconLoader, bouquetList, currentIndex, self.piconSize, self.listStyle, self.epgList)
		self._timerlist = EpgCenterTimerlist(list, self.videoMode, self.piconLoader, self.piconSize, self.listStyle)
		self["timerlist"] = self._timerlist
		self["eventInfoSeparator"] = Pixmap()
		self["picon"] = Pixmap()
		self["serviceName"] = Label("")
		self["eventTitle"] = Label("")
		self["beginTime"] = Label("")
		self["eventProgress"] = ProgressBar()
		self.progressPixmap = None
		self["eventProgressImage"] = MultiPixmap()
		self["eventProgressText"] = Label("")
		self["endTime"] = Label("")
		self["duration"] = Label("")
		self["remaining"] = MultiColorLabel()
		self["isRecording"] = Pixmap()
		self["description"] = Label("")
		self["bouquet"] = Label("")
		self["videoPicture"] = VideoWindow(decoder = 0, fb_width = self.desktopSize.width(), fb_height = self.desktopSize.height())
		self["volume"] = VolumeBar()
		self["mute"] = Pixmap()
		
		# MiniTV - Merlin only
		self["ServiceEventReference"] = ServiceEventReference()
		self.miniTvRenderInstance = None
		
		self.historyList = config.plugins.merlinEpgCenter.searchHistory.value
		self["history"] = MenuList(self.historyList)
		
		self["searchLabel"] = Label(_("Search for:"))
		self.searchField = NoSave(ConfigText(default = "", fixed_size = False))
		self.searchList = [("", self.searchField)]
		self["search"] = ConfigList(self.searchList, session = session)
		
		self["settings"] = ConfigList([], session = session)
		ConfigBaseTab.settingsWidget = self["settings"]
		
		self["infoText"] = ResizeScrollLabel("")
		self.infoTextShown = False
		
		self.widgetFontSizes = []
		
		self.initTabLabels(TAB_TEXT_EPGLIST)
		
		self.getPrimeTime()
		self.initEpgBaseTab()
		
		if config.plugins.merlinEpgCenter.selectRunningService.value:
			self.selectRunningService = True
		else:
			self.selectRunningService = False
			
		self.lastMultiEpgIndex = None
		self.showOutdated = False
		self.hideOutdated = False
		self.numNextEvents = None
		self.configTabsShown = False
		self.configEditMode = False
		self.oldMode = None
		self.currentMode = None
		
		self.onLayoutFinish.append(self.startRun)
		self.onShown.append(self.setListPixmaps)
		self.onShown.append(self.setTabs)
		self.onShown.append(self.setBouquetName)
		
		# MiniTV - Merlin only
		self.onShown.append(self.getMiniTvRenderInstance)

	############################################################################################
	# INITIALISATION & CLEANUP
	
	def startRun(self):
		self.getWidgetSizes()
		self.searchField.help_window.hide()
		self.hideWidgets()
		
		# store the current minute for list refreshs
		t = localtime(time())
		self.oldTime = "%02d" % t.tm_min
		
		# used to wait another global timer tick (1 second) before updating the epg list
		# this is needed because we're using the global Clock() timer which can differ up to 1 second and
		# could result in a time different between the clock widget and the time shown in the epg list
		self.delayTick = True
		
		# get notifications from the global timer every second to refresh lists on time change
		self.clockTimer = self.session.screen["CurrentTime"].clock_timer
		self.clockTimer_conn = self.clockTimer.timeout.connect(self.checkTimeChange)
		
		# Initialise the blink timer if there's already a recording running
		self.blinkTimer.gotRecordEvent(None, None)
		
		self.session.nav.RecordTimer.on_state_change.append(self.onStateChange)
		
		self.blinkTimer.appendList(self["list"])
		self.blinkTimer.appendList(self["upcoming"])
		self.setEventPiconBlinkState_conn = self.blinkTimer.timer.timeout.connect(self.setEventPiconBlinkState)
		self.setRecordingBlinkState_conn = self.blinkTimer.timer.timeout.connect(self.setRecordingBlinkState)
		
		self["list"].onSelectionChanged.append(self.onListSelectionChanged)
		self["timerlist"].onSelectionChanged.append(self.onListSelectionChanged)
		
		self.configTabObjectList = []
		self.configTabObjectList.append(ConfigGeneral())
		self.configTabObjectList.append(ConfigListSettings())
		self.configTabObjectList.append(ConfigEventInfo())
		self.configTabObjectList.append(ConfigKeys())
		
		# similar events
		self.similarTimer = eTimer()
		self.getSimilarEvents_conn = self.similarTimer.timeout.connect(self.getSimilarEvents)
		self.getUpcomingEvents_conn = self.similarTimer.timeout.connect(self.getUpcomingEvents)
		self.similarShown = False
		
		searchFieldPos = self["search"].getPosition()
		self["search"].getCurrent()[1].help_window.instance.move(ePoint(searchFieldPos[0], searchFieldPos[1] + 40))
		
		self.setStartTab(self.startTab, self.doSearch)
		self.setBouquetName()
		
		self.savedVolUp = None
		self.savedVolDown = None
		self.savedVolMute = None
		self.savedMuteDialog = None
		
		self.setNotifier()
		
	def suspend(self):
		self.suspendedInMode = self.infoBarInstance.servicelist.mode
		self.session.nav.RecordTimer.on_state_change.remove(self.onStateChange)
		self.clockTimer_conn = None
		# reset the timer tab to Timer
		if self.timerListMode == LIST_MODE_AUTOTIMER:
			self.timerListMode = LIST_MODE_TIMER
			self["tab_text_%d" % TIMERLIST].setText(_("Timer"))
			
		if config.plugins.merlinEpgCenter.embeddedVolume.value:
			self.unsetVolumeControl()
			self.savedMuteDialog = VolumeControl.instance.muteDialog
			if self.getIsMuted():
				self.savedMuteDialog.show()
				
		if self.blinkTimer.getIsRunning():
			self["isRecording"].hide()
			
		self.blinkTimer.suspend()
		
		if self.similarShown:
			self.keyRed(forceHideSimilar = True)
			
		if self.currentMode > NUM_EPG_TABS:
			config.plugins.merlinEpgCenter.lastUsedTab.value = NUM_EPG_TABS
		else:
			config.plugins.merlinEpgCenter.lastUsedTab.value = self.currentMode
		config.plugins.merlinEpgCenter.save()
			
	def resume(self):
		# MiniTV - Merlin only
		if self.infoBarInstance.pipShown(): # hide pip if pip was active
			self.infoBarInstance.showPiP()
			
		# reset the tab text color of the last tab before suspending
		lastTab = config.plugins.merlinEpgCenter.lastUsedTab.value
		self["tab_text_%d" % lastTab].instance.setForegroundColor(parseColor("#ffffff")) # inactive
		
		# reread bouquet information if TV or radio mode was changed while we were suspended
		if self.suspendedInMode is not self.infoBarInstance.servicelist.mode:
			self.updateBouquets()
			
		if config.plugins.merlinEpgCenter.embeddedVolume.value:
			VolumeControl.instance.muteDialog = self.savedMuteDialog
			self.setVolumeControl()
			self.setMutePixmap()
			if self.getIsMuted():
				self.savedMuteDialog.hide()
				
		self.getPrimeTime()
		self.session.nav.RecordTimer.on_state_change.append(self.onStateChange)
		self.clockTimer_conn = self.clockTimer.timeout.connect(self.checkTimeChange)
		self.checkTimeChange()
		self.blinkTimer.resume()
		
	############################################################################################
	# TAB STUFF
	
	def setStartTab(self, startTab, doSearch):
		if doSearch:
			lastUsedTab = config.plugins.merlinEpgCenter.lastUsedTab.value
			self["tab_text_%d" % lastUsedTab].instance.setForegroundColor(parseColor("#ffffff")) # inactive
			self.oldMode = EPGSEARCH_HISTORY
			self.currentMode = EPGSEARCH_HISTORY
			self.epgTabObjectList[self.oldMode].hide()
			self.epgTabObjectList[self.currentMode].show()
			
		if startTab is not None:
			if self.currentMode != startTab:
				self.oldMode = self.currentMode
				self.currentMode = startTab
		else:
			if config.plugins.merlinEpgCenter.rememberLastTab.value:
				self.currentMode = config.plugins.merlinEpgCenter.lastUsedTab.value
			else:
				self.currentMode = 0
		self.setMode(doSearch = doSearch)
		
		if config.plugins.merlinEpgCenter.selectRunningService.value and (self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME):
			self.setSelectionToRunningService()
			self.setBouquetName()
			
	def initEpgBaseTab(self):
		# set ourself, the action map and prime time
		EpgBaseTab.parentInstance	= self
		EpgBaseTab.primeTime		= self.primeTime
		
		self.epgTabObjectList = []
		self.epgTabObjectList.append(EpgNowTab(self["list"]))
		self.epgTabObjectList.append(EpgNextTab(self["list"]))
		self.epgTabObjectList.append(EpgSingleTab(self["list"]))
		self.epgTabObjectList.append(EpgPrimeTimeTab(self["list"]))
		self.epgTabObjectList.append(EpgTimerListTab(self["timerlist"]))
		self.epgTabObjectList.append(EpgSearchHistoryTab(self["history"]))
		self.epgTabObjectList.append(EpgSearchResultTab(self["list"]))
		self.epgTabObjectList.append(EpgSearchManualTab(self["search"], self["searchLabel"]))
		
	def releaseEpgBaseTab(self):
		EpgBaseTab.parentInstance	= None
		EpgBaseTab.primeTime		= None
		
	def initTabLabels(self, tabList):
		i = 0
		while i <= NUM_EPG_TABS:
			if (i == MULTI_EPG_PRIMETIME) and config.plugins.merlinEpgCenter.showPrimeTimeValue.value:
				hours = str(config.plugins.merlinEpgCenter.primeTime.value[0])
				minutes = str(config.plugins.merlinEpgCenter.primeTime.value[1])
				timeString = hours + ":" + minutes
				self["tab_text_%d" % MULTI_EPG_PRIMETIME] = Label(timeString)
			else:
				self["tab_text_%d" % i] = Label(tabList[i])
			i += 1
			
	def setTabText(self, tabList):
		i = 0
		while i <= NUM_EPG_TABS:
			if (not self.configTabsShown) and (i == MULTI_EPG_PRIMETIME) and config.plugins.merlinEpgCenter.showPrimeTimeValue.value:
				hours = str(config.plugins.merlinEpgCenter.primeTime.value[0])
				minutes = str(config.plugins.merlinEpgCenter.primeTime.value[1])
				timeString = hours + ":" + minutes
				self["tab_text_%d" % MULTI_EPG_PRIMETIME].setText(timeString)
			else:
				self["tab_text_%d" % i].setText(tabList[i])
			i += 1
			
	def setTabs(self):
		if self.configTabsShown:
			numTabs = NUM_CONFIG_TABS
		else:
			numTabs = NUM_EPG_TABS
			
		# set tab text color
		if self.currentMode > numTabs:
			self["tabbar"].setPixmapNum(numTabs) # last tab
		else:
			self["tabbar"].setPixmapNum(self.currentMode)
			
		if self.oldMode != None:
			if self.oldMode >= numTabs:
				self["tab_text_%d" % numTabs].instance.setForegroundColor(parseColor("#ffffff")) # inactive
			else:
				self["tab_text_%d" % self.oldMode].instance.setForegroundColor(parseColor("#ffffff")) # inactive
				
		if self.currentMode >= numTabs:
			self["tab_text_%d" % numTabs].instance.setForegroundColor(parseColor(config.plugins.merlinEpgCenter.tabTextColorSelected.value)) # active
		else:
			self["tab_text_%d" % self.currentMode].instance.setForegroundColor(parseColor(config.plugins.merlinEpgCenter.tabTextColorSelected.value)) # active
			
	############################################################################################
	# VOLUME CONTROL
	
	def toggleEmbeddedVolume(self, configElement = None):
		if configElement.value:
			self.setVolumeControl()
		else:
			self.unsetVolumeControl()
			
		self.setMutePixmap()
		
	def setVolumeControl(self):
		global globalActionMap
		self.savedVolUp = globalActionMap.actions["volumeUp"]
		self.savedVolDown = globalActionMap.actions["volumeDown"]
		self.savedVolMute = globalActionMap.actions["volumeMute"]
		globalActionMap.actions["volumeUp"] = self.volUp
		globalActionMap.actions["volumeDown"] = self.volDown
		globalActionMap.actions["volumeMute"] = self.volMute
		self.setMutePixmap()
		
	def unsetVolumeControl(self):
		if self.savedVolUp == None:
			return
		global globalActionMap
		globalActionMap.actions["volumeUp"] = self.savedVolUp
		globalActionMap.actions["volumeDown"] = self.savedVolDown
		globalActionMap.actions["volumeMute"] = self.savedVolMute
		
 	############################################################################################
	# MINITV
	
	def getMiniTvRenderInstance(self):
		for r in self.renderer:
			if isinstance(r, MiniTV):
				self.miniTvRenderInstance = r
				if self.miniTvRenderInstance.timer_connection is not None:
					self.miniTvRenderInstance.timer_connection = None
				break
		self.setMiniTv()
		
	def setMiniTvService(self):
		if config.merlin2.minitv.value:
			service = self.session.nav.getCurrentService()
			if service:
				info = service.info()
				if info:
					cur = self["list"].getCurrent()
					if cur:
						refstr = info.getInfoString(iServiceInformation.sServiceref)
						self["ServiceEventReference"].newServices(eServiceReference(cur[2]), eServiceReference(refstr))
					else:
						refstr = NavigationInstance.instance.getCurrentlyPlayingServiceReference()
						self["ServiceEventReference"].newServices(refstr, refstr)
						
	def setMiniTv(self, configElement = None):
		if config.plugins.merlinEpgCenter.showMiniTV.value:
			if self.miniTvRenderInstance.timer_connection is None:
				self.miniTvRenderInstance.timer_connection = self.miniTvRenderInstance.timer.timeout.connect(self.miniTvRenderInstance.activatePiP)
		else:
			if self.miniTvRenderInstance.timer_connection is not None:
				self.miniTvRenderInstance.timer_connection = None
				self.miniTvRenderInstance.changed(None)
		self.setDescriptionSize()
		
	############################################################################################
	# MISC FUNCTIONS
	
	def setProgressbarStyle(self, configElement = None):
		if not config.plugins.merlinEpgCenter.showEventInfo.value:
			return
			
		if config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_SIMPLE_BAR or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_SIMPLE_BAR_LIST_OFF:
			self["eventProgressImage"].hide()
			self["eventProgress"].instance.setPixmap(gPixmapPtr())
			self["eventProgressText"].hide()
			self["eventProgress"].show()
		elif config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PIXMAP_BAR or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PIXMAP_BAR_LIST_OFF:
			self["eventProgressImage"].hide()
			self["eventProgressText"].hide()
			if self.progressPixmap == None:
				pixmapPath = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/MerlinEPGCenter/images/EventProgress.png")
				self.progressPixmap = LoadPixmap(cached = False, path = pixmapPath)
			self["eventProgress"].instance.setPixmap(self.progressPixmap)
			self["eventProgress"].show()
		elif config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_MULTI_PIXMAP or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_MULTI_PIXMAP_LIST_OFF:
			self["eventProgress"].hide()
			self["eventProgressText"].hide()
			self["eventProgressImage"].show()
		elif config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PERCENT_TEXT or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PERCENT_TEXT_LIST_OFF:
			self["eventProgressImage"].hide()
			self["eventProgress"].instance.setPixmap(gPixmapPtr())
			self["eventProgress"].hide()
			self["eventProgressText"].show()
			
		# we need to reset the bar to draw correctly
		value = self["eventProgress"].getValue()
		self["eventProgress"].setValue(0)
		self["eventProgress"].setValue(value)
		
	def getSimilarEvents(self):
		if self.similarShown or self.configTabsShown or (self.currentMode != MULTI_EPG_NOW and self.currentMode != MULTI_EPG_NEXT and self.currentMode != SINGLE_EPG and self.currentMode != MULTI_EPG_PRIMETIME):
			return
			
		# get the selected entry
		cur = self["list"].getCurrent()
		# cur[1] = eventId, cur[2] = sRef
		if cur != None and cur[2] != "" and cur[1] != None:
			serviceList = self.epgcache.search(('R', 100, eEPGCache.SIMILAR_BROADCASTINGS_SEARCH, cur[2], cur[1]))
			knownSimilar = False
			if serviceList is not None and config.plugins.merlinEpgCenter.limitSearchToBouquetServices.value:
				for sRef in serviceList:
					if sRef[0] in EpgCenterList.allServicesNameDict:
						knownSimilar = True
						break
			elif serviceList is not None:
				knownSimilar = True
				
			if knownSimilar:
				self["key_red"].setText(_("Similar"))
				self["epgRedActions"].setEnabled(True)
			elif self["epgRedActions"].enabled:
				self["epgRedActions"].setEnabled(False)
		elif self["epgRedActions"].enabled:
			self["epgRedActions"].setEnabled(False)
				
	def getUpcomingEvents(self):
		size = int(config.plugins.merlinEpgCenter.numNextEvents.value)
		if size == 0 or self.configTabsShown or (self.currentMode != MULTI_EPG_NOW and self.currentMode != MULTI_EPG_NEXT and self.currentMode != MULTI_EPG_PRIMETIME and self.currentMode != EPGSEARCH_RESULT):
			if size > 0:
				self["upcoming"].setList([])
			return
			
		upcomingEvents = []
		cur = self["list"].getCurrent()
		if cur == None:
			return
			
		sRef		= cur[2]
		begin		= cur[3]
		duration	= cur[4]
		
		if sRef == None or begin == None or duration == None:
			nextEvent = -1
		else:
			nextEvent = self.epgcache.lookupEventTime(eServiceReference(sRef), begin + duration)
		
		if nextEvent == -1:
			self["upcoming"].setList([])
			return
			
		i = 0
		while (i < size) and nextEvent:
			data = (0, nextEvent.getEventId(), sRef, nextEvent.getBeginTime(), nextEvent.getDuration(), nextEvent.getEventName(), nextEvent.getShortDescription(), nextEvent.getExtendedDescription())
			upcomingEvents.append(data)
			nextEvent = self.epgcache.lookupEventTime(eServiceReference(sRef), nextEvent.getBeginTime() + nextEvent.getDuration())
			i += 1
				
		self["upcoming"].currentBouquetIndex = self.currentBouquetIndex
		self["upcoming"].setList(upcomingEvents)
		
	def hideWidgets(self):
		self["timerlist"].hide()
		self["list"].hide()
		self["settings"].hide()
		self["searchLabel"].hide()
		self["search"].hide()
		self["history"].hide()
		self["videoPicture"].hide()
		self["infoText"].hide()
		self["upcoming"].hide()
		self["upcoming"].instance.setSelectionEnable(0)
		self["upcomingSeparator"].hide()
		self["eventInfoSeparator"].hide()
		self["eventProgress"].hide()
		self["eventProgressImage"].hide()
		self["eventProgressText"].hide()
		self["isRecording"].hide()
		self["volume"].hide()
		self["mute"].hide()
		
	# get some widget sizes
	def getWidgetSizes(self):
		# self["list"]
		for (attrib, value) in self["list"].skinAttributes:
			if attrib == "size":
				self.listWidthMin, self.listHeightMin = [int(x) for x in value.split(",")]
		# self["tabBackground"] (this is used to determine the maximum list width)
		for (attrib, value) in self["tabBackground"].skinAttributes:
			if attrib == "size":
				self.listWidthMax, self.listHeightMax = [int(x) for x in value.split(",")]
		# self["upcomingSeparator"]
		for (attrib, value) in self["upcomingSeparator"].skinAttributes:
			if attrib == "position":
				self.upcomingSepPosX, self.upcomingSepPosY = [int(x) for x in value.split(",")]
			elif attrib == "size":
				self.separatorWidth, self.separatorHeight = [int(x) for x in value.split(",")]
		# self["beginTime"]
		for (attrib, value) in self["beginTime"].skinAttributes:
			if attrib == "font":
				font = [x for x in value.split(";")]
				self.widgetFontSizes.append(("beginTime", font[0], int(font[1])))
		# self["endTime"]
		for (attrib, value) in self["endTime"].skinAttributes:
			if attrib == "font":
				font = [x for x in value.split(";")]
				self.widgetFontSizes.append(("endTime", font[0], int(font[1])))
		# self["duration"]
		for (attrib, value) in self["duration"].skinAttributes:
			if attrib == "font":
				font = [x for x in value.split(";")]
				self.widgetFontSizes.append(("duration", font[0], int(font[1])))
		# self["remaining"]
		for (attrib, value) in self["remaining"].skinAttributes:
			if attrib == "font":
				font = [x for x in value.split(";")]
				self.widgetFontSizes.append(("remaining", font[0], int(font[1])))
		# self["description"]
		for (attrib, value) in self["description"].skinAttributes:
			if attrib == "position":
				self.descriptionPosX, self.descriptionPosY = [int(x) for x in value.split(",")]
			if attrib == "size":
				self.descriptionWidthMax, self.descriptionHeightMax = [int(x) for x in value.split(",")]
			if attrib == "font":
				font = [x for x in value.split(";")]
				self.widgetFontSizes.append(("description", font[0], int(font[1])))
		# self["videoPicture"]
		for (attrib, value) in self["videoPicture"].skinAttributes:
			if attrib == "position":
				self.videoPicturePosX, self.videoPicturePosY = [int(x) for x in value.split(",")]
		# self["infoText"]
		for (attrib, value) in self["infoText"].skinAttributes:
			if attrib == "font":
				font = [x for x in value.split(";")]
				self.widgetFontSizes.append(("infoText", font[0], int(font[1])))
				
	def setSkinFile(self, configElement = None):
		config.plugins.merlinEpgCenter.skin.value = configElement.getValue()
		
	def setUpcomingWidgets(self, configElement = None):
		self.numNextEvents = int(config.plugins.merlinEpgCenter.numNextEvents.value)
		
		if self.numNextEvents == 0 or self.currentMode == SINGLE_EPG or self.currentMode == TIMERLIST or self.currentMode == EPGSEARCH_HISTORY or self.currentMode == EPGSEARCH_MANUAL or self.currentMode == EPGSEARCH_RESULT:
			self["upcomingSeparator"].hide()
			self["upcoming"].hide()
			
			newHeight = self.listHeightMin / self["list"].itemHeight * self["list"].itemHeight
			
			if config.plugins.merlinEpgCenter.showEventInfo.value:
				self["list"].maxWidth = self.listWidthMin
				newListSize = eSize(self.listWidthMin, newHeight)
			else:
				self["list"].maxWidth = self.listWidthMax
				newListSize = eSize(self.listWidthMax, newHeight)
			self["list"].instance.resize(newListSize)
			return
		
		self.heightDiff = self["list"].itemHeight * self.numNextEvents
		border = 5
		
		# resize self["list"] and self["upcoming"]
		newHeight = ((self.listHeightMin - self.heightDiff - border) / self["list"].itemHeight) * self["list"].itemHeight
		
		if config.plugins.merlinEpgCenter.showEventInfo.value:
			self["list"].maxWidth = self.listWidthMin
			self["upcoming"].maxWidth = self.listWidthMin
			newListSize = eSize(self.listWidthMin, newHeight)
		else:
			self["list"].maxWidth = self.listWidthMax
			self["upcoming"].maxWidth = self.listWidthMax
			newListSize = eSize(self.listWidthMax, newHeight)
			
		newPosY = self.upcomingSepPosY - self.heightDiff
		self["list"].instance.resize(newListSize)
		self["upcoming"].setPosition(self.upcomingSepPosX, newPosY + self.separatorHeight + border)
		self["upcoming"].instance.resize(newListSize)
		
		# set self["upcomingSeparator"] position
		self["upcomingSeparator"].setPosition(self.upcomingSepPosX, newPosY)
		if not self.configTabsShown:
			self["upcoming"].show()
			self["upcomingSeparator"].show()
			
	def checkTimeChange(self):
		t = localtime(time())
		tmpTime = "%02d" % t.tm_min
		if self.oldTime != tmpTime:
			if self.delayTick:
				# delay one more tick (1 second)
				self.delayTick = False
				return
			self.oldTime = tmpTime
			if self.similarShown:
				self.epgTabObjectList[self.currentMode].refreshSimilar()
			else:
				self.epgTabObjectList[self.currentMode].refresh()
			self.delayTick = True
			
	def setNotifier(self):
		config.plugins.merlinEpgCenter.primeTime.addNotifier(self.getPrimeTime, initial_call = False)
		config.plugins.merlinEpgCenter.showVideoPicture.addNotifier(self.setVideoPicture, initial_call = False)
		config.plugins.merlinEpgCenter.showEventInfo.addNotifier(self.setEventInfo, initial_call = True)
		config.plugins.merlinEpgCenter.showInputHelp.addNotifier(self.setInputHelp, initial_call = False)
		config.plugins.merlinEpgCenter.listStyle.addNotifier(self.setListStyle, initial_call = False)
		config.plugins.merlinEpgCenter.skinSelection.addNotifier(self.setSkinFile, initial_call = True)
		config.plugins.merlinEpgCenter.numNextEvents.addNotifier(self.setUpcomingWidgets, initial_call = True)
		config.plugins.merlinEpgCenter.listItemHeight.addNotifier(self.setUpcomingWidgets, initial_call = False)
		config.plugins.merlinEpgCenter.listProgressStyle.addNotifier(self.setProgressbarStyle, initial_call = True)
		config.plugins.merlinEpgCenter.adjustFontSize.addNotifier(self.setFontSizes, initial_call = True)
		config.plugins.merlinEpgCenter.embeddedVolume.addNotifier(self.toggleEmbeddedVolume, initial_call = True)
		config.plugins.merlinEpgCenter.showMiniTV.addNotifier(self.setMiniTv, initial_call = False)
		
	def removeNotifier(self):
		self["list"].onSelectionChanged.remove(self.onListSelectionChanged)
		self["timerlist"].onSelectionChanged.remove(self.onListSelectionChanged)
		
		for configTabObject in self.configTabObjectList:
			configTabObject.removeNotifier()
			
		config.plugins.merlinEpgCenter.primeTime.removeNotifier(self.getPrimeTime)
		config.plugins.merlinEpgCenter.showVideoPicture.removeNotifier(self.setVideoPicture)
		config.plugins.merlinEpgCenter.showEventInfo.removeNotifier(self.setEventInfo)
		config.plugins.merlinEpgCenter.showInputHelp.removeNotifier(self.setInputHelp)
		config.plugins.merlinEpgCenter.listStyle.removeNotifier(self.setListStyle)
		config.plugins.merlinEpgCenter.skinSelection.removeNotifier(self.setSkinFile)
		config.plugins.merlinEpgCenter.numNextEvents.removeNotifier(self.setUpcomingWidgets)
		config.plugins.merlinEpgCenter.listItemHeight.removeNotifier(self.setUpcomingWidgets)
		config.plugins.merlinEpgCenter.listProgressStyle.removeNotifier(self.setProgressbarStyle)
		config.plugins.merlinEpgCenter.adjustFontSize.removeNotifier(self.setFontSizes)
		config.plugins.merlinEpgCenter.embeddedVolume.removeNotifier(self.toggleEmbeddedVolume)
		config.plugins.merlinEpgCenter.showMiniTV.removeNotifier(self.setMiniTv)
		
	def setListStyle(self, configElement = None):
		itemHeight = self.piconSize.height() + int(config.plugins.merlinEpgCenter.listItemHeight.value)
		
		self.listStyle = configElement.value
		if self.listStyle != STYLE_SINGLE_LINE:
			itemHeight += 24 # TODO this should depend on font height
			
		self["list"].changeHeight()
		self["upcoming"].changeHeight()
		if self.numNextEvents > 0:
			self.setUpcomingWidgets()
		self["timerlist"].changeHeight()
		
	def setFontSizes(self, configElement = None):
		diff = configElement.getValue()
		
		for widget, font, fontSize in self.widgetFontSizes:
			if widget == "infoText":
				self[widget].long_text.setFont(gFont(font, fontSize + diff))
			else:
				self[widget].instance.setFont(gFont(font, fontSize + diff))
			
	def getPrimeTime(self, configElement = None):
		now = localtime(time())
		dt = datetime(now.tm_year, now.tm_mon, now.tm_mday, config.plugins.merlinEpgCenter.primeTime.value[0], config.plugins.merlinEpgCenter.primeTime.value[1])
		self.primeTime = int(mktime(dt.timetuple()))
		EpgBaseTab.primeTime = self.primeTime
		
	def addTimer(self, timer):
		if self.currentMode == TIMERLIST:
			if self.timerListMode == LIST_MODE_TIMER:
				self.session.openWithCallback(self.finishedAdd, TimerEntry, timer)
			elif self.timerListMode == LIST_MODE_AUTOTIMER:
				self.addAutotimerFromString("", addNewTimer = True)
		else:
			self.session.openWithCallback(self.finishedAdd, TimerEntry, timer)
			
	def addTimerEntry(self):
		cur = self["list"].getCurrent()
		if cur == None or cur[1] == None or cur[2] == "":
			return
			
		# cur = ignoreMe, eventid, sRef, begin, duration, title, short, desc
		eit = cur[1]
		serviceref = ServiceReference(cur[2])
		begin = cur[3]
		end = cur[3] + cur[4]
		name = cur[5]
		description = cur[6]
		begin -= ServiceRecordingSettings.instance.getMarginBefore(serviceref.ref)
		end += ServiceRecordingSettings.instance.getMarginAfter(serviceref.ref)
		data = (begin, end, name, description, eit)
		# TimerEditList method
		self.addTimer(RecordTimerEntry(serviceref, checkOldTimers = True, dirname = preferredTimerPath(), *data))
		
	def timerChoice(self):
		choices = []
		choices.append((_("Record or zap timer"), TIMER_TYPE_RECORD))
		choices.append((_("AutoTimer timer"), TIMER_TYPE_AUTOTIMER))
		self.session.openWithCallback(self.cbTimerChoice, ChoiceBox, title = _("Please select a timer type to add:"), list = choices, keys=["green", "yellow"])
		
	def cbTimerChoice(self, result):
		if not result:
			return
		elif result[1] == TIMER_TYPE_RECORD:
			self.addTimerEntry()
		elif result[1] == TIMER_TYPE_AUTOTIMER:
			# cur = ignoreMe, eventid, sRef, begin, duration, title, short, desc
			cur = self["list"].getCurrent()
			if cur == None or cur[1] == None or cur[2] == "":
				return
				
			self.addAutotimerFromString(cur[5], addNewTimer = True, begin = cur[3], end = cur[3] + cur[4], sRef = ServiceReference(cur[2]))
			
	# TimerEditList function (overwritten to update the timer button state)
	def finishedAdd(self, answer):
		if answer[0]:
			entry = answer[1]
			simulTimerList = self.session.nav.RecordTimer.record(entry)
			if simulTimerList is not None:
				for x in simulTimerList:
					if x.setAutoincreaseEnd(entry):
						self.session.nav.RecordTimer.timeChanged(x)
				simulTimerList = self.session.nav.RecordTimer.record(entry)
				if simulTimerList is not None:
					self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList)
			self.updateState()
			
			cur = self["list"].getCurrent()
			if cur is not None:
				self.key_green_choice = self.ADD_TIMER
				self.setTimerButtonState(cur)
				self.setButtonText(timerAdded = True)
				self.getSimilarEvents()
				
	# TimerEditList function (overwritten to either edit a timer or AutoTimer timer)
	def openEdit(self):
		cur = self["timerlist"].getCurrent()
		if cur:
			if isinstance(cur, RecordTimerEntry):
				self.session.openWithCallback(self.finishedEdit, TimerEntry, cur)
			else: # AutoTimer entry
				autotimerEntry = None
				self.getAutoTimerInstance()
				
				# find the corresponding AutoTimer entry by id
				timerList = autotimer.getTimerList()
				for autotimerEntry in timerList:
					if autotimerEntry.getId() == cur.autoTimerId:
						break
						
				if autotimerEntry:
					self.session.openWithCallback(self.cbOpenEdit, AutoTimerEditor, autotimerEntry)
					
				self.deleteAutoTimerInstance()
				
	# TimerEditList function (overwritten to either edit a timer or AutoTimer timer)
	def showLog(self):
		cur = self["timerlist"].getCurrent()
		if cur:
			if isinstance(cur, RecordTimerEntry):
				self.session.openWithCallback(self.finishedEdit, TimerLog, cur)
			else:
				global autotimer
				self.getAutoTimerInstance()
				total, new, modified, timers, conflicts, similars = autotimer.parseEPG(simulateOnly = True)
				self.session.openWithCallback(self.cbAutoTimerPreview, AutoTimerPreview, timers)
				
	def cbAutoTimerPreview(self, ret):
		# clear the AutoTimer instance
		self.deleteAutoTimerInstance()
		
	def cbOpenEdit(self, ret):
		if ret:
			self.updateAutoTimerEntry(ret.getId(), ret)
			self.updateState()
			
	def fillAutoTimerList(self):
		self.list = []
		self.getAutoTimerInstance()
		timerList = autotimer.getTimerList()
		
		for autoTimer in timerList:
			obj = self.getTimerListObjectFromAutoTimer(autoTimer)
			self.list.extend([(obj, False)]) # extend the TimerEditList list
		self.deleteAutoTimerInstance()
		self["timerlist"].l.setList(self.list)
		
	def getTimerListObjectFromAutoTimer(self, autoTimer):
		now = localtime(time())
		if autoTimer.timespan is not None and autoTimer.timespan[0] is not None:
			timeSpan = autoTimer.getTimespanBegin()
			if timeSpan is not None:
				parts = timeSpan.split(":")
				dt = datetime(now.tm_year, now.tm_mon, now.tm_mday, int(parts[0]), int(parts[1]))
				begin = int(mktime(dt.timetuple()))
			else:
				begin = 0
				
			timeSpan = autoTimer.getTimespanEnd()
			if timeSpan is not None:
				parts = timeSpan.split(":")
				dt = datetime(now.tm_year, now.tm_mon, now.tm_mday, int(parts[0]), int(parts[1]))
				end = int(mktime(dt.timetuple()))
			else:
				end = 0
		else:
			dt = datetime(now.tm_year, now.tm_mon, now.tm_mday, 0, 0)
			end = begin = int(mktime(dt.timetuple()))
			
		if autoTimer.getEnabled() == "no":
			enabled = True
		else:
			enabled = False
			
		return TimerListObject(begin, end, "", autoTimer.getName(), int(autoTimer.getJustplay()), enabled, autoTimer.getId(), autoTimer.getMatch(), autoTimer.searchType, autoTimer.getCounter(), autoTimer.getCounterLeft(), autoTimer.destination, autoTimer.getServices(), autoTimer.getBouquets(), autoTimer.getIncludedDays(), autoTimer.getExcludedDays())
		
	# TimerEditList method. Overwritten to support AutoTimer timers
	def toggleDisabledState(self):
		cur = self["timerlist"].getCurrent()
		if cur and isinstance(cur, RecordTimerEntry):
			t = cur
			if t.disabled:
				print "try to ENABLE timer"
				t.enable()
				timersanitycheck = TimerSanityCheck(self.session.nav.RecordTimer.timer_list, cur)
				if not timersanitycheck.check():
					t.disable()
					print "Sanity check failed"
					simulTimerList = timersanitycheck.getSimulTimerList()
					if simulTimerList is not None:
						self.session.openWithCallback(self.finishedEdit, TimerSanityConflict, simulTimerList)
				else:
					print "Sanity check passed"
					if timersanitycheck.doubleCheck():
						t.disable()
			else:
				if t.isRunning():
					if t.repeated:
						list = (
							(_("Stop current event but not coming events"), "stoponlycurrent"),
							(_("Stop current event and disable coming events"), "stopall"),
							(_("Don't stop current event but disable coming events"), "stoponlycoming")
						)
						self.session.openWithCallback(boundFunction(self.runningEventCallback, t), ChoiceBox, title=_("Repeating event currently recording... What do you want to do?"), list = list)
				else:
					t.disable()
			self.session.nav.RecordTimer.timeChanged(t)
		else: # AutoTimer timer
			global autotimer
			self.getAutoTimerInstance()
			
			# find the corresponding AutoTimer entry by id
			timerList = autotimer.getTimerList()
			for autotimerEntry in timerList:
				if autotimerEntry.getId() == cur.autoTimerId:
					autotimerEntry.enabled = not autotimerEntry.enabled
					cur.disabled = not cur.disabled
					autotimer.writeXml()
					break
					
			self.deleteAutoTimerInstance()
			
		# refresh the list
		idx = self["timerlist"].getCurrentIndex()
		self["timerlist"].l.invalidateEntry(idx)
		self.updateState()
			
	# TimerEditList method. Overwritten to support AutoTimer timers
	def removeTimer(self, result):
		if not result:
			return
		list = self["timerlist"]
		cur = list.getCurrent()
		if cur and isinstance(cur, RecordTimerEntry):
			timer = cur
			timer.afterEvent = AFTEREVENT.NONE
			self.session.nav.RecordTimer.removeEntry(timer)
			self.refill()
			self.updateState()
		else: # AutoTimer timer
			global autotimer
			self.getAutoTimerInstance()
			
			# find the corresponding AutoTimer entry by id
			timerList = autotimer.getTimerList()
			for autotimerEntry in timerList:
				if autotimerEntry.getId() == cur.autoTimerId:
					autotimer.remove(cur.autoTimerId)
					autotimer.writeXml()
					break
					
			self.deleteAutoTimerInstance()
			
			# remove the timerlist entry
			idx = self["timerlist"].getCurrentIndex()
			self.list.pop(idx)
			self["timerlist"].l.setList(self.list)
			self["timerlist"].invalidate()
			
	def onListSelectionChanged(self):
		isAutoTimer = False
		
		if self.currentMode == TIMERLIST:
			sel = self["timerlist"].getCurrent()
			if sel is None:
				# TODO hide event info
				return
			else:
				# build a tuple similar to the one returned by epg lists. the leading 0 is needed to make the list equal
				# to the epg list's (make list entries without event id selectable)
				if isinstance(sel, RecordTimerEntry):
					cur = (0, sel.eit, str(sel.service_ref), sel.begin, sel.end - sel.begin, sel.name, sel.description, None, sel.service_ref.getServiceName())
				else: # AutoTimer
					isAutoTimer = True
					cur = (0, 0, str(sel.service_ref), sel.begin, sel.end - sel.begin, sel.name, "", None, "")
					
				remainBeginString = ""
				percent = 0
				duraString = "%d" % ((sel.end - sel.begin) / 60)
		else:
			# check for similar events if similar events aren't shown already
			if not self.similarShown and (self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME):
				self["key_red"].setText("")
				self.similarTimer.start(400, True)
				
			cur = self["list"].getCurrent()
			if cur is None:
				# TODO hide event info
				return
				
		# MiniTV - Merlin only
		self.setMiniTvService()
		
		# use variable names to make the code more readable
		if self.currentMode == TIMERLIST:
			(ignoreMe, eventid, sRef, begin, duration, title, shortDesc, description, serviceName) = cur
			if isAutoTimer:
				dest = sel.destination or resolveFilename(SCOPE_HDD)
				
				description = ''.join([_("Match title:"), " ", sel.match, "\n"])
				if len(sel.services):
					serv = " "
					for service in sel.services:
						serv = ''.join([serv, ServiceReference(service).getServiceName(), ", "])
					serv = serv.rstrip(", ")
					description = ''.join([description, _("Services:"), " ", serv, "\n"])
				if len(sel.bouquets):
					bouq = " "
					for bouquet in sel.bouquets:
						bouq = ''.join([bouq, ServiceReference(bouquet).getServiceName(), ", "])
					bouq = bouq.rstrip(", ")
					description = ''.join([description, _("Bouquets:"), " ", bouq, "\n"])
				if len(sel.includedDays):
					days = ""
					for day in sel.includedDays:
						days = ''.join([days, [y[1] for x,y in enumerate(weekdays) if y[0] == day][0], ", "])
					days = days.rstrip(", ")
					description = ''.join([description, _("Included days:"), " ", days, "\n"])
				if len(sel.excludedDays):
					days = ""
					for day in sel.excludedDays:
						days = ''.join([days, [y[1] for x,y in enumerate(weekdays) if y[0] == day][0], ", "])
					days = days.rstrip(", ")
					description = ''.join([description, _("Excluded days:"), " ", days, "\n"])
				description = ''.join([description, _("Record a maximum of x times:"), " ", str(sel.counter), "\n",
					_("Amount of recordings left:"), " ", str(sel.counterLeft), "\n",
					_("Search type:"), " ", sel.searchType, "\n",
					_("Location:"), " ", dest.rstrip('/')
					])
		else:
			(ignoreMe, eventid, sRef, begin, duration, title, shortDesc, description) = cur
		
		# set timer button state
		self.setTimerButtonState(cur)
		
		self.setEventViewPicon(cur, isAutoTimer)
		
		if isAutoTimer:
			serviceName = "AutoTimer"
		elif sRef in EpgCenterList.allServicesNameDict:
			serviceName = EpgCenterList.allServicesNameDict[sRef]
		else:
			serviceName = ServiceReference(sRef).getServiceName()
		self["serviceName"].setText(serviceName)

		if begin != None and duration != None:
			beginString = strftime("%H:%M", localtime(begin))
			endString = strftime("%H:%M", localtime(begin + duration))
			
			if self.currentMode != TIMERLIST:
				duraString = "%d" % (duration / 60)
				now = int(time())
				
				if self.currentMode == SINGLE_EPG:
					if self["list"].instance.getCurrentIndex() == 0:
						timeValue = (begin + duration - now) /  60 + 1
						percent = int((now - begin) * 100 / duration)
					else:
						timeValue = (now - begin) /  60
						percent = 0
				elif self.currentMode == MULTI_EPG_NEXT:
					timeValue = (now - begin) /  60
					percent = 0
				else:
					if now >= begin:
						timeValue = (begin + duration - now) /  60 + 1
						percent = int((now - begin) * 100 / duration)
					else:
						timeValue = (now - begin) /  60
						percent = 0
						
				if (KEEP_OUTDATED_TIME == 0 and (begin + duration) > now) or (KEEP_OUTDATED_TIME != 0 and (begin + duration) > now):
					remainBeginString = " I "
					if timeValue > 0:
						remainBeginString += "+"
					if fabs(timeValue) >= 120 and fabs(timeValue) < 1440:
						timeValue /= 60
						remainBeginString += "%02dh" % timeValue
					elif fabs(timeValue) >= 1440:
						timeValue = (timeValue / 1440) +1
						remainBeginString += "%02dd" % timeValue
					else:
						if timeValue < 0:
							remainBeginString += "%03d" % timeValue
						else:
							remainBeginString += "%02d" % timeValue
				else:
					remainBeginString = " I <->"
			else:
				remainBeginString = ""
				
			if remainBeginString.endswith('>'): # KEEP_OUTDATED_TIME
				outdated = True
				try:
					progColor = parseColor("eventNotAvailable").argb()
				except:
					progColor = 0x777777
			elif config.plugins.merlinEpgCenter.showColoredEpgTimes.value:
				outdated = False
				if remainBeginString.endswith('h'): # begins in... hours
					self["remaining"].setForegroundColorNum(0)
				elif remainBeginString.endswith('d'): # begins in... days
					self["remaining"].setForegroundColorNum(1)
				elif remainBeginString.startswith(' I +'): # already running
					self["remaining"].setForegroundColorNum(2)
				elif remainBeginString.startswith(' I -'): # begins in... minutes
					self["remaining"].setForegroundColorNum(3)
				else: # undefined, shouldn't happen
					self["remaining"].setForegroundColorNum(4)
			else:
				outdated = False
				self["remaining"].setForegroundColorNum(3)
				
			if outdated:
				try:
					textColor = parseColor("eventNotAvailable").argb()
				except:
					textColor = parseColor("#777777")
					
				if config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_MULTI_PIXMAP or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_MULTI_PIXMAP_LIST_OFF:
					self["eventProgressImage"].setPixmapNum(4)
				elif config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PERCENT_TEXT or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PERCENT_TEXT_LIST_OFF:
					self["eventProgressText"].setText("100%")
				else:
					self["eventProgress"].setValue(100)
			else:
				try:
					textColor = parseColor("ListboxForeground").argb()
				except:
					textColor = parseColor("#ffffff")
					
				if config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_MULTI_PIXMAP or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_MULTI_PIXMAP_LIST_OFF:
					if percent > 0:
						part = int(round(percent / 25)) + 1
						if part < 0:
							part = 0
						elif part > 4:
							part = 4
					else:
						part = 0
					self["eventProgressImage"].setPixmapNum(part)
				elif config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PERCENT_TEXT or config.plugins.merlinEpgCenter.listProgressStyle.value == STYLE_PERCENT_TEXT_LIST_OFF:
					self["eventProgressText"].setText(str(percent) + "%")
				else:
					self["eventProgress"].setValue(percent)
					
			self["beginTime"].setText(beginString)
			self["endTime"].setText(endString)
			self["remaining"].setText(remainBeginString)
			self["duration"].setText(duraString)
			
		# all lists
		self["eventTitle"].setText(title)
		
		if config.plugins.merlinEpgCenter.showShortDescInEventInfo.value:
			newDescription = ""
			
			if shortDesc != None and shortDesc != "" and shortDesc != title:
				if newDescription == "":
					newDescription = shortDesc
				else:
					newDescription = ''.join([newDescription, "\n\n", shortDesc])
			if description != None and description != "":
				if newDescription == "":
					newDescription = description
				else:
					newDescription = ''.join([newDescription, "\n\n", description])
			description = newDescription

		self["description"].setText(description)
		
	def prepareFillMultiEpg(self):
		self.currentBouquet = self.bouquetList[self.currentBouquetIndex][1]
		if self.currentMode == MULTI_EPG_PRIMETIME:
			stime = self.primeTime
		else:
			stime = -1

		self.epgTabObjectList[self.currentMode].show(self.currentBouquet, self.currentBouquetIndex, self.currentMode)
		self.setBouquetName()
		
	def switchTvRadio(self, mode):
		if self.configTabsShown or mode == self.infoBarInstance.servicelist.mode:
			return
			
		self.similarShown = False
		if self.infoTextShown:
			self.keyInfo()
			
		if mode == MODE_TV:
			# MiniTV - Merlin only
			if config.merlin2.minitv.value and config.plugins.merlinEpgCenter.showMiniTV.value:
				self.miniTvRenderInstance.onShow()
				self.setDescriptionSize()
			self.infoBarInstance.servicelist.setModeTv()
		else:
			# MiniTV - Merlin only
			if config.merlin2.minitv.value and config.plugins.merlinEpgCenter.showMiniTV.value:
				self.miniTvRenderInstance.onHide()
				self.setDescriptionSize()
			self.infoBarInstance.servicelist.setModeRadio()
		self.infoBarInstance.servicelist.zap()
		self.updateBouquets()
		
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME:
			self.selectRunningService = True
			self.setMode(switchTvRadio = True)
			self["list"].l.invalidate()
			
		self.setBouquetName()
			
		if config.plugins.merlinEpgCenter.exitOnTvRadioSwitch.value:
			self.keyExit()
			
	def setButtonText(self, timerAdded = False):
		# cleanup button text
		if self.configTabsShown:
			self["key_red"].setText("")
			self["key_green"].setText("")
			self["key_blue"].setText("")
			return
		elif self.oldMode == SINGLE_EPG:
			self["key_blue"].setText("")
		elif self.oldMode == TIMERLIST:
			self["key_red"].setText("")
			self["key_yellow"].setText("")
			self["key_blue"].setText("")
		elif self.oldMode == EPGSEARCH_HISTORY or timerAdded:
			if not self.similarShown:
				self["key_red"].setText("")
			self["key_yellow"].setText("")
			self["key_blue"].setText("")
			
		# set button text
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT:
			if self.currentMode == SINGLE_EPG and KEEP_OUTDATED_TIME != 0:
				if not self.showOutdated:
					self["key_blue"].setText(_("Outdated on"))
				else:
					self["key_blue"].setText(_("Outdated off"))
			else:
				self["key_blue"].setText("")
				
			if IMDB_INSTALLED:
				self["key_yellow"].setText(_("IMDb"))
		elif self.currentMode == TIMERLIST:
			self.key_red_choice = self.EMPTY # TimerEditList method
			self.key_yellow_choice = self.EMPTY # TimerEditList method
			self.key_blue_choice = self.EMPTY # TimerEditList method
			self.updateState() # TimerEditList method
			self["key_green"].setText(_("Add"))
		elif self.currentMode == EPGSEARCH_HISTORY:
			self["key_red"].setText(_("Remove"))
			self["key_green"].setText(_("OK"))
			self["key_yellow"].setText(_("New Search"))
			
	def setTimerButtonState(self, cur):
		if self.configTabsShown:
			return
		if cur == None or cur[1] == None or cur[2] == "":
			self.key_green_choice = self.EMPTY
			self["key_green"].setText("")
		else:
			if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT or self.currentMode == EPGSEARCH_HISTORY:
				isRecordEvent = False
				for timer in self.session.nav.RecordTimer.timer_list:
					if timer.eit == cur[1] and timer.service_ref.ref.toString() == cur[2]:
						isRecordEvent = True
						break
				if isRecordEvent:
					self["key_green"].setText(_("Remove timer"))
					self.key_green_choice = self.REMOVE_TIMER
				elif not isRecordEvent:
					self["key_green"].setText(_("Add timer"))
					self.key_green_choice = self.ADD_TIMER
			elif self.currentMode == TIMERLIST:
				self.key_green_choice = self.EMPTY
			
	def deleteTimer(self, timer):
		timer.afterEvent = AFTEREVENT.NONE
		self.session.nav.RecordTimer.removeEntry(timer)
		self["key_green"].setText(_("Add timer"))
		self.key_green_choice = self.ADD_TIMER
		# refresh timer pixmaps in our list
		self["list"].l.invalidate()
		size = int(config.plugins.merlinEpgCenter.numNextEvents.value)
		if not (size == 0 or self.configTabsShown or (self.currentMode != MULTI_EPG_NOW and self.currentMode != MULTI_EPG_NEXT and self.currentMode != MULTI_EPG_PRIMETIME and self.currentMode != EPGSEARCH_RESULT)):
			self["upcoming"].l.invalidate()
			
	def setRecordingBlinkState(self):
		if self.blinkTimer.getBlinkState() and not self.blinkTimer.getIsStopping():
			self["isRecording"].show()
		else:
			self["isRecording"].hide()
			
	def setEventPiconBlinkState(self):
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT:
			cur = self["list"].getCurrent()
			self.setEventViewPicon(cur)
			
	def setEventViewPicon(self, cur, isAutoTimer = False):
		if isAutoTimer:
			if not self.autoTimerPixmapLarge:
				pixmapPath = resolveFilename(SCOPE_CURRENT_PLUGIN, "Extensions/MerlinEPGCenter/images/AutoTimerLarge.png")
				self.autoTimerPixmapLarge = LoadPixmap(cached = False, path = pixmapPath)
			if self.autoTimerPixmapLarge:
				self["picon"].instance.setPixmap(self.autoTimerPixmapLarge)
		else:
			idx = self["list"].instance.getCurrentIndex()
			if config.plugins.merlinEpgCenter.blinkingPicon.value and self.blinkTimer.getIsInList(idx) and not self.blinkTimer.getBlinkState():
				self["picon"].instance.setPixmap(gPixmapPtr())
			elif cur is not None:
				sRef = cur[2]
				if self["picon"].instance is not None:
					fileName = findDefaultPicon(sRef)
					if fileName is not "":
						picon = LoadPixmap(fileName)
						self["picon"].instance.setPixmap(picon)
						
	def removeFromEpgSearchHistory(self):
		if len(self["history"].list):
			cur = self["history"].getCurrent()
			config.plugins.merlinEpgCenter.searchHistory.value.remove(cur)
			self["history"].setList(config.plugins.merlinEpgCenter.searchHistory.value)
			
	def setInputHelp(self, configElement = None):
		if config.plugins.merlinEpgCenter.showInputHelp.value:
			self.searchField.help_window.show()
		else:
			self.searchField.help_window.hide()
			
	############################################################################################
	# BOUQUET RELATED FUNCTIONS
	
	def getBouquetName(self):
		name = self.bouquetList[self.currentBouquetIndex][0]
		showBouquetText = config.plugins.merlinEpgCenter.showBouquetText.value
		if self.infoBarInstance.servicelist.mode == MODE_TV:
			if name[len(name) -5:] == ' (TV)':
				if showBouquetText:
					return 'Bouquet: %s' % name[:len(name) -5]
				else:
					return '%s' % name[:len(name) -5]
			else:
				if showBouquetText:
					return 'Bouquet: %s' % name # Partnerbox bouquet
				else:
					return '%s' % name # Partnerbox bouquet
		else:
			if name[len(name) -8:] == ' (Radio)':
				if showBouquetText:
					return 'Bouquet: %s' % name[:len(name) -8]
				else:
					return '%s' % name[:len(name) -8]
			else:
				if showBouquetText:
					return 'Bouquet: %s' % name # Partnerbox bouquet
				else:
					return '%s' % name # Partnerbox bouquet
				
	def setBouquetName(self):
		self["bouquet"].setText(self.getBouquetName())
		
	def updateBouquets(self):
		from plugin import getBouquetInformation
		(self.servicelist, self.currentBouquet, self.bouquetList, self.currentBouquetIndex) = getBouquetInformation()
		self.similarShown = False
		
		EpgCenterList.bouquetList = self.bouquetList
		EpgCenterList.currentBouquetIndex = self.currentBouquetIndex
		EpgCenterList.updateBouquetServices()
		
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME:
			self.selectRunningService = True
			self.setMode(switchTvRadio = True)
			self["list"].l.invalidate()
			
		self.setBouquetName()
		
	############################################################################################
	# AUTOTIMER

	def getAutoTimerInstance(self):
		global autotimer
		
		# create autotimer instance if needed
		if autotimer is None:
			self.removeAutoTimerInstance = True
			autotimer = AutoTimer()
			autotimer.readXml()
		else:
			self.removeAutoTimerInstance = False
			
	def deleteAutoTimerInstance(self):
		if self.removeAutoTimerInstance:
			global autotimer
			autotimer = None
			
	# Taken from AutoTimerEditor
	def addAutotimerFromString(self, match, addNewTimer = False, begin = None, end = None, sRef = None):
		global autotimer
		self.getAutoTimerInstance()
		
		newTimer = autotimer.defaultTimer.clone()
		newTimer.id = autotimer.getUniqueId()
		newTimer.name = match
		newTimer.match = ''
		newTimer.enabled = True
		
		if begin != None and end != None:
			begin -= 3600
			end += 3600
			
		self.session.openWithCallback(
			boundFunction(self.importerCallback, addNewTimer),
			AutoTimerImporter,
			newTimer,
			match,		# Proposed Match
			begin,		# Proposed Begin
			end,		# Proposed End
			None,		# Proposed Disabled
			sRef,		# Proposed ServiceReference
			None,		# Proposed afterEvent
			None,		# Proposed justplay
			None,		# Proposed dirname, can we get anything useful here?
			[]		# Proposed tags
		)
	
	def importerCallback(self, addNewTimer, ret):
		if ret:
			ret, session = ret

			self.session.openWithCallback(
				boundFunction(self.editorCallback, addNewTimer),
				AutoTimerEditor,
				ret
			)
		else:
			self.deleteAutoTimerInstance()

	def editorCallback(self, addNewTimer, ret):
		if ret:
			global autotimer
			self.getAutoTimerInstance()
			autotimer.add(ret)
			autotimer.writeXml()
			idx = self["timerlist"].getCurrentIndex()
			obj = self.getTimerListObjectFromAutoTimer(ret)
			if addNewTimer:
				self.list.append((obj, False))
			else:
				self.list[idx] = (obj, False)
			self.updateState()
			
		self.deleteAutoTimerInstance()
		
	def updateAutoTimerEntry(self, id, changedTimer):
		global autotimer
		self.getAutoTimerInstance()
		
		idx = 0
		for timer in autotimer.timers:
			if timer.getId() == id:
				autotimer.timers[idx] = changedTimer
				break
			idx += 1
		autotimer.writeXml()
		self.deleteAutoTimerInstance()
		
		# update the list entry
		idx = self["timerlist"].getCurrentIndex()
		obj = self.getTimerListObjectFromAutoTimer(changedTimer)
		self.list[idx] = (obj, False)
		self["timerlist"].l.invalidateEntry(idx)
		self.onListSelectionChanged()
		
	############################################################################################
	# MODE CONTROL
	
	def setMode(self, searchEpg = False, historySearch = False, manualSearch = False, switchTvRadio = False, doSearch = False):
		self.setTabs()
		self.setUpcomingWidgets()
		
		if self.blinkTimer.getIsRunning():
			self.blinkTimer.reset()
		
		# TODO only hide if the plugin wasn't just started
		if not historySearch and self.oldMode != None:
			self.epgTabObjectList[self.oldMode].hide()
			
		if doSearch:
			playingSref = NavigationInstance.instance.getCurrentlyPlayingServiceReference() # get the currently playing service
			if playingSref is not None:
				event = self.epgcache.lookupEventTime(playingSref, -1, 0) # get the matching event
				if event is not None:
					searchString = event.getEventName() # set the event name as search string
				else:
					searchString = ""
				self.currentMode = EPGSEARCH_RESULT
				self.epgTabObjectList[self.currentMode].show(searchString, self.currentMode)
		elif searchEpg:
			cur = None
			if self.oldMode == MULTI_EPG_NOW or self.oldMode == MULTI_EPG_NEXT or self.oldMode == SINGLE_EPG or self.oldMode == MULTI_EPG_PRIMETIME:
				cur = self["list"].getCurrent()
				if cur:
					searchString = cur[5]
			elif self.oldMode == TIMERLIST:
				cur = self["timerlist"].getCurrent()
				if cur:
					searchString = cur.name
			elif self.currentMode == EPGSEARCH_MANUAL:
				self.oldMode = self.currentMode
				self.currentMode = EPGSEARCH_RESULT
				searchString = self["search"].list[0][1].value
				self.epgTabObjectList[self.oldMode].hide()
				self.epgTabObjectList[self.currentMode].show(searchString, self.currentMode)
			if cur:
				self.currentMode = EPGSEARCH_RESULT
				self.epgTabObjectList[self.currentMode].show(searchString, self.currentMode)
		elif manualSearch:
			self.oldMode = self.currentMode
			self.currentMode = EPGSEARCH_MANUAL
			self.epgTabObjectList[self.oldMode].hide()
			self.epgTabObjectList[self.currentMode].show()
		elif self.currentMode == EPGSEARCH_HISTORY:
			if historySearch:
				self.oldMode = self.currentMode
				cur = self["history"].getCurrent()
				if cur:
					self.currentMode = EPGSEARCH_RESULT
					self.epgTabObjectList[self.oldMode].hide()
					self.epgTabObjectList[self.currentMode].show(cur, self.currentMode)
			else:
				self.epgTabObjectList[self.currentMode].show()
		elif self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == MULTI_EPG_PRIMETIME:
			self.epgTabObjectList[self.currentMode].show(self.currentBouquet, self.currentBouquetIndex, self.currentMode)
			# set the marker to the currently running service on plugin start
			if self.selectRunningService:
				self.selectRunningService = False
				self.setSelectionToRunningService()
			elif self.oldMode == SINGLE_EPG or self.oldMode == EPGSEARCH_RESULT or self.oldMode == EPGSEARCH_HISTORY:
				if self.lastMultiEpgIndex > 0:
					self["list"].instance.moveSelectionTo(self.lastMultiEpgIndex)
				else:
					self["list"].instance.moveSelectionTo(0)
		elif self.currentMode == SINGLE_EPG:
			sRef = None
			if self.selectRunningService:
				self.setSelectionToRunningService()
			if self.showOutdated and not self.hideOutdated:
				self.hideOutdated = True
			elif self.showOutdated and self.hideOutdated:
				self.showOutdated = False
				self.hideOutdated = False
			elif not self.showOutdated and not self.hideOutdated and not self.oldMode == EPGSEARCH_RESULT and not self.selectRunningService:
				self.lastMultiEpgIndex = self["list"].instance.getCurrentIndex()
				
			self.selectRunningService = False
				
			if switchTvRadio:
				self.oldMode = None
				
			self.epgTabObjectList[self.currentMode].show(self.oldMode, self.bouquetList[0], self.currentBouquet, self.currentBouquetIndex, self.currentMode, self.showOutdated, sRef, self.timerListMode)
		elif self.currentMode == TIMERLIST:
			if self.timerListMode == LIST_MODE_TIMER:
				self.fillTimerList()
			else:
				self.fillAutoTimerList()
			self.onListSelectionChanged()
			self["timerlist"].moveToIndex(0)
			self.epgTabObjectList[self.currentMode].show()
		if self.listStyle == STYLE_SINGLE_LINE:
			if (self.currentMode == SINGLE_EPG or self.currentMode == EPGSEARCH_RESULT) and (self.oldMode != SINGLE_EPG and self.oldMode != EPGSEARCH_RESULT):
				self.setUpcomingWidgets()
			elif (self.currentMode != SINGLE_EPG and self.currentMode != EPGSEARCH_RESULT) and (self.oldMode == SINGLE_EPG or self.oldMode == EPGSEARCH_RESULT):
				self.setUpcomingWidgets()
				
		self.setButtonText()
		self.setActions()
		
	def setSelectionToRunningService(self):
		playingSref = NavigationInstance.instance.getCurrentlyPlayingServiceReference()
		if not playingSref:
			return
			
		from plugin import getBouquetInformation
		(self.servicelist, self.currentBouquet, self.bouquetList, self.currentBouquetIndex) = getBouquetInformation()
		EpgCenterList.bouquetList = self.bouquetList
		EpgCenterList.currentBouquetIndex = self.currentBouquetIndex
		sRef = playingSref.toCompareString()
		if sRef in self["list"].bouquetServices[self.currentBouquetIndex]:
			self.lastMultiEpgIndex = self["list"].bouquetServices[self.currentBouquetIndex].index(sRef)
		
		if self.currentMode == SINGLE_EPG:
			if sRef in self["list"].bouquetServices[self.currentBouquetIndex]:
				self.epgTabObjectList[self.currentMode].show(self.oldMode, self.bouquetList[0], self.currentBouquet, self.currentBouquetIndex, self.currentMode, self.showOutdated, sRef, self.timerListMode)
		else:
			if sRef in self["list"].bouquetServices[self.currentBouquetIndex]:
				self.epgTabObjectList[self.currentMode].show(self.currentBouquet, self.currentBouquetIndex, self.currentMode)
				
			i = 0
			while i < len(self["list"].list):
				if self["list"].list[i][2] == sRef:
					self.lastMultiEpgIndex = i
					self["list"].instance.moveSelectionTo(self.lastMultiEpgIndex)
					break
				i += 1
				
	############################################################################################
	# KEY HANDLING
	
	def keyEditMode(self):
		if self.configEditMode == False:
			self.configEditMode = True
			self["key_yellow"].setText(_("Edit Off"))
		else:
			self.configEditMode = False
			if self.configTabsShown:
				self["key_yellow"].setText(_("Edit On"))
			else:
				self["key_yellow"].setText("")
				
	def keyRed(self, forceHideSimilar = False):
		if self.currentMode == EPGSEARCH_HISTORY:
			self.removeFromEpgSearchHistory()
		else:
			if not forceHideSimilar:
				self.similarShown = not self.similarShown
			else:
				self.similarShown = False
				
			if not self.similarShown:
				self.epgTabObjectList[self.currentMode].hideSimilar()
				self["key_red"].setText("")
				self["epgRedActions"].setEnabled(False)
			else:
				if self.infoTextShown:
					self.keyInfo()
				self.epgTabObjectList[self.currentMode].showSimilar()
				self["key_red"].setText(_("return"))
				self["epgRedActions"].setEnabled(True)
				
	def keyGreen(self):
		if self.currentMode == EPGSEARCH_HISTORY:
			self.setMode(historySearch = True)
		elif self.currentMode == EPGSEARCH_MANUAL:
			self.keyOk()
		else:
			cur = self["list"].getCurrent()
			if cur == None or cur[1] == None or cur[2] == "":
				return
			
			addTimer = True
			for timer in self.session.nav.RecordTimer.timer_list:
				if timer.eit == cur[1] and timer.service_ref.ref.toString() == cur[2]:
					addTimer = False
					self.deleteTimer(timer)
					self.setButtonText(timerAdded = True)
					self.getSimilarEvents()
					self.setEventViewPicon(cur)
					break
					
			if addTimer:
				if AUTOTIMER:
					self.timerChoice()
				else:
					self.addTimerEntry()
					
	def keyYellow(self):
		if self.currentMode == EPGSEARCH_HISTORY:
			self.setMode(manualSearch = True)
		elif self.configTabsShown:
			self.keyEditMode()
		elif IMDB_INSTALLED and (self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT):
			cur = self["list"].getCurrent()
			self.session.open(IMDB, cur[5])
			
	def keyBlue(self):
		if self.currentMode == EPGSEARCH_RESULT:
			cur = self["list"].getCurrent()
			if cur == None or cur[5] == None:
				return
			self.epgTabObjectList[self.currentMode].updateEpgSearchHistory(cur[5]) # save the searchString in the search history
			# remove possibility to add the service name to the list of epg search terms
			self["key_blue"].setText("")
			self["epgBlueActions"].setEnabled(False)
		elif KEEP_OUTDATED_TIME > 0:
			if not self.showOutdated:
				self.showOutdated = True
			if self.similarShown:
				self.similarShown = False
				self["key_red"].setText("")
			self.setMode()
		
	def keyLeft(self):
		if self.configTabsShown:
			if self.configEditMode:
				self["settings"].handleKey(KEY_LEFT)
		elif self.currentMode == EPGSEARCH_MANUAL:
			self["search"].handleKey(KEY_LEFT)
		elif self.currentMode == EPGSEARCH_HISTORY:
			self["history"].pageUp()
		elif self.infoTextShown:
			self["infoText"].pageUp()
		elif self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT:
			self["list"].pageUp()
			
	def keyRight(self):
		if self.configTabsShown:
			if self.configEditMode:
				self["settings"].handleKey(KEY_RIGHT)
		elif self.currentMode == EPGSEARCH_MANUAL:
			self["search"].handleKey(KEY_RIGHT)
		elif self.currentMode == EPGSEARCH_HISTORY:
			self["history"].pageDown()
		elif self.infoTextShown:
			self["infoText"].pageDown()
		elif self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT:
			self["list"].pageDown()
			
	def keyUp(self):
		if self["list"].getVisible():
			self["list"].moveUp()
		elif self.currentMode == EPGSEARCH_HISTORY:
			self["history"].up()
		elif self.configTabsShown:
			self["settings"].instance.moveSelection(self["settings"].instance.moveUp)
		elif self.infoTextShown:
			self["infoText"].pageUp()
			
	def keyDown(self):
		if self["list"].getVisible():
			self["list"].moveDown()
		elif self.currentMode == EPGSEARCH_HISTORY:
			self["history"].down()
		elif self.configTabsShown:
			self["settings"].instance.moveSelection(self["settings"].instance.moveDown)
		elif self.infoTextShown:
			self["infoText"].pageDown()
			
	def keyExit(self):
		mainTabValue = int(config.plugins.merlinEpgCenter.mainTab.getValue())
		if self.configTabsShown:
			self.keyMenu()
			return
		elif mainTabValue != -1 and self.currentMode != mainTabValue:
			self.keyNumber(mainTabValue +1)
			return
		elif self.infoTextShown:
			self.keyInfo()
			return
		
		if self.currentMode == EPGSEARCH_MANUAL or self.currentMode == EPGSEARCH_RESULT:
			self.oldMode = self.currentMode
			self.currentMode = EPGSEARCH_HISTORY
			self.epgTabObjectList[self.oldMode].hide()
			self.epgTabObjectList[self.currentMode].show()
			self.setActions()
			self.setButtonText()
		else:
			self.suspend()
			self.close(None)
			
	# really shutdown everything when enigma2 is shut down
	def shutdown(self):
		self.removeNotifier()
		self.setEventPiconBlinkState_conn = None
		self.setRecordingBlinkState_conn = None
		self.releaseEpgBaseTab()
		self.blinkTimer.suspend()
		self.close(None)
		
	def keyDirection(self, direction):
		if self.similarShown:
			self.keyRed()
		elif self.infoTextShown:
			self.keyInfo()
			
		if self.configEditMode:
			if direction == -1:
				self["settings"].handleKey(KEY_BACKSPACE)
			elif direction == 1:
				self["settings"].handleKey(KEY_DELETE)
		elif self.currentMode == EPGSEARCH_MANUAL:
			if direction == -1:
				self["search"].handleKey(KEY_BACKSPACE)
			elif direction == 1:
				self["search"].handleKey(KEY_DELETE)
		else:
			if self.configTabsShown:
				numTabs = NUM_CONFIG_TABS
			else:
				numTabs = NUM_EPG_TABS
				
			self.oldMode = self.currentMode
			
			if direction == 1: # right
				self.currentMode += 1
				if self.currentMode > numTabs:
					self.currentMode = 0 # set to first tab
			else:
				self.currentMode -= 1
				if self.currentMode >= numTabs:
					self.currentMode = numTabs -1 # set to last tab -1
				elif self.currentMode == -1:
					self.currentMode = numTabs # set to last tab
			
			if self.configTabsShown:
				self.setTabs()
				self.configTabObjectList[self.currentMode].settingsWidget.setCurrentIndex(0)
				self.configTabObjectList[self.currentMode].show()
			else:
				self.setMode()
				
	def keyNumber(self, number):
		if self.configTabsShown:
			if self.configEditMode:
				self["settings"].handleKey(KEY_0 + number)
			else:
				if number != 0 and self.currentMode != number -1 and number -1 <= NUM_CONFIG_TABS:
					self["tab_text_%d" % self.currentMode].instance.setForegroundColor(parseColor("#ffffff")) # inactive
					self.currentMode = number -1
					self.setTabs()
					self.configTabObjectList[self.currentMode].settingsWidget.setCurrentIndex(0)
					self.configTabObjectList[self.currentMode].show()
			return
		elif self.similarShown:
			self.keyRed()
		elif self.infoTextShown:
			self.keyInfo()
			
		self.oldMode = self.currentMode
		if self.oldMode == MULTI_EPG_NOW or self.oldMode == MULTI_EPG_NEXT or self.oldMode == MULTI_EPG_PRIMETIME:
			self.lastMultiEpgIndex = self["list"].instance.getCurrentIndex()
			
		if self.currentMode == EPGSEARCH_MANUAL:
			self["search"].handleKey(KEY_0 + number)
		else:
			if self.oldMode == number -1 and not self.oldMode == TIMERLIST: # same mode, there's nothing to do for other modes than TIMERLIST
				return
			elif number <= (NUM_EPG_TABS +1): # make sure one of our tabs was selected
				self.currentMode = number -1 # 0 based
				if number == 6 and self.oldMode != EPGSEARCH_RESULT: # epg search
					self.setMode(searchEpg = True)
					
					# reset / don't show similar events option
					self.similarShown = False
					self["key_red"].setText("")
					self["epgRedActions"].setEnabled(False)
					
					# add possibility to add the service name to the list of epg search terms
					self["key_blue"].setText(_("Set search term"))
					self["epgBlueActions"].setEnabled(True)
				elif number == 5 and AUTOTIMER and self.oldMode == TIMERLIST: # toggle timer / autotimer
					if self.timerListMode == LIST_MODE_TIMER:
						self.timerListMode = LIST_MODE_AUTOTIMER
						self["tab_text_%d" % TIMERLIST].setText("AutoTimer")
						self.getAutoTimerInstance()
						self.fillAutoTimerList()
						self.deleteAutoTimerInstance()
					elif self.timerListMode == LIST_MODE_AUTOTIMER:
						self.timerListMode = LIST_MODE_TIMER
						self["tab_text_%d" % TIMERLIST].setText(_("Timer"))
						self.fillTimerList()
						
					self["timerlist"].moveToIndex(0)
					self["timerlist"].invalidate()
					self.updateState()
					self.onListSelectionChanged()
				else:
					self.setMode()
					
	def keyOk(self):
		if self.currentMode == EPGSEARCH_MANUAL:
			self.epgTabObjectList[self.currentMode].updateEpgSearchHistory() # save the searchString in the search history
			self.setMode(searchEpg = True)
		elif self.currentMode == EPGSEARCH_HISTORY:
			self.setMode(historySearch = True)
		elif self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME:
			cur = self["list"].getCurrent()
			if cur != None:
				# MiniTV - Merlin only
				if config.merlin2.minitv.value and config.plugins.merlinEpgCenter.showMiniTV.value:
					self.miniTvRenderInstance = None
				# update the infobar servicelist...
				self.infoBarInstance.epg_bouquet = self.bouquetList[self.currentBouquetIndex][1]
				# this is ugly but it ensures that zapping to service works as well when alternatives are used
				sref = EpgCenterList.alternativesDict.get(cur[2], cur[2])
				self.infoBarInstance.zapToService(eServiceReference(sref))
				# ...and exit
				self.keyExit()
				
	def keyBouquetUp(self):
		if self.infoTextShown:
			self.keyInfo()
			
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == MULTI_EPG_PRIMETIME:
			if (self.currentBouquetIndex +1)  <= (len(self.bouquetList) -1):
				self.currentBouquetIndex += 1
			else:
				self.currentBouquetIndex = 0
			self.prepareFillMultiEpg()
			
			# set selection to the first list entry
			self.lastMultiEpgIndex = 0
			self["list"].instance.moveSelectionTo(self.lastMultiEpgIndex)
		elif self.currentMode == SINGLE_EPG:
			self.epgTabObjectList[self.currentMode].changeService(1)
			
	def keyBouquetDown(self):
		if self.infoTextShown:
			self.keyInfo()
			
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == MULTI_EPG_PRIMETIME:
			if (self.currentBouquetIndex - 1) >= 0:
				self.currentBouquetIndex -= 1
			else:
				self.currentBouquetIndex = len(self.bouquetList) - 1
			self.prepareFillMultiEpg()
			
			# set selection to the first list entry
			self.lastMultiEpgIndex = 0
			self["list"].instance.moveSelectionTo(self.lastMultiEpgIndex)
		elif self.currentMode == SINGLE_EPG:
			self.epgTabObjectList[self.currentMode].changeService(-1)
			
	def keyMenu(self):
		if self.infoTextShown:
			self.keyInfo()
		if self.similarShown:
			self.keyRed()
		self.toggleConfigTabs()
		
	# show short and long description for the selected event
	def keyInfo(self):
		if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT:
			if self.infoTextShown:
				self["infoText"].hide()
				self["list"].show()
				if config.plugins.merlinEpgCenter.showEventInfo.value:
					self["description"].show()
					
			else:
				# get the selected entry
				cur = self["list"].getCurrent()
				if cur is None:
					title = ""
					shortDesc = ""
					description = ""
				else:
					title = cur[5]
					shortDesc = cur[6]
					description = cur[7]
					
				if title != None and title != "":
					infoText = title
				else:
					infoText = ""
					
				if shortDesc != None and shortDesc != "" and shortDesc != title:
					if infoText == "":
						infoText = shortDesc
					else:
						infoText = ''.join([infoText, "\n\n", shortDesc])
				if description != None and description != "":
					if infoText == "":
						infoText = description
					else:
						infoText = ''.join([infoText, "\n\n", description])
					
				self["infoText"].setText(infoText)
				size = self["list"].instance.size()
				self["infoText"].resize(eSize(size.width() - 5, size.height()))
				self["list"].hide()
				self["description"].hide()
				self["infoText"].show()
				
			self.infoTextShown = not self.infoTextShown
			
	def keyTv(self):
		self.switchTvRadio(MODE_TV)
		
	def keyRadio(self):
		self.switchTvRadio(MODE_RADIO)
		
	def keyVideo(self):
		if YTTRAILER_INSTALLED:
			if self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == SINGLE_EPG or self.currentMode == MULTI_EPG_PRIMETIME or self.currentMode == EPGSEARCH_RESULT:
				cur = self["list"].getCurrent()
				if cur:
					self.session.open(YTTrailerList, cur[5])
			elif self.currentMode == TIMERLIST:
				cur = self["timerlist"].getCurrent()
				if cur:
					self.session.open(YTTrailerList, cur.name)
					
	def keyText(self):
		if self.currentMode == SINGLE_EPG:
			if self.epgTabObjectList[self.currentMode].sortMode == EpgSingleTab.SORT_MODE_TIME:
				self.epgTabObjectList[self.currentMode].sortMode = EpgSingleTab.SORT_MODE_NAME
			else:
				self.epgTabObjectList[self.currentMode].sortMode = EpgSingleTab.SORT_MODE_TIME
			self.epgTabObjectList[self.currentMode].sort()
			
	############################################################################################
	# TAB TOGGLING
	
	def toggleConfigTabs(self):
		if self.configTabsShown: # show epg tabs again
			self["settings"].hide()
			self.configTabsShown = False
			self["tab_text_%d" % self.currentMode].instance.setForegroundColor(parseColor("#ffffff")) # inactive
			self.currentMode = self.savedCurrentMode
			if self.numNextEvents > 0 and (self.currentMode == MULTI_EPG_NOW or self.currentMode == MULTI_EPG_NEXT or self.currentMode == MULTI_EPG_PRIMETIME):
				self["upcomingSeparator"].show()
			self.oldMode = self.savedOldMode
			self.setTabText(TAB_TEXT_EPGLIST)
			if self.currentMode <= NUM_EPG_TABS:
				self["tab_text_%d" % self.currentMode].instance.setForegroundColor(parseColor(config.plugins.merlinEpgCenter.tabTextColorSelected.value)) # active
				self["tabbar"].setPixmapNum(self.currentMode)
			else:
				self["tab_text_%d" % NUM_EPG_TABS].instance.setForegroundColor(parseColor(config.plugins.merlinEpgCenter.tabTextColorSelected.value)) # active
				self["tabbar"].setPixmapNum(NUM_EPG_TABS)
				
			if self.currentMode == EPGSEARCH_MANUAL:
				self.setMode(manualSearch = True)
			elif self.currentMode == EPGSEARCH_RESULT:
				self["list"].show()
			else:
				self.setMode()
				
			self.configEditMode = True
			self.keyEditMode()
			
			# reset the timer button text
			cur = self["list"].getCurrent()
			if cur is not None:
				self.setTimerButtonState(cur)
		else: # show config tabs
			self["upcoming"].hide()
			self["upcomingSeparator"].hide()
			self.epgTabObjectList[self.currentMode].hide()
			if self.currentMode <= NUM_EPG_TABS:
				self["tab_text_%d" % self.currentMode].instance.setForegroundColor(parseColor("#ffffff")) # inactive
			else:
				self["tab_text_%d" % NUM_EPG_TABS].instance.setForegroundColor(parseColor("#ffffff")) # inactive
			self.savedCurrentMode = self.currentMode
			self.savedOldMode = self.oldMode
			self.currentMode = 0 # first config tab
			self["tab_text_%d" % self.currentMode].instance.setForegroundColor(parseColor(config.plugins.merlinEpgCenter.tabTextColorSelected.value)) # active
			self["tabbar"].setPixmapNum(self.currentMode)
			self.configTabsShown = True
			self.setTabText(TAB_TEXT_CONFIGLIST)
			self.configEditMode = True
			self.keyEditMode()
			self["settings"].show()
			self.configTabObjectList[self.currentMode].show()
			
		self.setButtonText()
		self.setActions()
			
	############################################################################################
	# EVENT INFORMATION
	
	def setVideoPicture(self, configElement = None):
		if config.plugins.merlinEpgCenter.showEventInfo.value:
			if config.plugins.merlinEpgCenter.showVideoPicture.value:
				self["videoPicture"].show()
			else:
				self["videoPicture"].hide()
			
	def setDescriptionSize(self):
		# Invisible option to allow moving the videoPicture above the event description in skins
		if not config.plugins.merlinEpgCenter.setDescriptionSize.value:
			return
			
		lineHeight = int(fontRenderClass.getInstance().getLineHeight(self["description"].instance.getFont()))
		if config.plugins.merlinEpgCenter.showVideoPicture.value or (config.merlin2.minitv.value and config.plugins.merlinEpgCenter.showMiniTV.value):
			maxVisibleLines = int((self.videoPicturePosY - self.descriptionPosY - 5) / lineHeight)
		else:
			maxVisibleLines = int(self.descriptionHeightMax / lineHeight)
		newHeight = lineHeight * maxVisibleLines
		self["description"].instance.resize(eSize(self.descriptionWidthMax, newHeight))
		
	def setEventInfo(self, configElement = None):
		if config.plugins.merlinEpgCenter.showEventInfo.value:
			newSize = eSize(self.listWidthMin, self.listHeightMin)
			self["eventInfoSeparator"].show()
			self["picon"].show()
			self["serviceName"].show()
			self["eventTitle"].show()
			self["beginTime"].show()
			self["eventProgress"].show()
			self["endTime"].show()
			self["duration"].show()
			self["remaining"].show()
			self["description"].show()
			self["videoPicture"].show()
		else:
			newSize = eSize(self.listWidthMax, self.listHeightMin)
			self["eventInfoSeparator"].hide()
			self["picon"].hide()
			self["serviceName"].hide()
			self["eventTitle"].hide()
			self["beginTime"].hide()
			self["eventProgress"].hide()
			self["endTime"].hide()
			self["duration"].hide()
			self["remaining"].hide()
			self["description"].hide()
			self["videoPicture"].hide()
			
		border = 5
		self["timerlist"].instance.resize(newSize)
		self["search"].instance.resize(eSize(newSize.width() - border -15, newSize.height()))
		self["history"].instance.resize(eSize(newSize.width() - border, newSize.height()))
		self["settings"].instance.resize(eSize(newSize.width() - border, newSize.height()))
		self["upcomingSeparator"].instance.resize(eSize(newSize.width() + border, newSize.height())) # touch the event info separator
		self["timerlist"].setMaxWidth(newSize)
		
		self.setUpcomingWidgets()
		self.setVideoPicture()
		self.setListPixmaps()
		
	def setListPixmaps(self):
		backgroundPixmap = None
		if config.plugins.merlinEpgCenter.showEventInfo.value and config.plugins.merlinEpgCenter.backgroundPixmapShort.value != "":
			backgroundPixmap = LoadPixmap(cached = True, path = config.plugins.merlinEpgCenter.backgroundPixmapShort.value)
		elif not config.plugins.merlinEpgCenter.showEventInfo.value and config.plugins.merlinEpgCenter.backgroundPixmapLong.value != "":
			backgroundPixmap = LoadPixmap(cached = True, path = config.plugins.merlinEpgCenter.backgroundPixmapLong.value)
		if backgroundPixmap is not None:
			self["timerlist"].instance.setBackgroundPicture(backgroundPixmap)
			self["list"].instance.setBackgroundPicture(backgroundPixmap)
			self["upcoming"].instance.setBackgroundPicture(backgroundPixmap)
			self["history"].instance.setBackgroundPicture(backgroundPixmap)
			self["settings"].instance.setBackgroundPicture(backgroundPixmap)
			
		selectionPixmap = None
		if config.plugins.merlinEpgCenter.showEventInfo.value and config.plugins.merlinEpgCenter.selectionPixmapShort.value != "":
			selectionPixmap = LoadPixmap(cached = True, path = config.plugins.merlinEpgCenter.selectionPixmapShort.value)
		elif not config.plugins.merlinEpgCenter.showEventInfo.value and config.plugins.merlinEpgCenter.selectionPixmapLong.value != "":
			selectionPixmap = LoadPixmap(cached = True, path = config.plugins.merlinEpgCenter.selectionPixmapLong.value)
		if selectionPixmap is not None:
			self["timerlist"].instance.setSelectionPicture(selectionPixmap)
			self["list"].instance.setSelectionPicture(selectionPixmap)
			self["history"].instance.setSelectionPicture(selectionPixmap)
			self["settings"].instance.setSelectionPicture(selectionPixmap)
			
