#######################################################
# Permanent Timeshift Plugin for Enigma2 Dreamboxes
# Coded by Homey (c) 2010
#
# Version: 1.00 RC18
# Support: www.i-have-a-dreambox.com
#######################################################
from Components.ActionMap import ActionMap
from Components.ConfigList import ConfigList, ConfigListScreen
from Components.config import config, configfile, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigInteger, ConfigSelection
from Components.Label import Label
from Components.Language import language
from Components.Pixmap import Pixmap
from Components.ServiceEventTracker import ServiceEventTracker
from Components.Sources.StaticText import StaticText
from Components.Task import Task, Job, job_manager as JobManager
from Components.UsageConfig import preferredInstantRecordPath, defaultMoviePath
from Screens.ChoiceBox import ChoiceBox
from Screens.ChannelSelection import ChannelSelection
from Screens.InfoBar import InfoBar
from Screens.InfoBarGenerics import NumberZap, InfoBarSeek, InfoBarNumberZap, InfoBarEPG, InfoBarTimeshiftState, InfoBarInstantRecord, InfoBarChannelSelection
from Screens.MessageBox import MessageBox
from Screens.Screen import Screen
from Screens.Setup import SetupSummary
from Screens.PVRState import TimeshiftState
from ServiceReference import ServiceReference
from Tools import Directories, ASCIItranslit
from Tools.Directories import fileExists, copyfile, resolveFilename, SCOPE_LANGUAGE, SCOPE_PLUGINS
from Plugins.Plugin import PluginDescriptor
from RecordTimer import RecordTimerEntry, parseEvent

from re import search as re_search
from enigma import eTimer, eServiceCenter, eBackgroundFileEraser, eConsoleAppContainer, iPlayableService, iServiceInformation
from os import environ, stat as os_stat, listdir as os_listdir, link as os_link, path as os_path, statvfs
from time import localtime, time, strftime
from timer import TimerEntry

import gettext
import Screens.InfoBar

##############################
#####  CONFIG SETTINGS   #####
##############################

config.plugins.pts = ConfigSubsection()
config.plugins.pts.enabled = ConfigYesNo(default = False)
config.plugins.pts.maxevents = ConfigInteger(default=5, limits=(1, 99))
config.plugins.pts.maxlength = ConfigInteger(default=180, limits=(5, 999))
config.plugins.pts.startdelay = ConfigInteger(default=5, limits=(5, 999))
config.plugins.pts.showinfobar = ConfigYesNo(default = False)
config.plugins.pts.stopwhilerecording = ConfigYesNo(default = False)
config.plugins.pts.favoriteSaveAction = ConfigSelection([("askuser", _("Ask user")),("savetimeshift", _("Save and stop")),("savetimeshiftandrecord", _("Save and record")),("noSave", _("Don't save"))], "askuser")

##############################
###   Multilanguage Init   ###
##############################

def localeInit():
	lang = language.getLanguage()
	environ["LANGUAGE"] = lang[:2]
	gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
	gettext.textdomain("enigma2")
	gettext.bindtextdomain("PTSPlugin", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/PermanentTimeshift/locale/"))

def _(txt):
	t = gettext.dgettext("PTSPlugin", txt)
	if t == txt:
		t = gettext.gettext(txt)
	return t

localeInit()
language.addCallback(localeInit)

###################################
###  PTS TimeshiftState Screen  ###
###################################

class PTSTimeshiftState(Screen):
	skin = """
		<screen position="center,40" zPosition="2" size="420,70" backgroundColor="transpBlack" flags="wfNoBorder">
			<widget name="state" position="10,3" size="80,27" font="Regular;20" halign="center" backgroundColor="transpBlack" />
			<widget source="session.CurrentService" render="Label" position="95,5" size="120,27" font="Regular;20" halign="left" foregroundColor="white" backgroundColor="transpBlack">
				<convert type="ServicePosition">Position</convert>
			</widget>
			<widget source="session.CurrentService" render="Label" position="350,5" size="60,27" font="Regular;20" halign="left" foregroundColor="white" backgroundColor="transpBlack">
				<convert type="ServicePosition">Length</convert>
			</widget>
			<widget name="PTSSeekPointer" position="8,30" zPosition="3" size="19,50" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/PermanentTimeshift/images/timeline-now.png" alphatest="on" />
			<ePixmap position="10,33" size="840,15" zPosition="1" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/PermanentTimeshift/images/slider_back.png" alphatest="on"/>
			   <widget source="session.CurrentService" render="Progress" position="10,33" size="390,15" zPosition="2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/PermanentTimeshift/images/slider.png" transparent="1">
				<convert type="ServicePosition">Position</convert>
			</widget>
			<widget name="eventname" position="10,49" zPosition="4" size="420,20" font="Regular;18" halign="center" backgroundColor="transpBlack" />
		</screen>"""

	def __init__(self, session):
		Screen.__init__(self, session)
		self["state"] = Label(text="")
		self["PTSSeekPointer"] = Pixmap()
		self["eventname"] = Label(text="")
		

###################################
###   PTS CopyTimeshift Task    ###
###################################

class CopyTimeshiftJob(Job):
	def __init__(self, toolbox, cmdline):
		Job.__init__(self, _("Saving Timeshift files"))
		self.toolbox = toolbox
		AddCopyTimeshiftTask(self, cmdline)

class AddCopyTimeshiftTask(Task):
	def __init__(self, job, cmdline):
		Task.__init__(self, job, job.name)
		self.toolbox = job.toolbox
		self.setCmdline(cmdline)

	def afterRun(self):
		self.toolbox.ptsCopyFilefinished(self.returncode)

###################################
###   PTS MergeTimeshift Task   ###
###################################

class MergeTimeshiftJob(Job):
	def __init__(self, toolbox, cmdline):
		Job.__init__(self, _("Merging Timeshift files"))
		self.toolbox = toolbox
		AddMergeTimeshiftTask(self, cmdline)

class AddMergeTimeshiftTask(Task):
	def __init__(self, job, cmdline):
		Task.__init__(self, job, job.name)
		self.toolbox = job.toolbox
		self.setCmdline(cmdline)

	def afterRun(self):
		self.toolbox.ptsMergeFilefinished(self.returncode)


##############################
#####  Class InfoBarPTS  #####
##############################
class InfoBarPTS(InfoBar):
	def __init__(self, session):
		InfoBar.__init__(self, session)
		self.skinName = "InfoBar"

		self.__event_tracker = ServiceEventTracker(screen = self, eventmap =
			{
				iPlayableService.evStart: self.__evStart,
				iPlayableService.evEnd: self.__evEnd,
				iPlayableService.evSOF: self.__evSOF,
				iPlayableService.evUpdatedInfo: self.__evInfoChanged,
				iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
				iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
				iPlayableService.evUser+1: self.ptsTimeshiftFileChanged
			})

		self["PTSactions"] = ActionMap(["PTS_GlobalActions"],{"instantRecord": self.instantRecord, "restartTimeshift": self.restartTimeshift},-2)
#---> HDF CHANGE FOR AAF VERSION
#		self["PTSSeekPointerActions"] = ActionMap(["PTS_SeekPointerActions"],{"SeekPointerOK": self.ptsSeekPointerOK, "SeekPointerLeft": self.ptsSeekPointerLeft, "SeekPointerRight": self.ptsSeekPointerRight},-2)
#---<
#+++>
		self["PTSSeekPointerActions"] = ActionMap(["PTS_SeekPointerActions"],{"SeekPointerOK": self.ptsSeekPointerOK, "SeekPointerLeft": self.ptsSeekPointerLeft, "SeekPointerRight": self.ptsSeekPointerRight, "SeekPointerStop": self.stopTimeshift},-2)
#+++<
		self["PTSSeekPointerActions"].setEnabled(False)

		self.pts_begintime = 0
		self.pts_pathchecked = False
		self.pts_delmergeRecordName = None
		self.pts_pvrStateDialog = "TimeshiftState"
		self.pts_seektoprevfile = False
		self.pts_switchtolive = False
		self.pts_currplaying = 1
		self.pts_lastseekspeed = 0
		self.pts_service_changed = False
		self.pts_record_running = self.session.nav.RecordTimer.isRecording()
		self.save_current_timeshift = False
		self.save_timeshift_postaction = None
		self.save_timeshift_filename = None
		self.service_changed = 0

		# Init eBackgroundFileEraser
		self.BgFileEraser = eBackgroundFileEraser.getInstance()

		# Init PTS Delay-Timer
		self.pts_delay_timer = eTimer()
		self.pts_delay_timer.callback.append(self.ActivatePermanentTimeshift)

		# Init PTS LengthCheck-Timer
		self.pts_LengthCheck_timer = eTimer()
		self.pts_LengthCheck_timer.callback.append(self.ptsLengthCheck)

		# Init PTS MergeRecords-Timer
		self.pts_mergeRecords_timer = eTimer()
		self.pts_mergeRecords_timer.callback.append(self.ptsMergeRecords)

		# Init PTS CleanUp-Timer
		self.pts_cleanUp_timer = eTimer()
		self.pts_cleanUp_timer.callback.append(self.ptsCleanTimeshiftFolder)
		self.pts_cleanUp_timer.start(30000, True)

		# Init PTS SeekBack-Timer
		self.pts_SeekBack_timer = eTimer()
		self.pts_SeekBack_timer.callback.append(self.ptsSeekBackTimer)

		# Record Event Tracker
		self.session.nav.RecordTimer.on_state_change.append(self.ptsTimerEntryStateChange)

		# Keep Current Event Info for recordings
		self.pts_eventcount = 1
		self.pts_curevent_begin = int(time())
		self.pts_curevent_end = 0
		self.pts_curevent_name = _("Timeshift")
		self.pts_curevent_description = ""
		self.pts_curevent_servicerefname = ""
		self.pts_curevent_station = ""
		self.pts_curevent_eventid = None

		# Init PTS Infobar
		self.pts_seekpointer_MinX = 8
		self.pts_seekpointer_MaxX = 396 # make sure you can divide this through 2

	def __evStart(self):
		self.service_changed = 1
		self.pts_delay_timer.stop()
		self.pts_service_changed = True

	def __evEnd(self):
		self.service_changed = 0

	def __evSOF(self):
		if not config.plugins.pts.enabled.value or not self.timeshift_enabled:
			return

		if self.pts_currplaying == 1:
			preptsfile = config.plugins.pts.maxevents.value
		else:
			preptsfile = self.pts_currplaying-1

		# Switch to previous TS file by seeking forward to next one
		if fileExists("%s/pts_livebuffer.%s" % (config.usage.timeshift_path.value, preptsfile), 'r') and preptsfile != self.pts_eventcount:
			self.pts_seektoprevfile = True
			self.ptsSetNextPlaybackFile("pts_livebuffer.%s" % (preptsfile))

			self.setSeekState(self.SEEK_STATE_PAUSE)
			if self.seekstate != self.SEEK_STATE_PLAY:
				self.setSeekState(self.SEEK_STATE_PLAY)
			self.doSeek(-1)
			self.seekFwd()

	def __evInfoChanged(self):
		if self.service_changed:
			self.service_changed = 0

			# Delete Timeshift Records on zap
			self.pts_eventcount = 0
			self.pts_cleanUp_timer.start(3000, True)

			# Ooops, we zapped away before saving the file :(
			if self.save_current_timeshift:
				self.save_current_timeshift = False
				self.session.open(MessageBox,_("OH NO!\nThe timeshift that was marked to save at end of event, was lost because you zapped away!"), MessageBox.TYPE_INFO)

	def __evEventInfoChanged(self):
		if not config.plugins.pts.enabled.value:
			return

		# Get Current Event Info
		service = self.session.nav.getCurrentService()
		old_begin_time = self.pts_begintime
		info = service and service.info()
		ptr = info and info.getEvent(0)
		self.pts_begintime = ptr and ptr.getBeginTime() or 0

		# Save current TimeShift permanently now ...
		if info.getInfo(iServiceInformation.sVideoPID) != -1:

			# Take care of Record Margin Time ...
			if self.save_current_timeshift and self.timeshift_enabled:
				if config.recording.margin_after.value > 0 and len(self.recording) == 0:
					self.SaveTimeshift(mergelater=True)
					recording = RecordTimerEntry(ServiceReference(self.session.nav.getCurrentlyPlayingServiceReference()), time(), time()+(config.recording.margin_after.value*60), self.pts_curevent_name, self.pts_curevent_description, self.pts_curevent_eventid, dirname = config.usage.default_path.value)
					recording.dontSave = True
					self.session.nav.RecordTimer.record(recording)
					self.recording.append(recording)
				else:
					self.SaveTimeshift()

			# Restarting active timers after zap ...
			if self.pts_delay_timer.isActive() and not self.timeshift_enabled:
				self.pts_delay_timer.start(config.plugins.pts.startdelay.value*1000, True)
			if self.pts_cleanUp_timer.isActive() and not self.timeshift_enabled:
				self.pts_cleanUp_timer.start(3000, True)

			# (Re)Start TimeShift
			if not self.pts_delay_timer.isActive():
				if not self.timeshift_enabled or old_begin_time != self.pts_begintime or old_begin_time == 0:
					if self.pts_service_changed:
						self.pts_service_changed = False
						self.pts_delay_timer.start(config.plugins.pts.startdelay.value*1000, True)
					else:
						self.pts_delay_timer.start(1000, True)

	def __seekableStatusChanged(self):
		enabled = False
		if not self.isSeekable() and self.timeshift_enabled:
			enabled = True
		self["TimeshiftActivateActions"].setEnabled(enabled)

		enabled = False
		if config.plugins.pts.enabled.value and config.plugins.pts.showinfobar.value and self.timeshift_enabled and self.isSeekable():
			enabled = True

		self["PTSSeekPointerActions"].setEnabled(enabled)

		# Reset Seek Pointer And Eventname in InfoBar
		if config.plugins.pts.enabled.value and config.plugins.pts.showinfobar.value and self.timeshift_enabled and not self.isSeekable():
			if self.pts_pvrStateDialog == "PTSTimeshiftState":
				self.pvrStateDialog["eventname"].setText("")
			self.ptsSeekPointerReset()

		# setNextPlaybackFile() when switching back to live tv
		if config.plugins.pts.enabled.value and self.timeshift_enabled and not self.isSeekable():
			self.pts_currplaying = self.pts_eventcount
			self.ptsSetNextPlaybackFile("pts_livebuffer.%s" % (self.pts_eventcount))

	def ActivatePermanentTimeshift(self):
		if self.ptsCheckTimeshiftPath() is False or self.session.screen["Standby"].boolean is True or self.ptsLiveTVStatus() is False or (config.plugins.pts.stopwhilerecording.value and self.pts_record_running):
			return

		# Replace PVR Timeshift State Icon
		if config.plugins.pts.showinfobar.value:
			if self.pts_pvrStateDialog != "PTSTimeshiftState":
				self.pts_pvrStateDialog = "PTSTimeshiftState"
				self.pvrStateDialog = self.session.instantiateDialog(PTSTimeshiftState)
		elif not config.plugins.pts.showinfobar.value and self.pts_pvrStateDialog != "TimeshiftState":
			self.pts_pvrStateDialog = "TimeshiftState"
			self.pvrStateDialog = self.session.instantiateDialog(TimeshiftState)

		# Set next-file on event change only when watching latest timeshift ...
		if self.isSeekable() and self.pts_eventcount == self.pts_currplaying:
			pts_setnextfile = True
		else:
			pts_setnextfile = False

		# Update internal Event Counter
		if self.pts_eventcount >= config.plugins.pts.maxevents.value:
			self.pts_eventcount = 0

		self.pts_eventcount += 1

		# Do not switch back to LiveTV while timeshifting
		# Note: This only works with enigma from JAN 2010 or later
		if self.isSeekable():
			switchToLive = False
		else:
			switchToLive = True

		# setNextPlaybackFile() on event change while timeshifting
		if self.pts_eventcount > 1 and self.isSeekable() and pts_setnextfile:
			self.ptsSetNextPlaybackFile("pts_livebuffer.%s" % (self.pts_eventcount))

		# (Re)start Timeshift now
		self.stopTimeshiftConfirmed(True, switchToLive)
		ts = self.getTimeshift()
		if ts and not ts.startTimeshift():
			self.pts_starttime = time()
			self.pts_LengthCheck_timer.start(120000)
			self.timeshift_enabled = 1
			self.save_timeshift_postaction = None
			self.ptsGetEventInfo()
			self.ptsCreateHardlink()
			self.__seekableStatusChanged()
		else:
			self.pts_eventcount = 0

	def startTimeshift(self):
		if config.plugins.pts.enabled.value:
			self.pts_delay_timer.stop()
			self.ActivatePermanentTimeshift()
			self.activateTimeshiftEndAndPause()
		else:
			InfoBar.startTimeshift(self)

	def stopTimeshift(self):
		if not self.timeshift_enabled:
			return 0

		# Jump Back to Live TV
		if config.plugins.pts.enabled.value and self.timeshift_enabled:
			if self.isSeekable():
				self.pts_switchtolive = True
				self.ptsSetNextPlaybackFile("")
				self.setSeekState(self.SEEK_STATE_PAUSE)
				if self.seekstate != self.SEEK_STATE_PLAY:
					self.setSeekState(self.SEEK_STATE_PLAY)
#---> HDF CHANGE FOT AAF VERSION
#				self.doSeek(-1) # seek 1 gop before end
#				self.seekFwd() # seekFwd to switch to live TV
#---<
#+++>
				self.fwdSeekTo(+1)
#+++<
				return 1
			return 0
		InfoBar.stopTimeshift(self)

	def stopTimeshiftConfirmed(self, confirmed, switchToLive=True):
		was_enabled = self.timeshift_enabled

		if not confirmed:
			return
		ts = self.getTimeshift()
		if ts is None:
			return

		try:
			ts.stopTimeshift(switchToLive)
		except:
			ts.stopTimeshift()

		self.timeshift_enabled = 0
		self.__seekableStatusChanged()

		if was_enabled and not self.timeshift_enabled:
			self.timeshift_enabled = 0
			self.pts_LengthCheck_timer.stop()

	def restartTimeshift(self):
		self.ActivatePermanentTimeshift()
		self.session.open(MessageBox, _("PTS-Plugin: Restarting timeshift!"), MessageBox.TYPE_INFO, timeout=5)

	def saveTimeshiftPopup(self):
		self.session.openWithCallback(self.saveTimeshiftPopupCallback, ChoiceBox, \
			title=_("The Timeshift record was not saved yet!\nWhat do you want to do now with the timeshift file?"), \
			list=((_("Save Timeshift as Movie and stop recording"), "savetimeshift"), \
			(_("Save Timeshift as Movie and continue recording"), "savetimeshiftandrecord"), \
			(_("Don't save Timeshift as Movie"), "noSave")))

	def saveTimeshiftPopupCallback(self, answer):
		if answer is None:
			return

		if answer[1] == "savetimeshift":
			self.saveTimeshiftActions("savetimeshift")
		elif answer[1] == "savetimeshiftandrecord":
			self.saveTimeshiftActions("savetimeshiftandrecord")
		elif answer[1] == "noSave":
			self.save_current_timeshift = False
			self.saveTimeshiftActions("noSave")

	def saveTimeshiftEventPopup(self):
		filecount = 0
		entrylist = []
		entrylist.append((_("Current Event:")+" %s" % (self.pts_curevent_name), "savetimeshift"))

		filelist = os_listdir(config.usage.timeshift_path.value)

		if filelist is not None:
			filelist.sort()

		for filename in filelist:
			if (filename.startswith("pts_livebuffer.") is True) and (filename.endswith(".del") is False and filename.endswith(".meta") is False and filename.endswith(".copy") is False):
				statinfo = os_stat("%s/%s" % (config.usage.timeshift_path.value,filename))
				if statinfo.st_mtime < (time()-5.0):
					# Get Event Info from meta file
					readmetafile = open("%s/%s.meta" % (config.usage.timeshift_path.value,filename), "r")
					servicerefname = readmetafile.readline()[0:-1]
					eventname = readmetafile.readline()[0:-1]
					description = readmetafile.readline()[0:-1]
					begintime = readmetafile.readline()[0:-1]
					readmetafile.close()

					# Add Event to list
					filecount += 1
					entrylist.append((_("Record") + " #%s (%s): %s" % (filecount,strftime("%H:%M",localtime(int(begintime))),eventname), "%s" % filename))

		self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=_("Which event do you want to save permanently?"), list=entrylist)

	def saveTimeshiftActions(self, action = None):
		if action is None:
			if config.plugins.pts.favoriteSaveAction.value == "askuser":
				self.saveTimeshiftPopup()
				return
			elif config.plugins.pts.favoriteSaveAction.value == "savetimeshift":
				self.SaveTimeshift()
			elif config.plugins.pts.favoriteSaveAction.value == "savetimeshiftandrecord":
				self.SaveTimeshift(mergelater=True)
				InfoBarInstantRecord.startInstantRecording(self, limitEvent = True)
			elif config.plugins.pts.favoriteSaveAction.value == "noSave":
				self.save_current_timeshift = False
		elif action == "savetimeshift":
			self.SaveTimeshift()
		elif action == "savetimeshiftandrecord":
			self.SaveTimeshift(mergelater=True)
			InfoBarInstantRecord.startInstantRecording(self, limitEvent = True)
		elif action == "noSave":
			self.save_current_timeshift = False

		# Post PTS Actions like ZAP or whatever the user requested
		if self.save_timeshift_postaction == "zapUp":
			InfoBarChannelSelection.zapUp(self)
		elif self.save_timeshift_postaction == "zapDown":
			InfoBarChannelSelection.zapDown(self)
		elif self.save_timeshift_postaction == "historyBack":
			InfoBarChannelSelection.historyBack(self)
		elif self.save_timeshift_postaction == "historyNext":
			InfoBarChannelSelection.historyNext(self)
		elif self.save_timeshift_postaction == "switchChannelUp":
			InfoBarChannelSelection.switchChannelUp(self)
		elif self.save_timeshift_postaction == "switchChannelDown":
			InfoBarChannelSelection.switchChannelDown(self)
		elif self.save_timeshift_postaction == "openServiceList":
			InfoBarChannelSelection.openServiceList(self)
		elif self.save_timeshift_postaction == "showRadioChannelList":
			InfoBarChannelSelection.showRadioChannelList(self, zap=True)

	def SaveTimeshift(self, timeshiftfile=None, mergelater=False):
		self.save_current_timeshift = False
		savefilename = None

		if not self.timeshift_enabled:
			return

		if timeshiftfile is not None:
			savefilename = timeshiftfile

		if savefilename is None:
			for filename in os_listdir(config.usage.timeshift_path.value):
				if filename.startswith("timeshift.") and not filename.endswith(".del") and not filename.endswith(".copy"):
					statinfo = os_stat("%s/%s" % (config.usage.timeshift_path.value,filename))
					if statinfo.st_mtime > (time()-5.0):
						savefilename=filename

		if savefilename is None:
			self.session.open(MessageBox, _("No Timeshift found to save as recording!"), MessageBox.TYPE_ERROR)
		else:
			timeshift_saved = True
			timeshift_saveerror1 = ""
			timeshift_saveerror2 = ""
			metamergestring = ""

			if mergelater:
				self.pts_mergeRecords_timer.start(120000, True)
				metamergestring = "pts_merge\n"

			try:
				if timeshiftfile is None:
					# Save Current Event by creating hardlink to ts file
					ptsfilename = "%s - %s - %s" % (strftime("%Y%m%d %H%M",localtime(self.pts_starttime)),self.pts_curevent_station,self.pts_curevent_name)
					try:
						if config.usage.setup_level.index >= 2:
							if config.recording.filename_composition.value == "long" and self.pts_curevent_name != pts_curevent_description:
								ptsfilename = "%s - %s - %s - %s" % (strftime("%Y%m%d %H%M",localtime(self.pts_starttime)),self.pts_curevent_station,self.pts_curevent_name,self.pts_curevent_description)
							elif config.recording.filename_composition.value == "short":
								ptsfilename = "%s - %s" % (strftime("%Y%m%d",localtime(self.pts_starttime)),self.pts_curevent_name)
					except Exception, errormsg:
						print "PTS-Plugin: Using default filename"
					
					if config.recording.ascii_filenames.value:
						ptsfilename = ASCIItranslit.legacyEncode(ptsfilename)

					fullname = Directories.getRecordingFilename(ptsfilename,config.usage.default_path.value)
					os_link("%s/%s" % (config.usage.timeshift_path.value,savefilename), "%s.ts" % (fullname))
					metafile = open("%s.ts.meta" % (fullname), "w")
					metafile.write("%s\n%s\n%s\n%i\n%s" % (self.pts_curevent_servicerefname,self.pts_curevent_name,self.pts_curevent_description,int(self.pts_starttime),metamergestring))
					metafile.close()
				elif timeshiftfile.startswith("pts_livebuffer"):
					# Save stored timeshift by creating hardlink to ts file
					readmetafile = open("%s/%s.meta" % (config.usage.timeshift_path.value,timeshiftfile), "r")
					servicerefname = readmetafile.readline()[0:-1]
					eventname = readmetafile.readline()[0:-1]
					description = readmetafile.readline()[0:-1]
					begintime = readmetafile.readline()[0:-1]
					readmetafile.close()

					ptsfilename = "%s - %s - %s" % (strftime("%Y%m%d %H%M",localtime(int(begintime))),self.pts_curevent_station,eventname)
					try:
						if config.usage.setup_level.index >= 2:
							if config.recording.filename_composition.value == "long" and eventname != description:
								ptsfilename = "%s - %s - %s - %s" % (strftime("%Y%m%d %H%M",localtime(int(begintime))),self.pts_curevent_station,eventname,description)
							elif config.recording.filename_composition.value == "short":
								ptsfilename = "%s - %s" % (strftime("%Y%m%d",localtime(int(begintime))),eventname)
					except Exception, errormsg:
						print "PTS-Plugin: Using default filename"
						
					if config.recording.ascii_filenames.value:
						ptsfilename = ASCIItranslit.legacyEncode(ptsfilename)

					fullname=Directories.getRecordingFilename(ptsfilename,config.usage.default_path.value)
					os_link("%s/%s" % (config.usage.timeshift_path.value,timeshiftfile),"%s.ts" % (fullname))
					os_link("%s/%s.meta" % (config.usage.timeshift_path.value,timeshiftfile),"%s.ts.meta" % (fullname))

				self.session.open(MessageBox, _("Timeshift saved to your harddisk!"), MessageBox.TYPE_INFO, timeout=5)
			except Exception, errormsg:
				timeshift_saved = False
				timeshift_saveerror1 = errormsg

			# Hmpppf! Saving Timeshift via Hardlink-Method failed. Probably other device?
			# Let's try to copy the file in background now! This might take a while ...
			if not timeshift_saved:
				try:
					stat = statvfs(config.usage.default_path.value)
					freespace = stat.f_bfree / 1000 * stat.f_bsize / 1000

					if timeshiftfile is None:
						# Get Filesize for Free Space Check
						filesize = int(os_path.getsize("%s/%s" % (config.usage.timeshift_path.value,savefilename)) / (1024*1024))

						# Save Current Event by copying it to the other device
						if filesize <= freespace:
							os_link("%s/%s" % (config.usage.timeshift_path.value,savefilename), "%s/%s.copy" % (config.usage.timeshift_path.value,savefilename))
							copy_cmd = "cp '%s/%s.copy' '%s.ts'" % (config.usage.timeshift_path.value,savefilename,fullname)
							metafile = open("%s.ts.meta" % (fullname), "w")
							metafile.write("%s\n%s\n%s\n%i\n%s" % (self.pts_curevent_servicerefname,self.pts_curevent_name,self.pts_curevent_description,int(self.pts_starttime),metamergestring))
							metafile.close()
					elif timeshiftfile.startswith("pts_livebuffer"):
						# Get Filesize for Free Space Check
						filesize = int(os_path.getsize("%s/%s" % (config.usage.timeshift_path.value, timeshiftfile)) / (1024*1024))

						# Save stored timeshift by copying it to the other device
						if filesize <= freespace:
							os_link("%s/%s" % (config.usage.timeshift_path.value,timeshiftfile), "%s/%s.copy" % (config.usage.timeshift_path.value,timeshiftfile))
							copyfile("%s/%s.meta" % (config.usage.timeshift_path.value,timeshiftfile),"%s.ts.meta" % (fullname))
							copy_cmd = "cp '%s/%s.copy' '%s.ts'" % (config.usage.timeshift_path.value,timeshiftfile,fullname)

					# Only copy file when enough disk-space available!
					if filesize <= freespace:
						timeshift_saved = True
						self.session.open(MessageBox, _("Saving timeshift as movie now. This might take a while!"), MessageBox.TYPE_INFO, timeout=5)
						self.ptsFrontpanelActions("start")
						JobManager.AddJob(CopyTimeshiftJob(self, copy_cmd))
					else:
						timeshift_saved = False
						timeshift_saveerror1 = ""
						timeshift_saveerror2 = _("Not enough free Diskspace!\n\nFilesize: %sMB\nFree Space: %sMB\nPath: %s" % (filesize,freespace,config.usage.default_path.value))
						self.save_timeshift_postaction = None

				except Exception, errormsg:
					timeshift_saved = False
					timeshift_saveerror2 = errormsg

			if not timeshift_saved:
				errormessage = str(timeshift_saveerror1) + "\n" + str(timeshift_saveerror2)
				self.session.open(MessageBox, _("Timeshift save failed!")+"\n\n%s" % errormessage, MessageBox.TYPE_ERROR)

	def ptsCleanTimeshiftFolder(self):
		if not config.plugins.pts.enabled.value or self.ptsCheckTimeshiftPath() is False or self.session.screen["Standby"].boolean is True:
			return

		try:
			for filename in os_listdir(config.usage.timeshift_path.value):
				if (filename.startswith("timeshift.") or filename.startswith("pts_livebuffer.")) and (filename.endswith(".del") is False and filename.endswith(".meta") is False and filename.endswith(".copy") is False):

					statinfo = os_stat("%s/%s" % (config.usage.timeshift_path.value,filename))
					# if no write for 5 sec = stranded timeshift
					if statinfo.st_mtime < (time()-5.0):
						print "PTS-Plugin: Erasing stranded timeshift %s" % filename
						self.BgFileEraser.erase("%s/%s" % (config.usage.timeshift_path.value,filename))

						# Delete Meta File too
						if filename.startswith("pts_livebuffer.") is True:
							self.BgFileEraser.erase("%s/%s.meta" % (config.usage.timeshift_path.value,filename))
		except:
			print "PTS: IO-Error while cleaning Timeshift Folder ..."

	def ptsGetEventInfo(self):
		event = None
		try:
			serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
			serviceHandler = eServiceCenter.getInstance()
			info = serviceHandler.info(serviceref)

			self.pts_curevent_servicerefname = serviceref.toString()
			self.pts_curevent_station = info.getName(serviceref)

			service = self.session.nav.getCurrentService()
			info = service and service.info()
			event = info and info.getEvent(0)
		except Exception, errormsg:
			self.session.open(MessageBox, _("Getting Event Info failed!")+"\n\n%s" % errormsg, MessageBox.TYPE_ERROR, timeout=10)

		if event is not None:
			curEvent = parseEvent(event)
			self.pts_curevent_begin = int(curEvent[0])
			self.pts_curevent_end = int(curEvent[1])
			self.pts_curevent_name = curEvent[2]
			self.pts_curevent_description = curEvent[3]
			self.pts_curevent_eventid = curEvent[4]

	def ptsFrontpanelActions(self, action=None):
		if InfoBarInstantRecord.isInstantRecordRunning(self):
			return

		if action == "start":
			try:
				open("/proc/stb/fp/led0_pattern", "w").write("0x55555555")
				open("/proc/stb/fp/led_pattern_speed", "w").write("20")
			except IOError:
				print "PTS-Plugin: No FrontPanel LED that can start blinking"
		elif action == "stop":
			try:
				open("/proc/stb/fp/led0_pattern", "w").write("0")
			except IOError:
				print "PTS-Plugin: No FrontPanel LED that can stop blinking"

	def ptsCreateHardlink(self):
		for filename in os_listdir(config.usage.timeshift_path.value):
			if filename.startswith("timeshift.") and not filename.endswith(".del") and not filename.endswith(".copy"):
				statinfo = os_stat("%s/%s" % (config.usage.timeshift_path.value,filename))
				if statinfo.st_mtime > (time()-5.0):
					try:
						self.BgFileEraser.erase("%s/pts_livebuffer.%s" % (config.usage.timeshift_path.value,self.pts_eventcount))
					except Exception, e:
						print "PTS Plugin: %s" % (e)

					try:
						os_link("%s/%s" % (config.usage.timeshift_path.value,filename), "%s/pts_livebuffer.%s" % (config.usage.timeshift_path.value,self.pts_eventcount))

						# Create a Meta File
						metafile = open("%s/pts_livebuffer.%s.meta" % (config.usage.timeshift_path.value,self.pts_eventcount), "w")
						metafile.write("%s\n%s\n%s\n%i\n" % (self.pts_curevent_servicerefname,self.pts_curevent_name,self.pts_curevent_description,int(self.pts_starttime)))
						metafile.close()
					except Exception, errormsg:
						self.session.open(MessageBox, _("Creating Hardlink to Timeshift file failed!")+"\nFilesystems like FAT32 do not support hardlinks!"+"\n\n%s" % errormsg, MessageBox.TYPE_ERROR)

	def ptsMergeRecords(self):
		if InfoBarInstantRecord.isInstantRecordRunning(self):
			self.pts_mergeRecords_timer.start(120000, True)
			return

		ptsmergeSRC = ""
		ptsmergeDEST = ""
		ptsmergeeventname = ""
		ptsgetnextfile = False

		filelist = os_listdir(config.usage.default_path.value)

		if filelist is not None:
			filelist.sort()

		for filename in filelist:
			if filename.endswith(".meta"):
				# Get Event Info from meta file
				readmetafile = open("%s/%s" % (config.usage.default_path.value,filename), "r")
				servicerefname = readmetafile.readline()[0:-1]
				eventname = readmetafile.readline()[0:-1]
				eventtitle = readmetafile.readline()[0:-1]
				eventtime = readmetafile.readline()[0:-1]
				eventtag = readmetafile.readline()[0:-1]
				readmetafile.close()

				if ptsgetnextfile:
					ptsgetnextfile = False
					ptsmergeSRC = filename[0:-5]

					if ASCIItranslit.legacyEncode(eventname) == ASCIItranslit.legacyEncode(ptsmergeeventname):
						self.pts_delmergeRecordName = ptsmergeSRC
						self.ptsFrontpanelActions("start")

						self.session.open(MessageBox,_("Merging Timeshift records now!\nThis might take a while ..."), MessageBox.TYPE_INFO, timeout=5)

						# Copy EIT File
						copyfile("%s/%s.eit" % (config.usage.default_path.value, ptsmergeSRC[0:-3]),"%s/%s.eit" % (config.usage.default_path.value, ptsmergeDEST[0:-3]))

						# Delete AP File
						self.BgFileEraser.erase("%s/%s.ap" % (config.usage.default_path.value, ptsmergeDEST))

						# Add Merge Job to JobManager
						JobManager.AddJob(MergeTimeshiftJob(self, "cat '%s/%s' >> '%s/%s'" % (config.usage.default_path.value,ptsmergeSRC,config.usage.default_path.value,ptsmergeDEST)))
						return
					else:
						self.session.open(MessageBox,_("PTS-Plugin: Merging records failed!\nEventnames did not match ...\n\nSRC: %s\nDEST: %s") % (ASCIItranslit.legacyEncode(eventname),ASCIItranslit.legacyEncode(ptsmergeeventname)), MessageBox.TYPE_ERROR)

				if eventtag == "pts_merge":
					ptsgetnextfile = True
					ptsmergeDEST = filename[0:-5]
					ptsmergeeventname = eventname

					# If still recording or transfering, try again later ...
					statinfo = os_stat("%s/%s" % (config.usage.default_path.value,ptsmergeDEST))
					if statinfo.st_mtime > (time()-10.0):
						self.pts_mergeRecords_timer.start(120000, True)
						return

					# Rewrite Meta File to get rid of pts_merge tag
					metafile = open("%s/%s.meta" % (config.usage.default_path.value,ptsmergeDEST), "w")
					metafile.write("%s\n%s\n%s\n%i\n" % (servicerefname,eventname,eventtitle,int(eventtime)))
					metafile.close()

	def ptsCopyFilefinished(self,retval):
		for filename in os_listdir(config.usage.timeshift_path.value):
			if filename.endswith(".copy"):
				self.BgFileEraser.erase("%s/%s" % (config.usage.timeshift_path.value,filename))

		# Restart Merge Timer
		if self.pts_mergeRecords_timer.isActive():
			self.pts_mergeRecords_timer.stop()
			self.pts_mergeRecords_timer.start(15000, True)
		else:
			self.ptsFrontpanelActions("stop")
			self.session.open(MessageBox, _("Timeshift saved to your harddisk!"), MessageBox.TYPE_INFO, timeout = 5)

	def ptsMergeFilefinished(self,retval):
		if self.pts_delmergeRecordName is not None:
			# Delete Instant Record permanently now ... R.I.P.
			self.BgFileEraser.erase("%s/%s" % (config.usage.default_path.value,self.pts_delmergeRecordName))
			self.BgFileEraser.erase("%s/%s.eit" % (config.usage.default_path.value,self.pts_delmergeRecordName[0:-3]))
			self.BgFileEraser.erase("%s/%s.ap" % (config.usage.default_path.value,self.pts_delmergeRecordName))
			self.BgFileEraser.erase("%s/%s.cuts" % (config.usage.default_path.value,self.pts_delmergeRecordName))
			self.BgFileEraser.erase("%s/%s.meta" % (config.usage.default_path.value,self.pts_delmergeRecordName))
			self.BgFileEraser.erase("%s/%s.sc" % (config.usage.default_path.value,self.pts_delmergeRecordName))

			self.pts_delmergeRecordName = None

		self.ptsFrontpanelActions("stop")
		self.session.open(MessageBox,("Records successfully merged!"), MessageBox.TYPE_INFO, timeout = 5)

	def ptsGetSeekInfo(self):
		s = self.session.nav.getCurrentService()
		return s and s.seek()

	def ptsGetPosition(self):
		seek = self.ptsGetSeekInfo()
		if seek is None:
			return None
		pos = seek.getPlayPosition()
		if pos[0]:
			return 0
		return pos[1]

	def ptsGetLength(self):
		seek = self.ptsGetSeekInfo()
		if seek is None:
			return None
		length = seek.getLength()
		if length[0]:
			return 0
		return length[1]

	def ptsSeekPointerOK(self):
		if self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled and self.isSeekable():
			if not self.pvrstate_hide_timer.isActive():
				if self.seekstate != self.SEEK_STATE_PLAY:
					self.setSeekState(self.SEEK_STATE_PLAY)
				self.doShow()
				return

			length = self.ptsGetLength()
			position = self.ptsGetPosition()

			if length is None or position is None:
				return

			cur_pos = self.pvrStateDialog["PTSSeekPointer"].position
			jumptox = int(cur_pos[0]) - int(self.pts_seekpointer_MinX)
			jumptoperc = round((jumptox / 400.0) * 100, 0)
			jumptotime = int((length / 100) * jumptoperc)
			jumptodiff = position - jumptotime

			self.doSeekRelative(-jumptodiff)
		else:
			return

	def ptsSeekPointerLeft(self):
		if self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled and self.isSeekable():
			self.ptsMoveSeekPointer(direction="left")
		else:
			return

	def ptsSeekPointerRight(self):
		if self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled and self.isSeekable():
			self.ptsMoveSeekPointer(direction="right")
		else:
			return

	def ptsSeekPointerReset(self):
		if self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled:
			self.pvrStateDialog["PTSSeekPointer"].setPosition(self.pts_seekpointer_MinX,self.pvrStateDialog["PTSSeekPointer"].position[1])

	def ptsSeekPointerSetCurrentPos(self):
		if not self.pts_pvrStateDialog == "PTSTimeshiftState" or not self.timeshift_enabled or not self.isSeekable():
			return
		
		position = self.ptsGetPosition()
		length = self.ptsGetLength()
		
		if length >= 1:
			tpixels = int((float(int((position*100)/length))/100)*400)
			self.pvrStateDialog["PTSSeekPointer"].setPosition(self.pts_seekpointer_MinX+tpixels, self.pvrStateDialog["PTSSeekPointer"].position[1])

	def ptsMoveSeekPointer(self, direction=None):
		if direction is None or self.pts_pvrStateDialog != "PTSTimeshiftState":
			return

		isvalidjump = False
		cur_pos = self.pvrStateDialog["PTSSeekPointer"].position
		InfoBarTimeshiftState._mayShow(self)

		if direction == "left":
			minmaxval = self.pts_seekpointer_MinX
			movepixels = -15
			if cur_pos[0]+movepixels > minmaxval:
				isvalidjump = True
		elif direction == "right":
			minmaxval = self.pts_seekpointer_MaxX
			movepixels = 15
			if cur_pos[0]+movepixels < minmaxval:
				isvalidjump = True
		else:
			return 0

		if isvalidjump:
			self.pvrStateDialog["PTSSeekPointer"].setPosition(cur_pos[0]+movepixels,cur_pos[1])
		else:
			self.pvrStateDialog["PTSSeekPointer"].setPosition(minmaxval,cur_pos[1])

	def ptsTimeshiftFileChanged(self):
		# Reset Seek Pointer
		if config.plugins.pts.enabled.value and config.plugins.pts.showinfobar.value:
			self.ptsSeekPointerReset()
		
		if self.pts_switchtolive:
			self.pts_switchtolive = False
			return

		if self.pts_seektoprevfile:
			if self.pts_currplaying == 1:
				self.pts_currplaying = config.plugins.pts.maxevents.value
			else:
				self.pts_currplaying -= 1
		else:
			if self.pts_currplaying == config.plugins.pts.maxevents.value:
				self.pts_currplaying = 1
			else:
				self.pts_currplaying += 1

		if not fileExists("%s/pts_livebuffer.%s" % (config.usage.timeshift_path.value,self.pts_currplaying), 'r'):
			self.pts_currplaying = self.pts_eventcount

		# Set Eventname in PTS InfoBar
		if config.plugins.pts.enabled.value and config.plugins.pts.showinfobar.value:
			try:
				if self.pts_eventcount != self.pts_currplaying:
					readmetafile = open("%s/pts_livebuffer.%s.meta" % (config.usage.timeshift_path.value,self.pts_currplaying), "r")
					servicerefname = readmetafile.readline()[0:-1]
					eventname = readmetafile.readline()[0:-1]
					readmetafile.close()
					self.pvrStateDialog["eventname"].setText(eventname)
				else:
					self.pvrStateDialog["eventname"].setText("")
			except Exception, errormsg:
				self.pvrStateDialog["eventname"].setText("")
		
		# Get next pts file ...
		if self.pts_currplaying+1 > config.plugins.pts.maxevents.value:
			nextptsfile = 1
		else:
			nextptsfile = self.pts_currplaying+1

		# Seek to previous file
		if self.pts_seektoprevfile:
			self.pts_seektoprevfile = False

			if fileExists("%s/pts_livebuffer.%s" % (config.usage.timeshift_path.value,nextptsfile), 'r'):
				self.ptsSetNextPlaybackFile("pts_livebuffer.%s" % (nextptsfile))

			self.ptsSeekBackHack()
		else:
			if fileExists("%s/pts_livebuffer.%s" % (config.usage.timeshift_path.value,nextptsfile), 'r') and nextptsfile <= self.pts_eventcount:
				self.ptsSetNextPlaybackFile("pts_livebuffer.%s" % (nextptsfile))
			if nextptsfile == self.pts_currplaying:
				self.pts_switchtolive = True
				self.ptsSetNextPlaybackFile("")

	def ptsSetNextPlaybackFile(self, nexttsfile):
		ts = self.getTimeshift()
		if ts is None:
			return

		try:
			ts.setNextPlaybackFile("%s/%s" % (config.usage.timeshift_path.value,nexttsfile))
		except:
			print "PTS-Plugin: setNextPlaybackFile() not supported by OE. Enigma2 too old !?"

	def ptsSeekBackHack(self):
		if not config.plugins.pts.enabled.value or not self.timeshift_enabled:
			return

		self.setSeekState(self.SEEK_STATE_PAUSE)
		self.doSeek(-90000*4) # seek ~4s before end
		self.pts_SeekBack_timer.start(1000, True)

	def ptsSeekBackTimer(self):
		if self.pts_lastseekspeed == 0:
			self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
		else:
			self.setSeekState(self.makeStateBackward(int(-self.pts_lastseekspeed)))

	def ptsCheckTimeshiftPath(self):
		if self.pts_pathchecked:
			return True
		else:
			if fileExists(config.usage.timeshift_path.value, 'w'):
				self.pts_pathchecked = True
				return True
			else:
				self.session.open(MessageBox, _("Could not activate Permanent-Timeshift!\nTimeshift-Path does not exist"), MessageBox.TYPE_ERROR, timeout=15)
				if self.pts_delay_timer.isActive():
					self.pts_delay_timer.stop()
				if self.pts_cleanUp_timer.isActive():
					self.pts_cleanUp_timer.stop()
				return False

	def ptsTimerEntryStateChange(self, timer):
		if not config.plugins.pts.enabled.value or not config.plugins.pts.stopwhilerecording.value:
			return

		self.pts_record_running = self.session.nav.RecordTimer.isRecording()

		# Abort here when box is in standby mode
		if self.session.screen["Standby"].boolean is True:
			return

		# Stop Timeshift when Record started ...
		if timer.state == TimerEntry.StateRunning and self.timeshift_enabled and self.pts_record_running:
			if self.ptsLiveTVStatus() is False:
				self.timeshift_enabled = 0
				self.pts_LengthCheck_timer.stop()
				return

			if self.seekstate != self.SEEK_STATE_PLAY:
				self.setSeekState(self.SEEK_STATE_PLAY)

			if self.isSeekable():
				self.session.open(MessageBox,_("Record started! Stopping timeshift now ..."), MessageBox.TYPE_INFO, timeout=5)

			self.stopTimeshiftConfirmed(True, False)
			
		# Restart Timeshift when all records stopped
		if timer.state == TimerEntry.StateEnded and not self.timeshift_enabled and not self.pts_record_running:
			self.ActivatePermanentTimeshift()

		# Restart Merge-Timer when all records stopped
		if timer.state == TimerEntry.StateEnded and self.pts_mergeRecords_timer.isActive():
			self.pts_mergeRecords_timer.stop()
			self.pts_mergeRecords_timer.start(15000, True)

		# Restart FrontPanel LED when still copying or merging files
		# ToDo: Only do this on PTS Events and not events from other jobs
		if timer.state == TimerEntry.StateEnded and (len(JobManager.getPendingJobs()) >= 1 or self.pts_mergeRecords_timer.isActive()):
			self.ptsFrontpanelActions("start")
		
	def ptsLiveTVStatus(self):
		service = self.session.nav.getCurrentService()
		info = service and service.info()
		sTSID = info and info.getInfo(iServiceInformation.sTSID) or -1

		if sTSID is None or sTSID == -1:
			return False
		else:
			return True

	def ptsLengthCheck(self):
		# Check if we are in TV Mode ...
		if self.ptsLiveTVStatus() is False:
			self.timeshift_enabled = 0
			self.pts_LengthCheck_timer.stop()
			return

		if config.plugins.pts.stopwhilerecording.value and self.pts_record_running:
			return

		# Length Check
		if config.plugins.pts.enabled.value and self.session.screen["Standby"].boolean is not True and self.timeshift_enabled and (time() - self.pts_starttime) >= (config.plugins.pts.maxlength.value * 60):
			if self.save_current_timeshift:
				self.saveTimeshiftActions("savetimeshift")
				self.ActivatePermanentTimeshift()
				self.save_current_timeshift = True
			else:
				self.ActivatePermanentTimeshift()
			self.session.open(MessageBox,_("Maximum Timeshift length per Event reached!\nRestarting Timeshift now ..."), MessageBox.TYPE_INFO, timeout=5)

#Replace the InfoBar with our version ;)
Screens.InfoBar.InfoBar = InfoBarPTS

############
#zapUp Hack#
############
InfoBarChannelSelection_zapUp = InfoBarChannelSelection.zapUp

def zapUp(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "zapUp"
		InfoBarPTS.saveTimeshiftActions(self)
	else:
		InfoBarChannelSelection_zapUp(self)

InfoBarChannelSelection.zapUp = zapUp

##############
#zapDown Hack#
##############
InfoBarChannelSelection_zapDown = InfoBarChannelSelection.zapDown

def zapDown(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "zapDown"
		InfoBarPTS.saveTimeshiftActions(self)
	else:
		InfoBarChannelSelection_zapDown(self)

InfoBarChannelSelection.zapDown = zapDown

##################
#historyBack Hack#
##################
InfoBarChannelSelection_historyBack = InfoBarChannelSelection.historyBack

def historyBack(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "historyBack"
		InfoBarPTS.saveTimeshiftActions(self)
	elif self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled and self.isSeekable():
		InfoBarTimeshiftState._mayShow(self)
		self.pvrStateDialog["PTSSeekPointer"].setPosition(self.pts_seekpointer_MinX, self.pvrStateDialog["PTSSeekPointer"].position[1])
		if self.seekstate != self.SEEK_STATE_PLAY:
			self.setSeekState(self.SEEK_STATE_PLAY)
		self.ptsSeekPointerOK()
	else:
		InfoBarChannelSelection_historyBack(self)

InfoBarChannelSelection.historyBack = historyBack

##################
#historyNext Hack#
##################
InfoBarChannelSelection_historyNext = InfoBarChannelSelection.historyNext

def historyNext(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "historyNext"
		InfoBarPTS.saveTimeshiftActions(self)
	elif self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled and self.isSeekable():
		InfoBarTimeshiftState._mayShow(self)
		self.pvrStateDialog["PTSSeekPointer"].setPosition(self.pts_seekpointer_MaxX, self.pvrStateDialog["PTSSeekPointer"].position[1])
		if self.seekstate != self.SEEK_STATE_PLAY:
			self.setSeekState(self.SEEK_STATE_PLAY)
		self.ptsSeekPointerOK()
	else:
		InfoBarChannelSelection_historyNext(self)

InfoBarChannelSelection.historyNext = historyNext

######################
#switchChannelUp Hack#
######################
InfoBarChannelSelection_switchChannelUp = InfoBarChannelSelection.switchChannelUp

def switchChannelUp(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "switchChannelUp"
		InfoBarPTS.saveTimeshiftActions(self)
	else:
		InfoBarChannelSelection_switchChannelUp(self)

InfoBarChannelSelection.switchChannelUp = switchChannelUp

########################
#switchChannelDown Hack#
########################
InfoBarChannelSelection_switchChannelDown = InfoBarChannelSelection.switchChannelDown

def switchChannelDown(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "switchChannelDown"
		InfoBarPTS.saveTimeshiftActions(self)
	else:
		InfoBarChannelSelection_switchChannelDown(self)

InfoBarChannelSelection.switchChannelDown = switchChannelDown

######################
#openServiceList Hack#
######################
InfoBarChannelSelection_openServiceList = InfoBarChannelSelection.openServiceList

def openServiceList(self):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "openServiceList"
		InfoBarPTS.saveTimeshiftActions(self)
	else:
		InfoBarChannelSelection_openServiceList(self)

InfoBarChannelSelection.openServiceList = openServiceList

###########################
#showRadioChannelList Hack#
###########################
InfoBarChannelSelection_showRadioChannelList = InfoBarChannelSelection.showRadioChannelList

def showRadioChannelList(self, zap=False):
	if self.save_current_timeshift and self.timeshift_enabled:
		self.save_timeshift_postaction = "showRadioChannelList"
		InfoBarPTS.saveTimeshiftActions(self)
	else:
		InfoBarChannelSelection_showRadioChannelList(self, zap)

InfoBarChannelSelection.showRadioChannelList = showRadioChannelList

#######################
#InfoBarNumberZap Hack#
#######################
InfoBarNumberZap_keyNumberGlobal = InfoBarNumberZap.keyNumberGlobal

def keyNumberGlobal(self, number):
	if self.save_current_timeshift and self.timeshift_enabled:
		InfoBarPTS.saveTimeshiftActions(self)
		return

	if self.pts_pvrStateDialog == "PTSTimeshiftState" and self.timeshift_enabled and self.isSeekable() and number == 0:
		InfoBarTimeshiftState._mayShow(self)
		self.pvrStateDialog["PTSSeekPointer"].setPosition(self.pts_seekpointer_MaxX/2, self.pvrStateDialog["PTSSeekPointer"].position[1])
		if self.seekstate != self.SEEK_STATE_PLAY:
			self.setSeekState(self.SEEK_STATE_PLAY)
		self.ptsSeekPointerOK()
		return

	InfoBarNumberZap_keyNumberGlobal(self, number)
	if number and config.plugins.pts.enabled.value and self.timeshift_enabled and not self.isSeekable():
		self.session.openWithCallback(self.numberEntered, NumberZap, number)

InfoBarNumberZap.keyNumberGlobal = keyNumberGlobal

###########################
#InfoBarInstantRecord Hack#
###########################
InfoBarInstantRecord_recordQuestionCallback = InfoBarInstantRecord.recordQuestionCallback

def recordQuestionCallback(self, answer):
	InfoBarInstantRecord_recordQuestionCallback(self, answer)

	if config.plugins.pts.enabled.value:
		if answer is not None and answer[1] == "savetimeshift":
			self.session.open(MessageBox,_("Timeshift will get saved at end of event!"), MessageBox.TYPE_INFO, timeout=5)
			self.save_current_timeshift = True

		if answer is not None and answer[1] == "savetimeshiftEvent":
			InfoBarPTS.saveTimeshiftEventPopup(self)

		if answer is not None and answer[1].startswith("pts_livebuffer") is True:
			InfoBarPTS.SaveTimeshift(self, timeshiftfile=answer[1])

InfoBarInstantRecord.recordQuestionCallback = recordQuestionCallback

############################
#InfoBarTimeshiftState Hack#
############################
def _mayShow(self):
	if self.execing and self.timeshift_enabled and self.isSeekable():
		InfoBarPTS.ptsSeekPointerSetCurrentPos(self)
		self.pvrStateDialog.show()
			
		self.pvrstate_hide_timer = eTimer()
		self.pvrstate_hide_timer.callback.append(self.pvrStateDialog.hide)

		if self.seekstate == self.SEEK_STATE_PLAY:
			idx = config.usage.infobar_timeout.index
			if not idx:
				idx = 5
			self.pvrstate_hide_timer.start(idx*1000, True)
		else:
			self.pvrstate_hide_timer.stop()
	elif self.execing and self.timeshift_enabled and not self.isSeekable():
		self.pvrStateDialog.hide()

InfoBarTimeshiftState._mayShow = _mayShow

##################
# seekBack Hack  #
##################
InfoBarSeek_seekBack = InfoBarSeek.seekBack

def seekBack(self):
	InfoBarSeek_seekBack(self)
	self.pts_lastseekspeed = self.seekstate[1]

InfoBarSeek.seekBack = seekBack

####################
#instantRecord Hack#
####################
InfoBarInstantRecord_instantRecord = InfoBarInstantRecord.instantRecord

def instantRecord(self):
	if not config.plugins.pts.enabled.value or not self.timeshift_enabled:
		InfoBarInstantRecord_instantRecord(self)
		return

	dir = preferredInstantRecordPath()
	if not dir or not fileExists(dir, 'w'):
		dir = defaultMoviePath()
	try:
		stat = os_stat(dir)
	except:
		# XXX: this message is a little odd as we might be recording to a remote device
		self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
		return

	if self.isInstantRecordRunning():
		self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
			title=_("A recording is currently running.\nWhat do you want to do?"), \
			list=((_("stop recording"), "stop"), \
			(_("add recording (stop after current event)"), "event"), \
			(_("add recording (indefinitely)"), "indefinitely"), \
			(_("add recording (enter recording duration)"), "manualduration"), \
			(_("add recording (enter recording endtime)"), "manualendtime"), \
			(_("change recording (duration)"), "changeduration"), \
			(_("change recording (endtime)"), "changeendtime"), \
			(_("Timeshift")+" "+_("save recording (stop after current event)"), "savetimeshift"), \
			(_("Timeshift")+" "+_("save recording (Select event)"), "savetimeshiftEvent"), \
			(_("do nothing"), "no")))
	else:
		self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
			title=_("Start recording?"), \
			list=((_("add recording (stop after current event)"), "event"), \
			(_("add recording (indefinitely)"), "indefinitely"), \
			(_("add recording (enter recording duration)"), "manualduration"), \
			(_("add recording (enter recording endtime)"), "manualendtime"), \
			(_("Timeshift")+" "+_("save recording (stop after current event)"), "savetimeshift"), \
			(_("Timeshift")+" "+_("save recording (Select event)"), "savetimeshiftEvent"), \
			(_("don't record"), "no")))

InfoBarInstantRecord.instantRecord = instantRecord

############################
#####  SETTINGS SCREEN #####
############################
class PermanentTimeShiftSetup(Screen, ConfigListScreen):
	def __init__(self, session):
		Screen.__init__(self, session)
		self.skinName = [ "PTSSetup", "Setup" ]
		self.setup_title = _("Permanent Timeshift Settings")

		self.onChangedEntry = [ ]
		self.list = [ ]
		ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changedEntry)

		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
		{
			"ok": self.SaveSettings,
			"green": self.SaveSettings,
			"red": self.Exit,
			"cancel": self.Exit
		}, -2)

		self["key_green"] = StaticText(_("OK"))
		self["key_red"] = StaticText(_("Cancel"))

		self.createSetup()
		self.onLayoutFinish.append(self.layoutFinished)

	def layoutFinished(self):
		self.setTitle(self.setup_title)

	def createSetup(self):
		self.list = [ getConfigListEntry(_("Permanent Timeshift Enable"), config.plugins.pts.enabled) ]
		if config.plugins.pts.enabled.value:
			self.list.extend((
				getConfigListEntry(_("Permanent Timeshift Max Events"), config.plugins.pts.maxevents),
				getConfigListEntry(_("Permanent Timeshift Max Length"), config.plugins.pts.maxlength),
				getConfigListEntry(_("Permanent Timeshift Start Delay"), config.plugins.pts.startdelay),
				getConfigListEntry(_("Timeshift-Save Action on zap"), config.plugins.pts.favoriteSaveAction),
				getConfigListEntry(_("Stop timeshift while recording?"), config.plugins.pts.stopwhilerecording),
				getConfigListEntry(_("Show PTS Infobar while timeshifting?"), config.plugins.pts.showinfobar)
			))

		self["config"].list = self.list
		self["config"].setList(self.list)

	def keyLeft(self):
		ConfigListScreen.keyLeft(self)
		if self["config"].getCurrent()[1] == config.plugins.pts.enabled:
			self.createSetup()

	def keyRight(self):
		ConfigListScreen.keyRight(self)
		if self["config"].getCurrent()[1] == config.plugins.pts.enabled:
			self.createSetup()

	def changedEntry(self):
		for x in self.onChangedEntry:
			x()

	def getCurrentEntry(self):
		return self["config"].getCurrent()[0]

	def getCurrentValue(self):
		return str(self["config"].getCurrent()[1].getText())

	def createSummary(self):
		return SetupSummary

	def SaveSettings(self):
		config.plugins.pts.save()
		configfile.save()
		self.close()

	def Exit(self):
		self.close()

#################################################

def startSetup(menuid):
	if menuid != "system":
		return [ ]
	return [(_("Timeshift Settings"), PTSSetupMenu, "pts_setup", 50)]

def PTSSetupMenu(session, **kwargs):
	session.open(PermanentTimeShiftSetup)

def Plugins(path, **kwargs):
	return [ PluginDescriptor(name=_("Permanent Timeshift Settings"), description=_("Permanent Timeshift Settings"), where=PluginDescriptor.WHERE_MENU, fnc=startSetup) ]
