from Tools.Profile import profile

from Screen import Screen
from Components.Button import Button
from Components.ServiceList import ServiceList
from Components.ActionMap import NumberActionMap, ActionMap, HelpableActionMap
from Components.MenuList import MenuList
from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
from Screens.ChoiceBox import ChoiceBox
#Dr.Best --> HD Services
from Tools.HardwareInfo import HardwareInfo
profile("ChannelSelection.py 1")
from EpgSelection import EPGSelection
from enigma import eServiceReference, eServiceCenter, eTimer, eDVBDB, iPlayableService, iServiceInformation, getPrevAsciiCode, eEnv, iRecordableService, eEPGCache
from Components.config import config, ConfigSubsection, ConfigText, NoSave, ConfigBoolean
from Tools.NumericalTextInput import NumericalTextInput
profile("ChannelSelection.py 2")
from Components.NimManager import nimmanager
profile("ChannelSelection.py 2.1")
from Components.Sources.RdsDecoder import RdsDecoder
profile("ChannelSelection.py 2.2")
from Components.Sources.ServiceEvent import ServiceEvent
profile("ChannelSelection.py 2.3")
from Components.Input import Input
# Dr.Best --> MiniTV
profile("ChannelSelection.py 2.4")
from Components.Sources.ServiceEventReference import ServiceEventReference
from EventView import EventViewEPGSelect  # vali --> EventInfo in Channelselection
profile("ChannelSelection.py 3")
from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
from Components.SystemInfo import SystemInfo
from Screens.InputBox import InputBox, PinInput
from Screens.MessageBox import MessageBox
from Screens.ServiceInfo import ServiceInfo
profile("ChannelSelection.py 4")
from Screens.PictureInPicture import PictureInPicture
import Screens.Standby
from ServiceReference import ServiceReference
from Tools.BoundFunction import boundFunction
from os import remove
from Plugins.Plugin import PluginDescriptor
from Components.PluginComponent import plugins
from ChannelSelectionDisplaySettings import ChannelSelectionDisplaySettings
#dre
from Tools.Directories import fileExists
import xml.etree.cElementTree as etree
profile("ChannelSelection.py after imports")

# Shaderman --> PiconLoader
from Screens.PiconLoader import FileDownload, PiconSetInfo, loadPiconSetsFromFile, getServicesList, buildServiceRefString, PICONBASEURL
from Tools.Transponder import ConvertToHumanReadable
import re

# Dre --> PiconMapper
from Screens.PiconMapper import PiconMapperScreen

FLAG_SERVICE_NEW_FOUND = 64 #define in lib/dvb/idvb.h as dxNewFound = 64

class BouquetSelector(Screen):
	def __init__(self, session, bouquets, selectedFunc, enableWrapAround=False):
		Screen.__init__(self, session)

		self.selectedFunc=selectedFunc

		self["actions"] = ActionMap(["OkCancelActions"],
			{
				"ok": self.okbuttonClick,
				"cancel": self.cancelClick
			})
		entrys = [ (x[0], x[1]) for x in bouquets ]
		self["menu"] = MenuList(entrys, enableWrapAround)

	def getCurrent(self):
		cur = self["menu"].getCurrent()
		return cur and cur[1]

	def okbuttonClick(self):
		self.selectedFunc(self.getCurrent())

	def up(self):
		self["menu"].up()

	def down(self):
		self["menu"].down()

	def cancelClick(self):
		self.close(False)

class SilentBouquetSelector:
	def __init__(self, bouquets, enableWrapAround=False, current=0):
		self.bouquets = [b[1] for b in bouquets]
		self.pos = current
		self.count = len(bouquets)
		self.enableWrapAround = enableWrapAround

	def up(self):
		if self.pos > 0 or self.enableWrapAround:
			self.pos = (self.pos - 1) % self.count

	def down(self):
		if self.pos < (self.count - 1) or self.enableWrapAround:
			self.pos = (self.pos + 1) % self.count

	def getCurrent(self):
		return self.bouquets[self.pos]

# csel.bouquet_mark_edit values
OFF = 0
EDIT_BOUQUET = 1
EDIT_ALTERNATIVES = 2

def append_when_current_valid(current, menu, args, level = 0, key = ""):
	if current and current.valid() and level <= config.usage.setup_level.index:
		menu.append(ChoiceEntryComponent(key, args))

def append_when_level(menu, args, level = 0, key = ""):
	if level <= config.usage.setup_level.index:
		menu.append(ChoiceEntryComponent(key, args))

class ChannelContextMenu(Screen):
	ALLOW_SUSPEND = Screen.SUSPEND_STOPS

	def __init__(self, session, csel):

		Screen.__init__(self, session)
		#raise Exception("we need a better summary screen here")
		self.csel = csel
		self.bsel = None

		self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions"],
			{
				"ok": self.okbuttonClick,
				"cancel": self.cancelClick,
				"blue": self.showServiceInPiP
			})
		menu = [ ]

		self.pipAvailable = False
		current = csel.getCurrentSelection()
		current_root = csel.getRoot()
		current_root_path = current_root and current_root.getPath()
		current_sel_path = current.getPath()
		current_sel_flags = current.flags

		inBouquetRootList = current_root_path and current_root_path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
		inBouquet = csel.getMutableList() is not None
		haveBouquets = config.usage.multibouquet.value
		channel_context_menu_plugins = plugins.getPlugins(PluginDescriptor.WHERE_CHANNEL_CONTEXT_MENU)

		isPlayableService = not (current_sel_path or current_sel_flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
		if isPlayableService:
			append_when_current_valid(current, menu, (_("show transponder info"), self.showServiceInformations), level = 2)

		plugins_to_remove = []
		for p in channel_context_menu_plugins:
			if p.helperfnc != None:
				if p.helperfnc(csel):
					append_when_level(menu, (p.description, boundFunction(self.execPlugin, p, csel.getCurrentSelection())))
				plugins_to_remove.append(p)
		channel_context_menu_plugins = [x for x in channel_context_menu_plugins if x not in plugins_to_remove]
		plugins_to_remove = None

		if isPlayableService:
			for p in channel_context_menu_plugins:
				append_when_current_valid(current, menu, (p.description, boundFunction(self.execPlugin, p, csel.getCurrentSelection())))
		if csel.bouquet_mark_edit == OFF and not csel.movemode:
			if not inBouquetRootList:
				isPlayable = not (current_sel_flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
				if isPlayable:
					if config.ParentalControl.configured.value:
						from Components.ParentalControl import parentalControl
						if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
							append_when_current_valid(current, menu, (_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())), level = 0)
						else:
							append_when_current_valid(current, menu, (_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())), level = 0)
					if haveBouquets:
						bouquets = self.csel.getBouquetList()
						if bouquets is None:
							bouquetCnt = 0
						else:
							bouquetCnt = len(bouquets)
						if not inBouquet or bouquetCnt > 1:
							append_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected), level = 0)
					else:
						if not inBouquet:
							append_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected), level = 0)
					# Shaderman --> PiconLoader
					if inBouquet and (config.merlin2.showPiconLoader.value or (fileExists("/etc/enigma2/piconmapper.xml") and config.plugins.piconmapper.activate.value)):
						append_when_current_valid(current, menu, (_("update picon for this service"), self.updatePicons), level = 0)
					if inBouquet and current.getPath():
						append_when_current_valid(current, menu, (_("map to DVB service"), self.mapToDvbService), level = 0)
					if inBouquet:
						if current_sel_flags & 512:
							append_when_current_valid(current, menu, (_("disable StreamRelay"), boundFunction(self.toggleStreamRelay, False)), level = 0)
						else:
							append_when_current_valid(current, menu, (_("enable StreamRelay"), boundFunction(self.toggleStreamRelay, True)), level = 0)
				else:
					if current_root_path.find('FROM SATELLITES') != -1:
						unsigned_orbpos = current.getUnsignedData(4) >> 16
						print "unsigned orbpos %08x" %unsigned_orbpos
						if unsigned_orbpos == 0xFFFF: #Cable
							append_when_current_valid(current, menu, (_("remove cable services"), self.removeSatelliteServices), level = 0)
						elif unsigned_orbpos == 0xEEEE: #Terrestrial
							append_when_current_valid(current, menu, (_("remove terrestrial services"), self.removeSatelliteServices), level = 0)
						else:
							append_when_current_valid(current, menu, (_("remove selected satellite"), self.removeSatelliteServices), level = 0)
					if haveBouquets:
						if not inBouquet and current_sel_path.find("PROVIDERS") == -1:
							append_when_current_valid(current, menu, (_("copy to bouquets"), self.copyCurrentToBouquetList), level = 0)
					if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
						append_when_current_valid(current, menu, (_("remove all new found flags"), self.removeAllNewFoundFlags), level = 0)
				if inBouquet:
					append_when_current_valid(current, menu, (_("remove entry"), self.removeCurrentService), level = 0)
					append_when_current_valid(current, menu, (_("rename entry"), self.renameSelectedEntry), level = 0)
					# Shaderman --> move entry to bouquet
					if haveBouquets and len(self.csel.getBouquetList()) > 1:
						append_when_current_valid(current, menu, (_("move entry into different bouquet"), self.moveEntryToBouquet), level = 0)
				if current_root and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
					append_when_current_valid(current, menu, (_("remove new found flag"), self.removeNewFoundFlag), level = 0)
				if isPlayable and SystemInfo.get("NumVideoDecoders", 1) > 1 and not isinstance(self.csel, ChannelSelectionRadio):
					#Dre: check if PiP is already running
					if self.session.pipshown:
						#Dre: check if selected service is equal to the one running
						if self.session.pip.getCurrentService() == self.csel.servicelist.getCurrent():
							append_when_current_valid(current, menu, (_("Disable Picture in Picture"), self.showServiceInPiP), level = 0, key = "blue")
						else:
							append_when_current_valid(current, menu, (_("Zap Picture in Picture"), self.showServiceInPiP), level = 0, key = "blue")
					else:
						append_when_current_valid(current, menu, (_("Activate Picture in Picture"), self.showServiceInPiP), level = 0, key = "blue")

					self.pipAvailable = True
			else:
					# Shaderman --> PiconLoader
					if (config.merlin2.showPiconLoader.value or (fileExists("/etc/enigma2/piconmapper.xml") and config.plugins.piconmapper.activate.value)):
						append_when_current_valid(current, menu, (_("update picons for this bouquet"), self.updatePicons), level = 0)
					menu.append(ChoiceEntryComponent(text = (_("add bouquet"), self.showBouquetInputBox)))
					append_when_current_valid(current, menu, (_("remove entry"), self.removeBouquet), level = 0)
					append_when_current_valid(current, menu, (_("rename entry"), self.renameSelectedEntry), level = 0)

		if inBouquet: # current list is editable?
			if csel.bouquet_mark_edit == OFF:
				if not csel.movemode:
					append_when_current_valid(current, menu, (_("enable move mode"), self.toggleMoveMode), level = 1)
					if not inBouquetRootList and current_root and not (current_root.flags & eServiceReference.isGroup):
						menu.append(ChoiceEntryComponent(text = (_("add marker"), self.showMarkerInputBox)))
						if haveBouquets:
							append_when_current_valid(current, menu, (_("enable bouquet edit"), self.bouquetMarkStart), level = 0)
						else:
							append_when_current_valid(current, menu, (_("enable favourite edit"), self.bouquetMarkStart), level = 0)
						if current_sel_flags & eServiceReference.isGroup:
							append_when_current_valid(current, menu, (_("edit alternatives"), self.editAlternativeServices), level = 2)
							append_when_current_valid(current, menu, (_("show alternatives"), self.showAlternativeServices), level = 2)
							append_when_current_valid(current, menu, (_("remove all alternatives"), self.removeAlternativeServices), level = 2)
						elif not current_sel_flags & eServiceReference.isMarker:
							append_when_current_valid(current, menu, (_("add alternatives"), self.addAlternativeServices), level = 2)
					# Dre --> PiconMapper
					if inBouquet and config.plugins.piconmapper.activate.value and fileExists("/usr/share/enigma2/sref2name"):
						menu.append(ChoiceEntryComponent(text = (_("add Picon mapping"), self.addPiconMapping)))
				else:
					append_when_current_valid(current, menu, (_("disable move mode"), self.toggleMoveMode), level = 0)
			else:
				if csel.bouquet_mark_edit == EDIT_BOUQUET:
					if haveBouquets:
						append_when_current_valid(current, menu, (_("end bouquet edit"), self.bouquetMarkEnd), level = 0)
						append_when_current_valid(current, menu, (_("abort bouquet edit"), self.bouquetMarkAbort), level = 0)
					else:
						append_when_current_valid(current, menu, (_("end favourites edit"), self.bouquetMarkEnd), level = 0)
						append_when_current_valid(current, menu, (_("abort favourites edit"), self.bouquetMarkAbort), level = 0)
				else:
						append_when_current_valid(current, menu, (_("end alternatives edit"), self.bouquetMarkEnd), level = 0)
						append_when_current_valid(current, menu, (_("abort alternatives edit"), self.bouquetMarkAbort), level = 0)

		append_when_current_valid(current, menu, (_("ChannelSelection Display Settings"), self.displaySettings), level = 2)

		menu.append(ChoiceEntryComponent(text = (_("back"), self.cancelClick)))
		self["menu"] = ChoiceList(menu)

	def okbuttonClick(self):
		self["menu"].getCurrent()[0][1]()

	def cancelClick(self):
		self.close(False)

	def displaySettings(self):
		self.session.openWithCallback(self.close, ChannelSelectionDisplaySettings)

	def toggleStreamRelay(self, enable):
		service = self.csel.servicelist.getCurrent()
		servicename = ServiceReference(service).getServiceName()
		
		if enable:
			service.flags = 512
		else:
			service.flags = 0
		
		self.csel.updateServiceReference(service, True)
		self.close()

	def mapToDvbService(self):
		self.session.openWithCallback(self.updateServiceReference, SimpleChannelSelection, _("Select DVB service..."))
		
	def updateServiceReference(self, targetRef=None):
		if targetRef is not None:
			if targetRef.getPath():
				print "[ChannelContextMenu] channel has path. Abort mapping"
				self.csel.updateServiceReference(None)
			else:
				print "[ChannelContextMenu] add mapping to DVB service"
				targetRefElements = targetRef.toString().split(":")
				service = self.csel.servicelist.getCurrent()
				currentRefElements = service.toString().split(":")
				currentRefLen = len(currentRefElements)
				currentPath = ""
				currentName = ""
				if currentRefLen == 11:
					currentPath = currentRefElements[10]
					newRef = eServiceReference("%s:%s:%s:%s:%s:%s:%s:0:0:0:%s" %(currentRefElements[0], currentRefElements[1], targetRefElements[2], targetRefElements[3], targetRefElements[4], targetRefElements[5], targetRefElements[6], currentPath))
					
					self.csel.updateServiceReference(newRef)
				
				elif currentRefLen == 12:
					currentPath = currentRefElements[10]
					currentName = currentRefElements[11]
					newRef = eServiceReference("%s:%s:%s:%s:%s:%s:%s:0:0:0:%s:%s" %(currentRefElements[0], currentRefElements[1], targetRefElements[2], targetRefElements[3], targetRefElements[4], targetRefElements[5], targetRefElements[6], currentPath, currentName))
					
					self.csel.updateServiceReference(newRef)
		self.close()
			

	# Dre --> PiconMapper
	def addPiconMapping(self):
		
		eServiceCenterInstance = eServiceCenter.getInstance()
		service = self.csel.servicelist.getCurrent()

		if service.flags & (eServiceReference.isDirectory):
			bouquetPath = service.getPath()
			bouquetRootstr = service_types_tv + " " + bouquetPath
			bouquetRoot = eServiceReference(bouquetRootstr)
		
			info = eServiceCenterInstance.info(bouquetRoot)
			print "[ChannelContextMenu] Updating picon mapping for bouquet", info.getName(bouquetRoot)
		
			serviceList = getServicesList(bouquetRoot)
		else:
			info = eServiceCenterInstance.info(service)
			sRef = buildServiceRefString(service)
			print '[ChannelContextMenu] Updating picon mapping for service "%s" (%s)' % (info.getName(service), sRef)
			serviceList = []
			serviceList.append(service)	
		
		self.csel.servicelist.getCurrent()
		info = eServiceCenterInstance.info(service)
		sRef = buildServiceRefString(service)

		self.session.openWithCallback(self.close, PiconMapperScreen, serviceList)	

	def showServiceInformations(self):
		self.session.open( ServiceInfo, self.csel.getCurrentSelection() )

	def showBouquetInputBox(self):
		self.session.openWithCallback(self.bouquetInputCallback, InputBox, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, visible_width = 56, type=Input.TEXT)

	def bouquetInputCallback(self, bouquet):
		if bouquet is not None:
			self.csel.addBouquet(bouquet, None)
		self.close()

	def addParentalProtection(self, service):
		from Components.ParentalControl import parentalControl
		parentalControl.protectService(service.toCompareString())
		self.close()

	def removeParentalProtection(self, service):
		self.session.openWithCallback(boundFunction(self.pinEntered, service.toCompareString()), PinInput, pinList = [config.ParentalControl.servicepin[0].value], triesEntry = config.ParentalControl.retries.servicepin, title = _("Enter the service pin"), windowTitle = _("Change pin code"))

	def pinEntered(self, service, result):
		if result:
			from Components.ParentalControl import parentalControl
			parentalControl.unProtectService(service)
			self.close()
		else:
			self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)

	def showServiceInPiP(self):
		if not self.pipAvailable:
			return
		if self.session.pipshown:
			#Dre: we only start PiP when selected service is not equal to the one running
			if self.session.pip.getCurrentService() != self.csel.servicelist.getCurrent():
				self.session.deleteDialog(self.session.pip)
				del self.session.pip
				self.session.pip = self.session.instantiateDialog(PictureInPicture)
				self.session.pip.show()
				newservice = self.csel.servicelist.getCurrent()
				if self.session.pip.playService(newservice):
					self.session.pipshown = True
					self.session.pip.servicePath = self.csel.getCurrentServicePath()
					self.close(True)
				else:
					self.session.pipshown = False
					self.session.deleteDialog(self.session.pip)
					del self.session.pip
					self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
			else:
				self.session.pipshown = False
				self.session.deleteDialog(self.session.pip)
				del self.session.pip
				self.close(True)
		else:
			self.session.pip = self.session.instantiateDialog(PictureInPicture)
			self.session.pip.show()
			newservice = self.csel.servicelist.getCurrent()
			if self.session.pip.playService(newservice):
				self.session.pipshown = True
				self.session.pip.servicePath = self.csel.getCurrentServicePath()
				self.close(True)
			else:
				self.session.pipshown = False
				self.session.deleteDialog(self.session.pip)
				del self.session.pip
				self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)

	def removeSourcefromBouquets(self, bouquets):
		# remove the source bouquet from the target list
		sourceBouquet = self.csel.servicePath[-1] # the the source bouquet is the last element in the service path
		for bouquet in bouquets:
			if bouquet[1] == sourceBouquet:
				bouquets.remove(bouquet)
				break
		return bouquets

	def addServiceToBouquetSelected(self):
		bouquets = self.csel.getBouquetList()
		if bouquets is None:
			cnt = 0
		else:
			cnt = len(bouquets)
		if cnt > 1: # show bouquet list
			bouquets = self.removeSourcefromBouquets(bouquets)
			self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
		elif cnt == 1: # add to only one existing bouquet
			self.addCurrentServiceToBouquet(bouquets[0][1], closeBouquetSelection = False)

	def bouquetSelClosed(self, recursive):
		self.bsel = None
		if recursive:
			self.close(False)

	def removeSatelliteServices(self):
		current = self.csel.getCurrentSelection()
		unsigned_orbpos = current.getUnsignedData(4) >> 16
		if unsigned_orbpos == 0xFFFF:
			eDVBDB.getInstance().removeServices(-65536) # 0xFFFF0000 as integer
		elif unsigned_orbpos == 0xEEEE:
			eDVBDB.getInstance().removeServices(-286392320) # 0xEEEE0000 as integer
		else:
			curpath = current.getPath()
			idx = curpath.find("satellitePosition == ")
			if idx != -1:
				tmp = curpath[idx+21:]
				idx = tmp.find(')')
				if idx != -1:
					satpos = int(tmp[:idx])
					eDVBDB.getInstance().removeServices(-1, -1, -1, satpos)
		self.close()

	def copyCurrentToBouquetList(self):
		self.csel.copyCurrentToBouquetList()
		self.close()

	def removeBouquet(self):
		self.csel.removeBouquet()
		self.close()

	def showMarkerInputBox(self):
		self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, visible_width = 56, type=Input.TEXT)

	def markerInputCallback(self, marker):
		if marker is not None:
			self.csel.addMarker(marker)
		self.close()

	def addCurrentServiceToBouquet(self, dest, closeBouquetSelection = True):
		self.csel.addServiceToBouquet(dest)
		if self.bsel is not None:
			self.bsel.close(True)
		else:
			self.close(closeBouquetSelection) # close bouquet selection

	def removeCurrentService(self):
		self.csel.removeCurrentService()
		self.close()

	# Shaderman --> move entry to bouquet
	def moveCurrentEntryToBouquet(self, dest, closeBouquetSelection = True):
		self.addCurrentServiceToBouquet(dest)
		self.removeCurrentService()

	# Shaderman --> move entry to bouquet
	def moveEntryToBouquet(self):
		bouquets = self.removeSourcefromBouquets(self.csel.getBouquetList())

		self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.moveCurrentEntryToBouquet)
	
	def toggleMoveMode(self):
		self.csel.toggleMoveMode()
		self.close()

	def renameSelectedEntry(self):
		cur = self.csel.getCurrentSelection()
		eServiceCenterInstance = eServiceCenter.getInstance()
		info = eServiceCenterInstance.info(cur)
		name = info and info.getName(cur) or ""
		#remove short name brakets
		name = name.replace('\xc2\x86', '').replace('\xc2\x87', '')
		if name:
			self.session.openWithCallback(self.csel.renameEntry, InputBox, title=_("Please enter a new name:"), text=name, maxSize=False, visible_width = 56, type=Input.TEXT)
		self.close()

	def bouquetMarkStart(self):
		self.csel.startMarkedEdit(EDIT_BOUQUET)
		self.close()

	def bouquetMarkEnd(self):
		self.csel.endMarkedEdit(abort=False)
		self.close()

	def bouquetMarkAbort(self):
		self.csel.endMarkedEdit(abort=True)
		self.close()

	def removeNewFoundFlag(self):
		eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
		self.close()

	def removeAllNewFoundFlags(self):
		curpath = self.csel.getCurrentSelection().getPath()
		idx = curpath.find("satellitePosition == ")
		if idx != -1:
			tmp = curpath[idx+21:]
			idx = tmp.find(')')
			if idx != -1:
				satpos = int(tmp[:idx])
				eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
		self.close()

	def editAlternativeServices(self):
		self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
		self.close()

	def showAlternativeServices(self):
		self.csel.enterPath(self.csel.getCurrentSelection())
		self.close()

	def removeAlternativeServices(self):
		self.csel.removeAlternativeServices()
		self.close()

	def addAlternativeServices(self):
		self.csel.addAlternativeServices()
		self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
		self.close()

	def execPlugin(self, plugin, service):
		plugin(self.session, service, csel=self.csel)

	# Shaderman --> PiconLoader
	def updatePicons(self):
		# get a list of installed picon sets
		installedSets = loadPiconSetsFromFile()
		url = ""
		oldPath = ""
		
		if not len(installedSets):
			if fileExists("/etc/enigma2/piconmapper.xml") and config.plugins.piconmapper.activate.value:
				pass
			else:
				return
			
		downloadList = []
		
		eServiceCenterInstance = eServiceCenter.getInstance()
		service = self.csel.servicelist.getCurrent()
		
		if service.flags & (eServiceReference.isDirectory):
			bouquetPath = service.getPath()
			bouquetRootstr = service_types_tv + " " + bouquetPath
			bouquetRoot = eServiceReference(bouquetRootstr)
		
			info = eServiceCenterInstance.info(bouquetRoot)
			print "[ChannelContextMenu] Updating picons for bouquet", info.getName(bouquetRoot)
		
			serviceList = getServicesList(bouquetRoot)
		elif service.flags & (eServiceReference.isGroup):
			info = eServiceCenterInstance.info(service)
			print "[ChannelContextMenu] Updating picons for alternative service", info.getName(service)
			serviceList = getServicesList(service)
		else:
			info = eServiceCenterInstance.info(service)
			sRef = buildServiceRefString(service)
			print '[ChannelContextMenu] Updating picon for service "%s" (%s)' % (info.getName(service), sRef)
			serviceList = []
			serviceList.append(service)
			
		self.serviceListLength = len(serviceList)
		self.serviceCounter = 1
		self.showMessage = False
		
		self.unmappedchannels = ""

		for service in serviceList:
			# remove partnerbox-services paths
			if service.getPath():
				x = service.toString().split(':')
				if x[6] != "21":
					oldPath = service.getPath()
					service.setPath("")
			sRef = buildServiceRefString(service)
			info = eServiceCenterInstance.info(service)
			
			name = info.getName(service) or ServiceReference(service).getServiceName() or ""
			self.channelname = name.replace('\xc2\x86', '').replace('\xc2\x87', '')
			
			if len(installedSets) > 0:
				for item in installedSets:
					print item
					name		= item[2]
					self.size   = item[4]
					provider	= item[6]
					path		= item[7]
					
					url = ""
					tunerType = ""
					
					transponderInfo = info.getInfoObject(service, iServiceInformation.sTransponderData)
					if transponderInfo is None:
						print "[PiconLoader] transponderInfo is None"
						#Dre - Partnerbox or IPTV
						if config.plugins.piconmapper.activate.value:
							print "[PiconLoader] Partnerbox channel - piconmapper active"
							url = self.updatePiconsWithPiconMapper(sRef, name)

						if url == "":
							print "[PiconLoader] Partnerbox channel without mapping"
							#service is a partnerbox-service but piconmapper is not used - try to find a sat channel
							position = ""
							if sRef.upper().find("C00000") != -1:
								position = "192"
								tunerType = "DVB-S"
							elif sRef.upper().find("820000") != -1:
								position = "130"
								tunerType = "DVB-S"
							elif sRef.upper().find("11C000") != -1:
								position = "282"
								tunerType = "DVB-S"
							else:
								url = ""
								print "[PiconLoader] No Mapping for channel ", self.channelname
								self.showMessage = True
								self.unmappedchannels += self.channelname + " (%s)\n" %(self.size)
						
							if position != "":
								print "[PiconLoader] Partnerbox channel Astra, Hotbird or Astra2"
								url = PICONBASEURL + "DVB-S/" + item[2] + "/" + position + "/" + sRef + ".png"
								print url
					
						service.setPath(oldPath)
					else:
						print "[PiconLoader] transponderInfo is not None"	
						frontendData = ConvertToHumanReadable(transponderInfo)
						
						if frontendData.has_key("tuner_type"):
							if frontendData["tuner_type"] == _("Cable"):
							    tunerType  =  "DVB-C"
							elif frontendData["tuner_type"] == _("Satellite"):
							    tunerType  =  "DVB-S"
						if tunerType == "DVB-S":
							position = str(transponderInfo["orbital_position"])	
							print "[PiconLoader] DVB-S"
							url = PICONBASEURL + tunerType + "/" + name + "/" + position + "/" + sRef + ".png"
						elif tunerType == "DVB-C":
							if config.plugins.piconmapper.activate.value and tunerType != item[0]:
								print "[PiconLoader] DVB-C - piconmapper active"
								url = self.updatePiconsWithPiconMapper(sRef, name)
								if url == "":
									self.showMessage = True
									self.unmappedchannels += self.channelname + " (%s)\n" %(self.size)
							elif item[0] == "DVB-C":
								print "[PiconLoader] DVB-C"
								url = PICONBASEURL + tunerType + "/" + name + "/" + provider + "/" + sRef + ".png"
							else:
								print "[PiconLoader] - DVB-C channel but no DVB-C PiconSet"
								self.showMessage = True
								self.unmappedchannels += self.channelname + " (%s)\n" %(self.size)
						else:
							#Dre
							#DVB-T
							if config.plugins.piconmapper.activate.value:
								print "[PiconLoader] DVB-T - piconmapper active"
								url = self.updatePiconsWithPiconMapper(sRef, name)
								if url == "":
									self.showMessage = True
									self.unmappedchannels += self.channelname + " (%s)\n" %(self.size)								

					if url != "":
						fileName = path + "/" + sRef + ".png"
						# dre - use channel name instead of sref
						if config.merlin2.skin_piconmode.value == "Name":
							channelName = re.sub('[^0-9a-zA-Z]+', '_', self.channelname)
							fileName = path + "/" + channelName + ".png"
						downloadList.append(PiconSetInfo(url = url, path = path, filename = fileName, channelname = self.channelname, tunerType = tunerType, sref = sRef ))
			
			self.serviceCounter += 1
			
		if self.showMessage:
			info = self.session.open(MessageBox,_("No picon found for the following channels:\n%s") %(self.unmappedchannels), MessageBox.TYPE_INFO)
			info.setTitle(_("Picon Loader"))
					
		if len(downloadList):
			self.session.openWithCallback(None, FileDownload, downloadList)

	#Dre
	def updatePiconsWithPiconMapper(self, sRef, name=""):
		print "[PiconLoader] getting mapping from PiconMapper"
		if fileExists("/etc/enigma2/piconmapper.xml"):
			# replace local sRef with matching satellite sRef
			url = ""
			mappedsRef = self.findSatSref(sRef)
			if mappedsRef is None:
				return url
			else:
				splittedsref = []
				splittedsref = mappedsRef.split("_")
				position = int(splittedsref[6][0:2], 16)

				self.piconset = name
				url = PICONBASEURL + "DVB-S/" + self.piconset + "/" + str(position) + "/" + mappedsRef + ".png"

				return url

	def getSelection(self, ret):
		self.piconset = ret
		print ret
		return ret
	
	#Dre
	def findSatSref(self, sRef):
		piconmapper = file("/etc/enigma2/piconmapper.xml", "r")
			
		piconmapperdom = etree.parse(piconmapper)
			
		xmldata = piconmapperdom.getroot()
			
		piconmapper.close()
			
		for x in xmldata.findall('piconmapping'):
			if x.get('localsref') == sRef:
				return x.get('satsref')
		
		return None

class SelectionEventInfo:
	def __init__(self):
		self["ServiceEvent"] = ServiceEvent()
		#Dr.Best
		self["ServiceEventReference"] = ServiceEventReference()
		self.servicelist.connectSelChanged(self.__selectionChanged)
		self.timer = eTimer()
		self.timer_conn = self.timer.timeout.connect(self.updateEventInfo)
		self.onShown.append(self.__selectionChanged)

	def __selectionChanged(self):
		if self.execing:
			#Dr.Best
			if config.merlin2.minitv.value:
				service = self.session.nav.getCurrentService()
				if service:
					info = service.info()
					if info:
						refstr = info.getInfoString(iServiceInformation.sServiceref)
						self["ServiceEventReference"].newServices(self.getCurrentSelection(), eServiceReference(refstr))
			self.timer.start(100, True)

	def updateEventInfo(self):
		cur = self.getCurrentSelection()
		self["ServiceEvent"].newService(cur)

class ChannelSelectionEPG:
	def __init__(self):
		self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
			{
				"showEPGList": self.showEPGList,
			})

	def showEPGList(self):
		ref=self.getCurrentSelection()
		if ref:
			if config.merlin2.channelselection_eventinfo.value: # EventInfo in Channelselection
				epgcache = eEPGCache.getInstance()
				newEvent = epgcache.lookupEventTime(ref, -1) 
				self.session.open(EventViewEPGSelect, newEvent, ServiceReference(ref),None ,self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
			else:
				self.savedService = ref
				self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB=self.changeServiceCB)

# Start -------> EventInfo in Channelselection
	def zapToService(self, service):
		if not service is None:
			self.setCurrentSelection(service) #select the service in servicelist
			self.zap()

	def getBouquetServices(self, bouquet):
		services = [ ]
		servicelist = eServiceCenter.getInstance().list(bouquet)
		if not servicelist is None:
			while True:
				service = servicelist.getNext()
				if not service.valid(): #check if end of list
					break
				if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
					continue
				services.append(ServiceReference(service))
		return services

	def openMultiServiceEPG(self):
		services = self.getBouquetServices(self.getRoot())
		if services:
			self.session.open(EPGSelection, services, self.zapToService)

	def openSingleServiceEPG(self):
		ref=self.getCurrentSelection()
		if ref:
			self.savedService = ref
			self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB=self.changeServiceCB)

	def openSimilarList(self, eventid, refstr):
		self.session.open(EPGSelection, refstr, None, eventid)

# End -------> EventInfo in Channelselection

	def SingleServiceEPGClosed(self, ret=False):
		self.setCurrentSelection(self.savedService)

	def changeServiceCB(self, direction, epg):
		beg = self.getCurrentSelection()
		while True:
			if direction > 0:
				self.moveDown()
			else:
				self.moveUp()
			cur = self.getCurrentSelection()
			if cur == beg or not (cur.flags & eServiceReference.isMarker):
				break
		epg.setService(ServiceReference(self.getCurrentSelection()))

class ChannelSelectionEdit:
	def __init__(self):
		self.entry_marked = False
		self.movemode = False
		self.bouquet_mark_edit = OFF
		self.mutableList = None
		self.__marked = [ ]
		self.saved_title = None
		self.saved_root = None

		class ChannelSelectionEditActionMap(ActionMap):
			def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
				ActionMap.__init__(self, contexts, actions, prio)
				self.csel = csel

			def action(self, contexts, action):
				if action == "cancel":
					self.csel.handleEditCancel()
					return 0 # fall-trough
				elif action == "ok":
					return 0 # fall-trough
				else:
					return ActionMap.action(self, contexts, action)

		self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
			{
				"contextMenu": self.doContext,
			})

	def getMutableList(self, root=eServiceReference()):
		if not self.mutableList is None:
			return self.mutableList
		serviceHandler = eServiceCenter.getInstance()
		if not root.valid():
			root=self.getRoot()
		list = root and serviceHandler.list(root)
		if list is not None:
			return list.startEdit()
		return None

	def buildBouquetID(self, str):
		tmp = str.lower()
		name = ''
		for c in tmp:
			if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
				name += c
			else:
				name += '_'
		return name

	def renameEntry(self, name):
		cur = self.servicelist.getCurrent()
		bouquet = self.getMutableList()
		if bouquet and name is not None:
			idx = self.servicelist.getCurrentIndex()
			if cur.flags & eServiceReference.mustDescent: # bouquet or service with alternatives
				mutableList = self.getMutableList(cur)
				mutableList.setListName(name)
				mutableList.flushChanges()
			else:
				cur.setName(name)
				self.servicelist.addService(cur, True) # add the new entry above the current position
				self.servicelist.removeCurrent()
				if not self.servicelist.atEnd():
					self.servicelist.moveUp()
				bouquet.removeService(cur)
				bouquet.addService(cur)
				bouquet.moveService(cur, idx)
				bouquet.flushChanges()
				
	def updateServiceReference(self, newServiceReference, isStreamRelay=False):
		cur = self.servicelist.getCurrent()
		print "cur", cur
		bouquet = self.getMutableList()
		print "bouquet", bouquet
		if bouquet and newServiceReference is not None:
			idx = self.servicelist.getCurrentIndex()
			self.servicelist.addService(newServiceReference, True) # add the new entry above the current position
			self.servicelist.removeCurrent()
			if not self.servicelist.atEnd():
				self.servicelist.moveUp()
			bouquet.removeService(cur)
			bouquet.addService(newServiceReference)
			bouquet.moveService(newServiceReference, idx)
			bouquet.flushChanges()
			if isStreamRelay:
				self.session.open(MessageBox, _("Service converted successfully"), MessageBox.TYPE_INFO, timeout=5)
			else:
				self.session.open(MessageBox, _("Service mapped successfully"), MessageBox.TYPE_INFO, timeout=5)
		elif bouquet:
			self.session.open(MessageBox, _("Cannot map to non-DVB service."), MessageBox.TYPE_ERROR, timeout=5)
			
				
	def addMarker(self, name):
		current = self.servicelist.getCurrent()
		mutableList = self.getMutableList()
		cnt = 0
		while mutableList:
			str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
			ref = eServiceReference(str)
			if current and current.valid():
				if not mutableList.addService(ref, current):
					self.servicelist.addService(ref, True)
					mutableList.flushChanges()
					break
			elif not mutableList.addService(ref):
				self.servicelist.addService(ref, True)
				mutableList.flushChanges()
				break
			cnt+=1

	def addAlternativeServices(self):
		cur_service = ServiceReference(self.getCurrentSelection())
		root = self.getRoot()
		cur_root = root and ServiceReference(root)
		mutableBouquet = cur_root.list().startEdit()
		if mutableBouquet:
			name = cur_service.getServiceName()
			print "NAME", name
			if self.mode == MODE_TV:
				str = '1:134:1:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(name))
			else:
				str = '1:134:2:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(name))
			new_ref = ServiceReference(str)
			if not mutableBouquet.addService(new_ref.ref, cur_service.ref):
				mutableBouquet.removeService(cur_service.ref)
				mutableBouquet.flushChanges()
				eDVBDB.getInstance().reloadBouquets()
				mutableAlternatives = new_ref.list().startEdit()
				if mutableAlternatives:
					mutableAlternatives.setListName(name)
					if mutableAlternatives.addService(cur_service.ref):
						print "add", cur_service.ref.toString(), "to new alternatives failed"
					mutableAlternatives.flushChanges()
					self.servicelist.removeCurrent()
					self.servicelist.addService(new_ref.ref, True)
				else:
					print "get mutable list for new created alternatives failed"
			else:
				print "add", str, "to", cur_root.getServiceName(), "failed"
		else:
			print "bouquetlist is not editable"

	def addBouquet(self, bName, services):
		serviceHandler = eServiceCenter.getInstance()
		mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
		if mutableBouquetList:
			if self.mode == MODE_TV:
				bName += " (TV)"
				str = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
			else:
				bName += " (Radio)"
				str = '1:7:2:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
			new_bouquet_ref = eServiceReference(str)
			if not mutableBouquetList.addService(new_bouquet_ref):
				mutableBouquetList.flushChanges()
				eDVBDB.getInstance().reloadBouquets()
				mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
				if mutableBouquet:
					mutableBouquet.setListName(bName)
					if services is not None:
						for service in services:
							if mutableBouquet.addService(service):
								print "add", service.toString(), "to new bouquet failed"
					mutableBouquet.flushChanges()
				else:
					print "get mutable list for new created bouquet failed"
				# do some voodoo to check if current_root is equal to bouquet_root
				cur_root = self.getRoot();
				str1 = cur_root and cur_root.toString()
				pos1 = str1 and str1.find("FROM BOUQUET") or -1
				pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
				if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
					self.servicelist.addService(new_bouquet_ref)
			else:
				print "add", str, "to bouquets failed"
		else:
			print "bouquetlist is not editable"

	def copyCurrentToBouquetList(self):
		provider = ServiceReference(self.getCurrentSelection())
		providerName = provider.getServiceName()
		serviceHandler = eServiceCenter.getInstance()
		services = serviceHandler.list(provider.ref)
		self.addBouquet(providerName, services and services.getContent('R', True))

	def removeAlternativeServices(self):
		cur_service = ServiceReference(self.getCurrentSelection())
		root = self.getRoot()
		cur_root = root and ServiceReference(root)
		list = cur_service.list()
		first_in_alternative = list and list.getNext()
		if first_in_alternative:
			edit_root = cur_root and cur_root.list().startEdit()
			if edit_root:
				if not edit_root.addService(first_in_alternative, cur_service.ref):
					self.servicelist.addService(first_in_alternative, True)
					self.servicelist.setCurrent(cur_service.ref)
				else:
					print "couldn't add first alternative service to current root"
			else:
				print "couldn't edit current root!!"
		else:
			print "remove empty alternative list !!"
		self.removeBouquet()
		if first_in_alternative:
			self.servicelist.setCurrent(first_in_alternative) 

	def removeBouquet(self):
		refstr = self.getCurrentSelection().toString()
		print "removeBouquet", refstr
		self.bouquetNumOffsetCache = { }
		pos = refstr.find('FROM BOUQUET "')
		filename = None
		if pos != -1:
			refstr = refstr[pos+14:]
			pos = refstr.find('"')
			if pos != -1:
				filename = eEnv.resolve('${sysconfdir}/enigma2/') + refstr[:pos]
		self.removeCurrentService()
		try:
			if filename is not None:
				remove(filename)
		except OSError:
			print "error during remove of", filename

#  multiple marked entry stuff ( edit mode, later multiepg selection )
	def startMarkedEdit(self, type):
		self.savedPath = self.servicePath[:]
		if type == EDIT_ALTERNATIVES:
			self.enterPath(self.getCurrentSelection())
		self.mutableList = self.getMutableList()
		# add all services from the current list to internal marked set in listboxservicecontent
		self.clearMarks() # this clears the internal marked set in the listboxservicecontent
		self.saved_title = self.getTitle()
		pos = self.saved_title.find(')')
		new_title = self.saved_title[:pos+1]
		if type == EDIT_ALTERNATIVES:
			self.bouquet_mark_edit = EDIT_ALTERNATIVES
			new_title += ' ' + _("[alternative edit]")
		else:
			self.bouquet_mark_edit = EDIT_BOUQUET
			if config.usage.multibouquet.value:
				new_title += ' ' + _("[bouquet edit]")
			else:
				new_title += ' ' + _("[favourite edit]")
		self.setTitle(_(new_title))
		self.__marked = self.servicelist.getRootServices()
		for x in self.__marked:
			self.servicelist.addMarked(eServiceReference(x))
		self.showAllServices()

	def endMarkedEdit(self, abort):
		if not abort and self.mutableList is not None:
			self.bouquetNumOffsetCache = { }
			new_marked = set(self.servicelist.getMarked())
			old_marked = set(self.__marked)
			removed = old_marked - new_marked
			added = new_marked - old_marked
			changed = False
			for x in removed:
				changed = True
				self.mutableList.removeService(eServiceReference(x))
			for x in added:
				changed = True
				self.mutableList.addService(eServiceReference(x))
			if changed:
				self.mutableList.flushChanges()
		self.__marked = []
		self.clearMarks()
		self.bouquet_mark_edit = OFF
		self.mutableList = None
		self.setTitle(_(self.saved_title))
		self.saved_title = None
		# self.servicePath is just a reference to servicePathTv or Radio...
		# so we never ever do use the asignment operator in self.servicePath
		del self.servicePath[:] # remove all elements
		self.servicePath += self.savedPath # add saved elements
		del self.savedPath
		self.setRoot(self.servicePath[-1])

	def clearMarks(self):
		self.servicelist.clearMarks()

	def doMark(self):
		ref = self.servicelist.getCurrent()
		if self.servicelist.isMarked(ref):
			self.servicelist.removeMarked(ref)
		else:
			self.servicelist.addMarked(ref)

	def removeCurrentService(self):
		ref = self.servicelist.getCurrent()
		mutableList = self.getMutableList()
		if ref.valid() and mutableList is not None:
			if not mutableList.removeService(ref):
				self.bouquetNumOffsetCache = { }
				mutableList.flushChanges() #FIXME dont flush on each single removed service
				self.servicelist.removeCurrent()

	def addServiceToBouquet(self, dest, service=None):
		mutableList = self.getMutableList(dest)
		if not mutableList is None:
			if service is None: #use current selected service
				service = self.servicelist.getCurrent()
			if not mutableList.addService(service):
				self.bouquetNumOffsetCache = { }
				mutableList.flushChanges()
				# do some voodoo to check if current_root is equal to dest
				cur_root = self.getRoot();
				str1 = cur_root and cur_root.toString() or -1
				str2 = dest.toString()
				pos1 = str1.find("FROM BOUQUET")
				pos2 = str2.find("FROM BOUQUET")
				if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
					self.servicelist.addService(service)
			# dre: read services again to show tick when tag bouquet services is enabled
			if config.usage.configselection_tagBouquetServices.value:
				self.servicelist.getAllBouquetServices()					

	def toggleMoveMode(self):
		if self.movemode:
			if self.entry_marked:
				self.toggleMoveMarked() # unmark current entry
			self.movemode = False
			self.pathChangeDisabled = False # re-enable path change
			self.mutableList.flushChanges() # FIXME add check if changes was made
			self.mutableList = None
			self.setTitle(_(self.saved_title))
			self.saved_title = None
			cur_root = self.getRoot()
			if cur_root and cur_root == self.bouquet_root:
				self.bouquetNumOffsetCache = { }
		else:
			self.mutableList = self.getMutableList()
			self.movemode = True
			self.pathChangeDisabled = True # no path change allowed in movemode
			self.saved_title = self.getTitle()
			new_title = self.saved_title
			pos = self.saved_title.find(')')
			new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
			self.setTitle(_(new_title))

	def handleEditCancel(self):
		if self.movemode: #movemode active?
			if self.entry_marked:
				self.channelSelected() # unmark
			self.toggleMoveMode() # disable move mode
		elif self.bouquet_mark_edit != OFF:
			self.endMarkedEdit(True) # abort edit mode

	def toggleMoveMarked(self):
		if self.entry_marked:
			self.servicelist.setCurrentMarked(False)
			self.entry_marked = False
		else:
			self.servicelist.setCurrentMarked(True)
			self.entry_marked = True

	def doContext(self):
		self.session.openWithCallback(self.exitContext, ChannelContextMenu, self)

	def exitContext(self, close = False):
		if close:
			self.cancel()

MODE_TV = 0
MODE_RADIO = 1

# type 1 = digital television service
# type 4 = nvod reference service (NYI)
# type 17 = MPEG-2 HD digital television service
# type 22 = advanced codec SD digital television
# type 24 = advanced codec SD NVOD reference service (NYI)
# type 25 = advanced codec HD digital television
# type 27 = advanced codec HD NVOD reference service (NYI)
# type 2 = digital radio sound service
# type 10 = advanced codec digital radio sound service

service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 31) || (type == 134) || (type == 195)'
#Dr.Best --> HD Services
service_types_tv_hd = '1:7:1:0:0:0:0:0:0:0:(type == 17) || (type == 25) || (type == 31) || (type == 134) || (type == 195)'
service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'

class ChannelSelectionBase(Screen):
	ALLOW_SUSPEND = Screen.SUSPEND_STOPS

	def __init__(self, session):
		Screen.__init__(self, session)

		self["key_red"] = Button("")
		self["key_green"] = Button("")
		self["key_yellow"] = Button("")
		self["key_blue"] = Button(_("Favourites"))

		self["list"] = ServiceList(session)
		self.servicelist = self["list"]

		self.numericalTextInput = NumericalTextInput()
		self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')

		self.servicePathTV = [ ]
		self.servicePathRadio = [ ]
		self.servicePath = [ ]
		self.rootChanged = False
		self.bouquet_root = None

		self.mode = MODE_TV

		self.pathChangeDisabled = False

		self.bouquetNumOffsetCache = { }
		self.onRootChanged = []

		self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions", "InputAsciiActions"],
			{
				"showFavourites": self.showFavourites,
				"showAllServices": self._openPlugins,
				"showProviders": self.showProviders,
				"showSatellites": self.showSatellites,
				"nextBouquet": self.nextBouquet,
				"prevBouquet": self.prevBouquet,
				"nextMarker": self.nextMarker,
				"prevMarker": self.prevMarker,
				"gotAsciiCode": self.keyAsciiCode,
				"selectServiceDown": None, #avoid debug output warning
				"selectServiceUp": None, #avoid debug output warning
				"selectServicePageDown": None, #avoid debug output warning
				"selectServicePageUp": None, #avoid debug output warning
				"1": self.keyNumberGlobal,
				"2": self.keyNumberGlobal,
				"3": self.keyNumberGlobal,
				"4": self.keyNumberGlobal,
				"5": self.keyNumberGlobal,
				"6": self.keyNumberGlobal,
				"7": self.keyNumberGlobal,
				"8": self.keyNumberGlobal,
				"9": self.keyNumberGlobal,
				"0": self.keyNumber0
			})

		self.moreTextActive = False
		config.merlin2.channelselection_more_on_color.addNotifier(self.setButtons)
		self.onClose.append(self.removeNotifier)
		
		self.setTitle(_("Channel Selection"))
		self._pluginList = []
		self._checkPlugins()
		self.recallBouquetMode()

	def removeNotifier(self):
		config.merlin2.channelselection_more_on_color.removeNotifier(self.setButtons)
		
	def setButtons(self, val):
		self.moreKeyColor = config.merlin2.channelselection_more_on_color.value
		
		if self.moreKeyColor == "key_green":
			self["key_red"].setText(_("All"))
			self["key_yellow"].setText(_("Providers"))
			self.moreButtonText = _("Satellites")
			self.moreFunc = self.showSatellites
		elif self.moreKeyColor == "key_yellow":
			self["key_red"].setText(_("All"))
			self["key_green"].setText(_("Satellites"))	
			self.moreButtonText = _("Providers")
			self.moreFunc = self.showProviders		
		else:
			self["key_green"].setText(_("Satellites"))		
			self["key_yellow"].setText(_("Providers"))	
			self.moreButtonText = _("All")
			self.moreFunc = self.showAllServices
		if self.moreTextActive:
			self[self.moreKeyColor].setText(_("More ..."))
			del self._pluginList[-1]
			self._pluginList.append((self.moreButtonText, self.moreFunc, True))
		else:
			self[self.moreKeyColor].setText(self.moreButtonText)
			
		if self.moreKeyColor == "key_green":
			self["ChannelSelectBaseActions"].actions["showAllServices"] = self.showAllServices
			self["ChannelSelectBaseActions"].actions["showSatellites"] = self._openPlugins
			self["ChannelSelectBaseActions"].actions["showProviders"] = self.showProviders
		elif self.moreKeyColor == "key_yellow":
			self["ChannelSelectBaseActions"].actions["showAllServices"] = self.showAllServices
			self["ChannelSelectBaseActions"].actions["showSatellites"] = self.showSatellites
			self["ChannelSelectBaseActions"].actions["showProviders"] = self._openPlugins		
	
	def getCurrentEventNow(self):
		serviceref = self.servicelist.getCurrent()
		event = None
		try:
			epg = eEPGCache.getInstance()
			event = epg.lookupEventTime(serviceref, -1, 0)
			if event is None:
				info = eServiceCenter.getInstance().info(serviceref)
				event = info.getEvent(0)
		except:
			pass
		return event

	def _checkPlugins(self):
		self._pluginList = [(p.name, p, False) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_CHANNEL_SELECTION_RED)]
		self._pluginList.append((self.moreButtonText, self.moreFunc , True))
		if self._pluginList:
			if len(self._pluginList) > 1:
	 			self[self.moreKeyColor].setText(_("More ..."))
	 			self.moreTextActive = True
	 		else:
	 			self[self.moreKeyColor].setText(self._pluginList[0][0])
	 	else:
	 		self[self.moreKeyColor].setText("")
	 		
	def _openPlugins(self):
		if self._pluginList:
			if len(self._pluginList) > 1:
				self.session.openWithCallback(self._onPluginSelected, ChoiceBox, list=self._pluginList, windowTitle=_("More ..."))
			else:
				self._onPluginSelected(self._pluginList[0])

	def _onPluginSelected(self, p=None):
		noargs = p and p[2]
		fnc = p and p[1]
		if not fnc:
			return
		if noargs: #noarg for multiepgcallback backwards compat
			fnc()
			return

		event = self.getCurrentEventNow()
		if not event:
			self.session.toastManager.showToast(_("This feature requires valid EPG!"))
			return
		fnc(self.session, event, self.servicelist.getCurrent())

	# Shaderman tag bouquet services
	def tagBouquetServicesChanged(self, configElement):
		if configElement.value:
			if not self.onServiceListRootChanged in self.onRootChanged:
				self.onRootChanged.append(self.onServiceListRootChanged)
		else:
			if self.onServiceListRootChanged in self.onRootChanged:
				self.onRootChanged.remove(self.onServiceListRootChanged)
			
	# Shaderman tag bouquet services
	def onServiceListRootChanged(self, ref):
			if self.getMutableList(): # FAVOURITES
				self.servicelist.showBouquetEntries = False
			else: # ALL SERVICES, SATELLITES, PROVIDERS
				self.servicelist.showBouquetEntries = True
				self.servicelist.getAllBouquetServices()
				
	def getBouquetNumOffset(self, bouquet):
		if not config.usage.multibouquet.value:
			return 0
		str = bouquet.toString()
		offsetCount = 0
		if not self.bouquetNumOffsetCache.has_key(str):
			serviceHandler = eServiceCenter.getInstance()
			bouquetlist = serviceHandler.list(self.bouquet_root)
			if not bouquetlist is None:
				while True:
					bouquetIterator = bouquetlist.getNext()
					if not bouquetIterator.valid(): #end of list
						break
					self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
					if not (bouquetIterator.flags & eServiceReference.isDirectory):
						continue
					servicelist = serviceHandler.list(bouquetIterator)
					if not servicelist is None:
						while True:
							serviceIterator = servicelist.getNext()
							if not serviceIterator.valid(): #check if end of list
								break
							playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
							if playable:
								offsetCount += 1
		return self.bouquetNumOffsetCache.get(str, offsetCount)

	def recallBouquetMode(self):
		fixServicePath = self.servicePath and self.servicePath[0] == self.bouquet_root
		if self.mode == MODE_TV:
			self.service_types = service_types_tv
			if config.usage.multibouquet.value:
				self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
			else:
				self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
		else:
			self.service_types = service_types_radio
			if config.usage.multibouquet.value:
				self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
			else:
				self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)

		self.bouquet_root = eServiceReference(self.bouquet_rootstr)
		if fixServicePath:
			self.servicePath = []
			self.servicePath.append(self.bouquet_root)

	def setTvMode(self):
		self.mode = MODE_TV
		self.servicePath = self.servicePathTV
		self.recallBouquetMode()
		title = self.getTitle()
		pos = title.find(" (")
		if pos != -1:
			title = title[:pos]
		title = _(title) + " (TV)"
		self.setTitle(_(title))

	def setRadioMode(self):
		self.mode = MODE_RADIO
		self.servicePath = self.servicePathRadio
		self.recallBouquetMode()
		title = self.getTitle()
		pos = title.find(" (")
		if pos != -1:
			title = title[:pos]
		title = _(title) + " (Radio)"
		self.setTitle(_(title))

	def setRoot(self, root, justSet=False):
		setModeFavourites = False

		serviceHandler = eServiceCenter.getInstance()
		list = root and serviceHandler.list(root)
		if list is not None:
			if list.startEdit():
				ref = list.getNext()
				setModeFavourites = not (ref.flags & eServiceReference.isDirectory)

		if setModeFavourites:
			self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
			self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
		else:
			self.servicelist.setMode(ServiceList.MODE_NORMAL)

		if config.usage.configselection_tagBouquetServices.value:
			self.servicelist.showBouquetEntries = False
		
		self.servicelist.setRoot(root, justSet)
		self.rootChanged = True
		self.buildTitleString()

	def removeModeStr(self, str):
		if self.mode == MODE_TV:
			pos = str.find(' (TV)')
		else:
			pos = str.find(' (Radio)')
		if pos != -1:
			return str[:pos]
		return str

	def getServiceName(self, ref):
		str = self.removeModeStr(ServiceReference(ref).getServiceName())
		if not str:
			pathstr = ref.getPath()
			if 'FROM PROVIDERS' in pathstr:
				return _("Providers")
			if 'FROM SATELLITES' in pathstr:
				return _("Satellites")
			if ') ORDER BY name' in pathstr:
				if config.merlin2.show_only_available_services.value:
					return _("All available")
				else:
					return _("All")
		return str

	def buildTitleString(self):
		titleStr = self.getTitle()
		pos = titleStr.find(']')
		if pos == -1:
			pos = titleStr.find(')')
		if pos != -1:
			titleStr = titleStr[:pos+1]
			Len = len(self.servicePath)
			if Len > 0:
				base_ref = self.servicePath[0]
				if Len > 1:
					end_ref = self.servicePath[Len-1]
				else:
					end_ref = None
				nameStr = self.getServiceName(base_ref)
				titleStr += ' ' + nameStr
				if end_ref is not None:
					if Len > 2:
						titleStr += '/../'
					else:
						titleStr += '/'
					nameStr = self.getServiceName(end_ref)
					titleStr += nameStr
				self.setTitle(_(titleStr))

	def moveUp(self):
		self.servicelist.moveUp()

	def moveDown(self):
		self.servicelist.moveDown()

	def clearPath(self):
		del self.servicePath[:]

	def enterPath(self, ref, justSet=False):
		self.servicePath.append(ref)
		self.setRoot(ref, justSet)
		for fnc in self.onRootChanged:
			fnc(ref)

	def pathUp(self, justSet=False):
		prev = self.servicePath.pop()
		if self.servicePath:
			current = self.servicePath[-1]
			self.setRoot(current, justSet)
			if not justSet:
				self.setCurrentSelection(prev)
		return prev

	def isBasePathEqual(self, ref):
		if len(self.servicePath) > 1 and self.servicePath[0] == ref:
			return True
		return False

	def isPrevPathEqual(self, ref):
		length = len(self.servicePath)
		if length > 1 and self.servicePath[length-2] == ref:
			return True
		return False

	def preEnterPath(self, refstr):
		return False

	def showAllServices(self):
		if not self.pathChangeDisabled:
			refstr = '%s ORDER BY name'%(self.service_types)
			if not self.preEnterPath(refstr):
				ref = eServiceReference(refstr)
				currentRoot = self.getRoot()
				if currentRoot is None or currentRoot != ref:
					self.clearPath()
					self.enterPath(ref)

	def showSatellites(self):
		if not self.pathChangeDisabled:
			refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
			if not self.preEnterPath(refstr):
				ref = eServiceReference(refstr)
				justSet=False
				prev = None

				if self.isBasePathEqual(ref):
					if self.isPrevPathEqual(ref):
						justSet=True
					prev = self.pathUp(justSet)
				else:
					currentRoot = self.getRoot()
					if currentRoot is None or currentRoot != ref:
						justSet=True
						self.clearPath()
						self.enterPath(ref, True)
				if justSet:
					serviceHandler = eServiceCenter.getInstance()
					#Dr.Best --> HD Services
					counter = i = 0
					if config.servicelist.lastmode.value == "tv" and HardwareInfo().get_device_name() != "dm7025":
						counter = 1
					while i <= counter:
						if i:
							refstr ='%s FROM SATELLITES ORDER BY satellitePosition'%(service_types_tv_hd)
							ref = eServiceReference(refstr)
						servicelist = serviceHandler.list(ref)
						if not servicelist is None:
							while True:
								service = servicelist.getNext()
								if not service.valid(): #check if end of list
									break
								unsigned_orbpos = service.getUnsignedData(4) >> 16
								orbpos = service.getData(4) >> 16
								if orbpos < 0:
									orbpos += 3600
								if service.getPath().find("FROM PROVIDER") != -1:
									service_type = _("Providers")
								elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
									service_type = _("New")
								elif service.getPath().find("numCAIDs") != -1:
									service_type = _("Services") + " FTA"
								else:
									service_type = _("Services")
								try:
									# why we need this cast?
									service_name = str(nimmanager.getSatDescription(orbpos))
								except:
									if unsigned_orbpos == 0xFFFF: #Cable
										service_name = _("Cable")
									elif unsigned_orbpos == 0xEEEE: #Terrestrial
										service_name = _("Terrestrial")
									else:
										if orbpos > 1800: # west
											orbpos = 3600 - orbpos
											h = _("W")
										else:
											h = _("E")
										service_name = ("%d.%d" + h) % (orbpos / 10, orbpos % 10)
								#Dr.Best --> HD Services
								if i:
									service_type = "HD %s" % service_type
								service.setName("%s - %s" % (service_name, service_type))
								self.servicelist.addService(service)
						i += 1 #Dr.Best --> HD Services
					self.servicelist.finishFill()
					cur_ref = self.session.nav.getCurrentlyPlayingServiceReference()
					if cur_ref:
						pos = self.service_types.rfind(':')
						refstr = '%s (channelID == %08x%04x%04x) && %s ORDER BY name' %(self.service_types[:pos+1],
							cur_ref.getUnsignedData(4), # NAMESPACE
							cur_ref.getUnsignedData(2), # TSID
							cur_ref.getUnsignedData(3), # ONID
							self.service_types[pos+1:])
						ref = eServiceReference(refstr)
						ref.flags |= eServiceReference.sort1 # needed for sort
						ref.setName(_("Current Transponder"))
						self.servicelist.addService(ref, True)
						self.servicelist.moveUp()
					if prev is not None:
						self.setCurrentSelection(prev)

	def showProviders(self):
		if not self.pathChangeDisabled:
			refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
			if not self.preEnterPath(refstr):
				ref = eServiceReference(refstr)
				if self.isBasePathEqual(ref):
					self.pathUp()
				else:
					currentRoot = self.getRoot()
					if currentRoot is None or currentRoot != ref:
						self.clearPath()
						self.enterPath(ref)

	def changeBouquet(self, direction):
		if not self.pathChangeDisabled:
			if len(self.servicePath) > 1:
				#when enter satellite root list we must do some magic stuff..
				ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
				if self.isBasePathEqual(ref):
					self.showSatellites()
				else:
					self.pathUp()
				if direction < 0:
					self.moveUp()
				else:
					self.moveDown()
				ref = self.getCurrentSelection()
				self.enterPath(ref)

	def inBouquet(self):
		if self.servicePath and self.servicePath[0] == self.bouquet_root:
			return True
		return False

	def atBegin(self):
		return self.servicelist.atBegin()

	def atEnd(self):
		return self.servicelist.atEnd()

	def nextBouquet(self):
		self.changeBouquet(+1)

	def prevBouquet(self):
		self.changeBouquet(-1)

	def showFavourites(self):
		if not self.pathChangeDisabled:
			if not self.preEnterPath(self.bouquet_rootstr):
				if self.isBasePathEqual(self.bouquet_root):
					self.pathUp()
				else:
					currentRoot = self.getRoot()
					if currentRoot is None or currentRoot != self.bouquet_root:
						self.clearPath()
						self.enterPath(self.bouquet_root)

	def keyNumberGlobal(self, number):
		unichar = self.numericalTextInput.getKey(number)
		charstr = unichar.encode("utf-8")
		if len(charstr) == 1:
			self.servicelist.moveToChar(charstr[0])

	def keyAsciiCode(self):
		unichar = unichr(getPrevAsciiCode())
		charstr = unichar.encode("utf-8")
		if len(charstr) == 1:
			self.servicelist.moveToChar(charstr[0])

	def getRoot(self):
		return self.servicelist.getRoot()

	def getCurrentSelection(self):
		return self.servicelist.getCurrent()

	def setCurrentSelection(self, service):
		self.servicelist.setCurrent(service)

	def getBouquetList(self):
		bouquets = [ ]
		serviceHandler = eServiceCenter.getInstance()
		if config.usage.multibouquet.value:
			list = serviceHandler.list(self.bouquet_root)
			if list:
				while True:
					s = list.getNext()
					if not s.valid():
						break
					if s.flags & eServiceReference.isDirectory:
						info = serviceHandler.info(s)
						if info:
							bouquets.append((info.getName(s), s))
				return bouquets
		else:
			info = serviceHandler.info(self.bouquet_root)
			if info:
				bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
			return bouquets
		return None

	def keyNumber0(self, num):
		if len(self.servicePath) > 1:
			self.keyGoUp()
		else:
			self.keyNumberGlobal(num)

	def keyGoUp(self):
		if len(self.servicePath) > 1:
			if self.isBasePathEqual(self.bouquet_root):
				self.showFavourites()
			else:
				ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
				if self.isBasePathEqual(ref):
					self.showSatellites()
				else:
					ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
					if self.isBasePathEqual(ref):
						self.showProviders()
					else:
						self.showAllServices()

	def nextMarker(self):
		self.servicelist.moveToNextMarker()

	def prevMarker(self):
		self.servicelist.moveToPrevMarker()

#config for lastservice
config.tv = ConfigSubsection()
config.tv.lastservice = ConfigText()
config.tv.lastroot = ConfigText()
config.radio = ConfigSubsection()
config.radio.lastservice = ConfigText()
config.radio.lastroot = ConfigText()
config.servicelist = ConfigSubsection()
config.servicelist.lastmode = ConfigText(default = "tv")

from Components.StreamServerControl import streamServerControl
class ChannelSelectionEncoderService(object):
	def __init__(self):
		self["EncoderActions"] = ActionMap(["ChannelSelectionEncoderActions"],
			{
				"setEncoderService" : self._setEncoderService
			})

	def _setEncoderService(self):
		ref = self.getCurrentSelection()
		if ref:
			res = streamServerControl.setEncoderService(ref)
			infotext = ""
			if res == streamServerControl.ENCODER_SERVICE_SET:
				infotext = _("Encoder service now set to {0}").format(ref.getName())
			elif res == streamServerControl.ENCODER_SERVICE_ALREADY_ACTIVE:
				infotext = _("Encoder service was already set to {0}").format(ref.getName())
			elif res == streamServerControl.ENCODER_SERVICE_INVALID_MODE:
				infotext = _("Encoder service can only be set when in TV-Services mode!")
			elif res == streamServerControl.ENCODER_SERVICE_INSUFFICIENT_RESOURCES:
				infotext = _("Setting new encoder service to {0} failed! (Insufficient resources)".format(ref.getName()))
			else:
				infotext = _("Setting new encoder service to {0} failed!".format(ref.getName()))
			if infotext:
				self.session.toastManager.showToast(infotext)

HISTORYSIZE = 20

class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo, ChannelSelectionEncoderService):
	initialized = NoSave(ConfigBoolean(default = False))

	def __init__(self, session):
		ChannelSelectionBase.__init__(self,session)
		ChannelSelectionEdit.__init__(self)
		ChannelSelectionEPG.__init__(self)
		SelectionEventInfo.__init__(self)
		ChannelSelectionEncoderService.__init__(self)

		self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
			{
				"cancel": self.cancel,
				"ok": self.channelSelected,
				"keyRadio": self.setModeRadio,
				"keyTV": self.setModeTv,
			})

		self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
			{
				iPlayableService.evStart: self.__evServiceStart,
				iPlayableService.evEnd: self.__evServiceEnd
			})

		self.lastChannelRootTimer = eTimer()
		self.lastChannelRootTimer_conn = self.lastChannelRootTimer.timeout.connect(self.__onCreate)
		self.lastChannelRootTimer.start(100,True)

		self.history_tv = [ ]
		self.history_radio = [ ]
		self.history = self.history_tv
		self.history_pos = 0

		self.lastservice = config.tv.lastservice
		self.lastroot = config.tv.lastroot
		self.revertMode = None
		config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
		self.new_service_played = False
		self.onLayoutFinish.append(self.layoutFinished)
		self.onExecBegin.append(self.__execBegin)

	def __execBegin(self):
		self.setKeyboardModeAscii()
		
	def layoutFinished(self):
		config.usage.configselection_tagBouquetServices.addNotifier(self.tagBouquetServicesChanged, initial_call = True)
		
	def multibouquet_config_changed(self, val):
		self.recallBouquetMode()

	def __evServiceStart(self):
		service = self.session.nav.getCurrentService()
		if service:
			info = service.info()
			if info:
				refstr = info.getInfoString(iServiceInformation.sServiceref)
				self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))

	def __evServiceEnd(self):
		self.servicelist.setPlayableIgnoreService(eServiceReference())

	def setMode(self):
		self.rootChanged = True
		self.restoreRoot()
		lastservice=eServiceReference(self.lastservice.value)
		if lastservice.valid():
			self.setCurrentSelection(lastservice)

	def setModeTv(self):
		if self.revertMode is None and config.servicelist.lastmode.value == "radio":
			self.revertMode = MODE_RADIO
		self.history = self.history_tv
		self.lastservice = config.tv.lastservice
		self.lastroot = config.tv.lastroot
		config.servicelist.lastmode.value = "tv"
		self.setTvMode()
		self.setMode()

	def setModeRadio(self):
		if self.revertMode is None and config.servicelist.lastmode.value == "tv":
			self.revertMode = MODE_TV
		if config.usage.e1like_radio_mode.value:
			self.history = self.history_radio
			self.lastservice = config.radio.lastservice
			self.lastroot = config.radio.lastroot
			config.servicelist.lastmode.value = "radio"
			self.setRadioMode()
			self.setMode()

	def __onCreate(self):
		if config.usage.e1like_radio_mode.value:
			if config.servicelist.lastmode.value == "tv":
				self.setModeTv()
			else:
				self.setModeRadio()
		else:
			self.setModeTv()
		lastservice=eServiceReference(self.lastservice.value)
		if lastservice.valid():
			if not Screens.Standby.inStandby:
				self.zap()
			else:
				Screens.Standby.inStandby.onClose.append(self.zap)
		ChannelSelection.initialized.value = True

	def channelSelected(self):
		ref = self.getCurrentSelection()
		if self.movemode:
			self.toggleMoveMarked()
		elif (ref.flags & 7) == 7:
			self.enterPath(ref)
		elif self.bouquet_mark_edit != OFF:
			if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
				self.doMark()
		elif not (ref.flags & eServiceReference.isMarker): # no marker
			root = self.getRoot()
			if not root or not (root.flags & eServiceReference.isGroup):
				# Dr.Best
				if not config.merlin2.minitv.value:
					self.zap()
				self.close(ref)
				if config.merlin2.minitv.value:
					self.zap()
			# Shaderman
			# Enable zapping for alternative services
			elif not (ref.flags & (eServiceReference.isMarker|eServiceReference.isDirectory)): # should be a playable service, zap!
				self.close(ref)
				self.zap()
				self.saveRoot()

	#called from infoBar and channelSelected
	def zap(self, nref=None, root=None):
		self.revertMode=None
		ref = self.session.nav.getCurrentlyPlayingServiceReference()
		# dre - remove streamrelay
		ref = self.removeStreamRelay(ref)	
		if not nref:
			nref = self.getCurrentSelection()
		if root:
			if not self.preEnterPath(root):
				self.clearPath()
				self.enterPath(eServiceReference(root))
		if ref is None or ref != nref:
			self.new_service_played = True
			self.session.nav.playService(nref)
			self.saveRoot()
			self.saveChannel(nref)
			config.servicelist.lastmode.save()
			self.addToHistory(nref)

	def newServicePlayed(self):
		ret = self.new_service_played
		self.new_service_played = False
		return ret

	def addToHistory(self, ref):
		if self.servicePath is not None:
			tmp=self.servicePath[:]
			# dre - remove streamrelay
			ref = self.removeStreamRelay(ref)	
			tmp.append(ref)
			try:
				del self.history[self.history_pos+1:]
			except:
				pass
			self.history.append(tmp)
			hlen = len(self.history)
			if hlen > HISTORYSIZE:
				del self.history[0]
				hlen -= 1
			self.history_pos = hlen-1

	def historyBack(self):
		hlen = len(self.history)
		if hlen > 1 and self.history_pos > 0:
			self.history_pos -= 1
			self.setHistoryPath()

	def historyNext(self):
		hlen = len(self.history)
		if hlen > 1 and self.history_pos < (hlen-1):
			self.history_pos += 1
			self.setHistoryPath()

	def setHistoryPath(self):
		path = self.history[self.history_pos][:]
		ref = path.pop()
		del self.servicePath[:]
		self.servicePath += path
		self.saveRoot()
		root = path[-1]
		cur_root = self.getRoot()
		if cur_root and cur_root != root:
			self.setRoot(root)
		self.session.nav.playService(ref)
		self.setCurrentSelection(ref)
		self.saveChannel(ref)

	def saveRoot(self):
		path = ''
		for i in self.servicePath:
			path += i.toString()
			path += ';'
		if path and path != self.lastroot.value:
			self.lastroot.value = path
			self.lastroot.save()

	def restoreRoot(self):
		tmp = [x for x in self.lastroot.value.split(';') if x != '']
		current = [x.toString() for x in self.servicePath]
		if tmp != current or self.rootChanged:
			self.clearPath()
			cnt = 0
			for i in tmp:
				self.servicePath.append(eServiceReference(i))
				cnt += 1
			if cnt:
				path = self.servicePath.pop()
				self.enterPath(path)
			else:
				self.showFavourites()
				self.saveRoot()
			self.rootChanged = False

	def preEnterPath(self, refstr):
		if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
			pathstr = self.lastroot.value
			if pathstr is not None and pathstr.find(refstr) == 0:
				self.restoreRoot()
				lastservice=eServiceReference(self.lastservice.value)
				if lastservice.valid():
					self.setCurrentSelection(lastservice)
				return True
		return False

	def saveChannel(self, ref):
		if ref is not None:
			# dre - remove streamrelay
			ref = self.removeStreamRelay(ref)	
			refstr = ref.toString()
		else:
			refstr = ""
		if refstr != self.lastservice.value:
			self.lastservice.value = refstr
			self.lastservice.save()

	def setCurrentServicePath(self, path):
		if self.history:
			self.history[self.history_pos] = path
		else:
			self.history.append(path)
		self.setHistoryPath()

	def getCurrentServicePath(self):
		if self.history:
			return self.history[self.history_pos]
		return None

	def recallPrevService(self):
		hlen = len(self.history)
		if hlen > 1:
			if self.history_pos == hlen-1:
				tmp = self.history[self.history_pos]
				self.history[self.history_pos] = self.history[self.history_pos-1]
				self.history[self.history_pos-1] = tmp
			else:
				tmp = self.history[self.history_pos+1]
				self.history[self.history_pos+1] = self.history[self.history_pos]
				self.history[self.history_pos] = tmp
			self.setHistoryPath()

	def cancel(self):
		if self.revertMode is None:
			self.restoreRoot()
			lastservice=eServiceReference(self.lastservice.value)
			if lastservice.valid() and self.getCurrentSelection() != lastservice:
				self.setCurrentSelection(lastservice)
		elif self.revertMode == MODE_TV:
			self.setModeTv()
		elif self.revertMode == MODE_RADIO:
			self.setModeRadio()
		self.revertMode = None
		self.close(None)

	def removeStreamRelay(self, ref):
		if ref and ref.getUnsignedData(4) == 33:
			ref.setUnsignedData(4, 12582912)
			ref.flags = 512
			ref.setName("")
			ref.setPath("")
		return ref

class RadioInfoBar(Screen):
	def __init__(self, session):
		Screen.__init__(self, session)
		self["RdsDecoder"] = RdsDecoder(self.session.nav)

class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarBase):

	def __init__(self, session, infobar=None):
		ChannelSelectionBase.__init__(self, session)
		ChannelSelectionEdit.__init__(self)
		ChannelSelectionEPG.__init__(self)
		InfoBarBase.__init__(self)
		if not infobar:
			from InfoBar import InfoBar
			infobar = InfoBar.instance
		self.infobar = infobar

		self.onLayoutFinish.append(self.onCreate)

		self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar

		self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
			{
				"keyTV": self.cancel,
				"keyRadio": self.cancel,
				"cancel": self.cancel,
				"ok": self.channelSelected,
			})

		self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
			{
				iPlayableService.evStart: self.__evServiceStart,
				iPlayableService.evEnd: self.__evServiceEnd
			})

########## RDS Radiotext / Rass Support BEGIN
		self["RdsDecoder"] = self.info["RdsDecoder"]
		self.infobar.rds_display.hide()
		self.onClose.append(self.__onClose)
		self.onShow.append(self.info.show)
		self.onHide.append(self.info.hide)		

	def __onClose(self):
		del self.info["RdsDecoder"]
		self.session.deleteDialog(self.info)
		lastservice=eServiceReference(config.tv.lastservice.value)
		self.session.nav.playService(lastservice)

########## RDS Radiotext / Rass Support END

	def cancel(self):
		self.info.hide()
		#set previous tv service
		self.close(True)

	def __evServiceStart(self):
		service = self.session.nav.getCurrentService()
		if service:
			info = service.info()
			if info:
				refstr = info.getInfoString(iServiceInformation.sServiceref)
				self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))

	def __evServiceEnd(self):
		self.servicelist.setPlayableIgnoreService(eServiceReference())

	def saveRoot(self):
		path = ''
		for i in self.servicePathRadio:
			path += i.toString()
			path += ';'
		if path and path != config.radio.lastroot.value:
			config.radio.lastroot.value = path
			config.radio.lastroot.save()

	def restoreRoot(self):
		tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
		current = [x.toString() for x in self.servicePathRadio]
		if tmp != current or self.rootChanged:
			self.clearPath()
			cnt = 0
			for i in tmp:
				self.servicePathRadio.append(eServiceReference(i))
				cnt += 1
			if cnt:
				path = self.servicePathRadio.pop()
				self.enterPath(path)
			else:
				self.showFavourites()
				self.saveRoot()
			self.rootChanged = False

	def preEnterPath(self, refstr):
		if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
			pathstr = config.radio.lastroot.value
			if pathstr is not None and pathstr.find(refstr) == 0:
				self.restoreRoot()
				lastservice=eServiceReference(config.radio.lastservice.value)
				if lastservice.valid():
					self.setCurrentSelection(lastservice)
				return True
		return False

	def onCreate(self):
		self.setRadioMode()
		self.restoreRoot()
		lastservice=eServiceReference(config.radio.lastservice.value)
		if lastservice.valid():
			self.servicelist.setCurrent(lastservice)
			self.session.nav.playService(lastservice)
		else:
			self.session.nav.stopService()
		self.info.show()

	def channelSelected(self): # just return selected service
		ref = self.getCurrentSelection()
		if self.movemode:
			self.toggleMoveMarked()
		elif (ref.flags & 7) == 7:
			self.enterPath(ref)
		elif self.bouquet_mark_edit != OFF:
			if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
				self.doMark()
		elif not (ref.flags & eServiceReference.isMarker): # no marker
			cur_root = self.getRoot()
			if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
				playingref = self.session.nav.getCurrentlyPlayingServiceReference()
				if playingref is None or playingref != ref:
					self.session.nav.playService(ref)
					config.radio.lastservice.value = ref.toString()
					config.radio.lastservice.save()
				self.saveRoot()

class SimpleChannelSelection(ChannelSelectionBase):
	def __init__(self, session, title):
		ChannelSelectionBase.__init__(self, session)
		self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
			{
				"cancel": self.close,
				"ok": self.channelSelected,
				"keyRadio": self.setModeRadio,
				"keyTV": self.setModeTv,
			})
		self.title = title
		self.onLayoutFinish.append(self.layoutFinished)

	def layoutFinished(self):
		self.setModeTv()

	def channelSelected(self): # just return selected service
		ref = self.getCurrentSelection()
		if (ref.flags & 7) == 7:
			self.enterPath(ref)
		elif not (ref.flags & eServiceReference.isMarker):
			ref = self.getCurrentSelection()
			self.close(ref)

	def setModeTv(self):
		self.setTvMode()
		self.showFavourites()

	def setModeRadio(self):
		self.setRadioMode()
		self.showFavourites()

