#!/usr/bin/python
# coding=utf-8
#*********************************************************************
#
# PyMPDTouchGui
# Gui for controlling the MusicPlayDaemon on Touchscreens
#
# written by Timo Boettcher
# pympdtouchgui (near) spida (.) net
#
# (C) 2007-2009 Timo Boettcher
# This is free software. You may redistribute copies of it under the
# terms of the GNU General Public License (Version 2)
# <http://www.gnu.org/licenses/gpl.html>.
# There is NO WARRANTY, to the extent permitted by law.
#
#*********************************************************************


try:
	import sys
	import os
	import optparse
	import ConfigParser
	import time
	import datetime
	import logging
	import pygame
	from pygame import image
	import pygame.locals
	from twisted.internet import reactor
	import libpympdtouchgui.events as events
	import libpympdtouchgui.gui as gui
	from libpympdtouchgui.mpdclienttwisted import MPDClientFactory
	import gc
except ImportError, err:
	print "couldn't load module. %s"%(err)
	sys.exit(2)

PyLircFound = False
try:
	import pylirc
	PyLircFound = True
except ImportError, err:
	# Pylirc is optional, ignore the error, message is printed later
	pass

AllowDaemonize = False
if os.name == 'posix':
	try:
		import resource
		import pwd
		import grp
		AllowDaemonize = True
	except ImportError, err:
		# Do not allow daemonizing on non-posix-systems and when filedescriptors cannot be detached without the resource module
		pass



VERSION='0.327' #This is automatically replaced by maintainer-scripts


# Options for Daemon
UMASK = 0
WORKDIR = "/"
MAXFD = 1024
if (hasattr(os, "devnull")):
    NULL_DEVICE = os.devnull
else:
    NULL_DEVICE = "/dev/null"

#==============================================================================
class DisplayView:

	def __init__(self, evManager, Config):
		self.isVideoInitialized = False
		self.display = None
		self.Config = Config
		self.logger = logging.getLogger('pympdtouchgui')

		self.evManager = evManager
		self.evManager.RegisterListener(self)

		ScreenSize = (self.Config.ScreenWidth, self.Config.ScreenHeight)

		pygame.display.init()
		pygame.font.init()

		#find the maximum supported window resolution
		try:
			modes = pygame.display.list_modes()
			self.isVideoInitialized = pygame.display.get_init()
		except:
			self.isVideoInitialized = False

		if self.isVideoInitialized:
			MaxModeX = 0
			MaxModeY = 0
			for mode in modes:
				if mode[0] > MaxModeX:
					MaxModeX = mode[0]
					MaxModeY = mode[1]
				if mode[0] == MaxModeX:
					if mode[1] > MaxModeY:
						MaxModeY = mode[1]

			videoflags = pygame.HWSURFACE | pygame.DOUBLEBUF
			if not self.Config.Fullscreen:
				videoflags = videoflags | pygame.RESIZABLE
			else:
				videoflags = videoflags | pygame.FULLSCREEN

			if self.Config.ScreenSizeAuto:
				self.window = pygame.display.set_mode((MaxModeX,MaxModeY), videoflags)
			else:
				self.window = pygame.display.set_mode(ScreenSize, videoflags)

			pygame.display.set_caption('MPD Client')

			self.logger.info("Using Video with %s-driver at %sx%s"%(pygame.display.get_driver(),self.window.get_size()[0],self.window.get_size()[1]))

			# Paint the Background
			background = pygame.Surface(self.window.get_size())
			background.fill(self.Config.Theme.ColorBackground)
			self.window.blit(background, (0,0))
			pygame.display.flip()

			self.Config.Sizes = Sizes(self.window.get_size())

	def CreateWidgets(self):
		self.display = Display(pygame.display, self.window, self.evManager, self.Config)

	def VideoInitialized(self):
		return self.isVideoInitialized

	def Notify(self, event):
		if self.isVideoInitialized:
			if self.display:
				self.display.Notify(event)

#==============================================================================
class Display:
	WidgetInstanceList = []
	DEFAULTWIDGETS = [gui.MenuStartArea,gui.SongArea,gui.PlayControlArea]
	def __init__(self,display,window,evManager,Config):
		self.Config = Config
		self.evManager = evManager

		self.display = display
		self.window = window

		self.KeyboardToggle = None

		self.logger = logging.getLogger('pympdtouchgui')

		# start the default-widgets
		WIDGETS = self.DEFAULTWIDGETS[0:]
		WIDGETS.append(gui.InfoArea)
		for widget in WIDGETS:
			self.CreateWidgets(widget)


	def CreateWidgets(self, widget):
		Parent = "Screen"
		if widget == gui.SongArea:
			Size = self.Config.Sizes.MainAreaSize
			Position = self.Config.Sizes.MainAreaPosition
			mywidget = widget(Parent, Position, Size, self.Config, self.evManager)
			self.WidgetInstanceList.append(mywidget)
		elif widget == gui.InfoArea:
			Size = self.Config.Sizes.InfoAreaSize
			Position = self.Config.Sizes.InfoAreaPosition
			mywidget = widget(Parent, Position, Size, self.Config, self.evManager)
			self.WidgetInstanceList.append(mywidget)
		elif widget == gui.PlayControlArea:
			Size = self.Config.Sizes.ButtonAreaSize
			Position = self.Config.Sizes.ButtonAreaPosition
			mywidget = widget(Parent, Position, Size, self.Config, self.evManager)
			self.WidgetInstanceList.append(mywidget)
		elif widget == gui.MenuStartArea:
			Size = self.Config.Sizes.MenuStartButtonSize
			Position = self.Config.Sizes.MenuStartButtonPosition
			mywidget = widget(Parent, Position, Size, self.Config, self.evManager)
			self.WidgetInstanceList.append(mywidget)
		elif widget == gui.MenuDetailsArea:
			Size = self.Config.Sizes.MainAreaSize
			Position = self.Config.Sizes.MainAreaPosition
			mywidget = widget(Parent, Position, Size, self.Config, self.evManager)
			self.WidgetInstanceList.append(mywidget)
		else:
			self.logger.debug("Unknown Widget %s"%widget)
			sys.exit(99)

	def Notify(self, event):
		MenuButtonSize = self.Config.Sizes.MenuButtonSize
		ScreenSize = self.Config.Sizes.ScreenSize

		if isinstance(event, events.MainAreaEvent):
			background = pygame.Surface(self.Config.Sizes.MainAreaSize)
			background.fill(self.Config.Theme.ColorBackground)
			self.window.blit(background, self.Config.Sizes.MainAreaPosition)
			self.display.flip()
			# find the mainareawidget and kill it
			RemoveList = []
			for WidgetInstance in self.WidgetInstanceList:
				if WidgetInstance.MainAreaWidget:
					# collect all widgets to kill in a separate list
					# killing right here would break the for-loop,
					# and only allow one widget to be killed
					RemoveList.append(WidgetInstance)
			for WidgetInstance in RemoveList:
				WidgetInstance.kill()
				self.WidgetInstanceList.remove(WidgetInstance)
				del(WidgetInstance)


			# do not show second info at the bottom if the mainareawidget already has the info
			ev = events.InfoareaEvent(event.widget != "Status")
			self.evManager.Notify(ev)

			# start the new widget
			mywidget = 0
			Size = self.Config.Sizes.MainAreaSize
			Position = self.Config.Sizes.MainAreaPosition
			Parent = "Screen"
			if event.widget != "Browse" and self.KeyboardToggle in self.WidgetInstanceList:
				# Keyboardtoggle is only used for Browse
				self.WidgetInstanceList.remove(self.KeyboardToggle)
				self.KeyboardToggle.kill()
				self.KeyboardToggle = None
			if event.widget == "Status":
				mywidget = gui.SongArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "Search":
				mywidget = gui.SearchArea(Parent, Position, Size, self.Config, self.evManager, event.extended)
			elif event.widget == "SearchResult":
				mywidget = gui.SearchResultArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "List":
				mywidget = gui.PlaylistArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "AlarmClock":
				mywidget = gui.AlarmClockArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "SleepClock":
				mywidget = gui.SleepClockArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "Browse":
				mywidget = gui.BrowseArea(Parent, Position, Size, self.Config, self.evManager, event.extended)
				if self.Config.VirtualKeyboard and not (self.KeyboardToggle in self.WidgetInstanceList):
					# don't start new keyboardtoggle if there is one
					self.KeyboardToggle = gui.KeyboardToggleArea(Parent, self.Config.Sizes.KeyboardButtonPosition, self.Config.Sizes.KeyboardButtonSize, self.Config, self.evManager, event.extended)
					self.KeyboardToggle.set_Callback(mywidget.CallbackToggleKeyboard)
					self.WidgetInstanceList.append(self.KeyboardToggle)
			elif event.widget == "Menu":
				mywidget = gui.MenuDetailsArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "SleepImage":
				mywidget = gui.SleepImageArea(Parent, Position, Size, self.Config, self.evManager)
			elif event.widget == "WakeupImage":
				mywidget = gui.WakeupImageArea(Parent, Position, Size, self.Config, self.evManager)
			if mywidget:
				self.WidgetInstanceList.append(mywidget)

			self.Update()
			if event.widget == "Browse":
				# populate browselist
				if event.extended != None:
					if isinstance(event.extended, dict):
						if event.extended.has_key("Path"):
							ev = events.BrowseEvent(event.extended["Path"])
						else:
							ev = events.BrowseEvent("")
					else:
						self.logger.fatal("extended is expected to be a 3-dir")
						sys.exit(99)
				else:
					ev = events.BrowseEvent("")
				self.evManager.Notify(ev)
			elif event.widget == "List":
				ev = events.PlaylistEvent()
				self.evManager.Notify(ev)
				ev = events.ServerUpdateRequestEvent()
				self.evManager.Notify(ev)
			elif event.widget == "Status":
				ev = events.ServerUpdateRequestEvent()
				self.evManager.Notify(ev)
			# cleanup now!
			gc.collect()
		elif isinstance(event, events.ScreensaverEvent):
			Parent = "Screen"

			# Cleanup
			background = pygame.Surface(self.Config.Sizes.ScreenSize)
			background.fill(self.Config.Theme.ColorBackground)
			self.window.blit(background, (0,0))
			self.display.flip()
			for WidgetInstance in self.WidgetInstanceList:
				WidgetInstance.kill()
				self.WidgetInstanceList.remove(WidgetInstance)
				del(WidgetInstance)
			if event.ScreensaverEnable:
				Size = self.Config.Sizes.ScreenSize
				Position = (0,0)
				mywidget = gui.ScreensaverImage(Parent, Position, Size, self.Config, self.evManager)
				self.WidgetInstanceList.append(mywidget)
			else:
				# start the default-widgets
				WIDGETS = self.DEFAULTWIDGETS[0:]
				WIDGETS.append(gui.InfoArea)
				for widget in WIDGETS:
					self.CreateWidgets(widget)

		elif isinstance(event, events.WindowResizeEvent):
			self.logger.debug("Got resized to %s,%s"%event.size)

		elif not (isinstance(event, events.TickEvent) or isinstance(event, events.ServerUpdateRequestEvent)):
			for WidgetInstance in self.WidgetInstanceList:
				if isinstance(event, events.MouseClickEvent):
					WidgetInstance.Clicked(event.clickpos[0], event.clickpos[1])
				elif isinstance(event, events.InfraredEvent):
					WidgetInstance.HandleEvent(event)
				else:
					WidgetInstance.HandleEvent(event)

	def Update(self):
		for WidgetInstance in self.WidgetInstanceList:
			for S in WidgetInstance.Children():
				if isinstance(S,pygame.sprite.Sprite):
					S.update()
					self.window.blit(S.image, S.rect)
				else:
					self.logger.debug("* Not a sprite: %s"%S)
		self.display.flip()

#==============================================================================
class TextLog:
	def __init__(self, evManager, Config):
		self.Config = Config
		self.evManager = evManager
		self.evManager.RegisterListener(self)
		self.logger = logging.getLogger('pympdtouchgui')

	def Notify(self, event):
		if self.Config.Debug:
			self.logger.debug("== Event: %s"%event.name)

#==============================================================================
class ServerConnection:
	def __init__(self, evManager, Config, DisplayupdateCallback, InputCallback):
		self.evManager = evManager
		self.evManager.RegisterListener(self)

		self.Config = Config
		self.logger = logging.getLogger('pympdtouchgui')

		self.Artist = ""
		self.Album = ""
		self.Title = ""
		self.ID = None

		self.State = "Stop"
		self.Time = "0:000"
		self.Random = False
		self.Repeat = False
		self.Volume = 0

		self.browsepath = ""
		self.searchtype = ""
		self.searchstring = ""

		self.protocol = None
		self.factory = None

		self.state = "disconnected"

		self.DisplayupdateCallback = DisplayupdateCallback
		self.InputCallback = InputCallback


	def connect(self):
		self.protocol = None
		self.factory = MPDClientFactory(self.Config.ConnectPassword, self.ConnectCallback, self.ReadyCallback, self.DisconnectCallback)
		reactor.connectTCP(self.Config.ConnectHost, self.Config.ConnectPort, self.factory)
		reactor.run()

	def ConnectCallback(self):
		self.protocol = self.factory.getProtocol()
		self.state = "connected"

	def DisconnectCallback(self):
		self.state = "disconnected"
		self.logger.warn("DisConnect")
		reactor.callLater(1, self.connect)

	def ReadyCallback(self):
		self.logger.info("Connected to %s:%s"%(self.Config.ConnectHost, self.Config.ConnectPort))
		self.protocol.setEventCallback("player", self.EventPlayerCallback)
		self.protocol.setEventCallback("mixer", self.EventMixerCallback)
		self.protocol.setEventCallback("options", self.EventOptionsCallback)

		self.protocol.waitEvent(once=False)

		deferc = self.protocol.sendCommand("currentsong")
		deferc.addCallback(self.CallbackCurrentsong)
		defers = self.protocol.sendCommand("status")
		defers.addCallback(self.CallbackStatus)

		reactor.callLater(1, self.TickCallback)

	def TickCallback(self):
		event = events.TickEvent()
		self.evManager.Notify(event)
		gotinput = False
		if self.InputCallback:
			gotinput = self.InputCallback()

		if True:
		#if gotinput: #DEBUG
			if self.DisplayupdateCallback:
				self.DisplayupdateCallback()
		reactor.callLater(1, self.TickCallback)

	def Notify(self, event):
		if isinstance(event, events.PreviousEvent):
			defer = self.protocol.sendCommand("previous")
		elif isinstance(event, events.StopEvent):
			defer = self.protocol.sendCommand("stop")
		elif isinstance(event, events.PlayEvent):
			defer = self.protocol.sendCommand("play")
		elif isinstance(event, events.PauseEvent):
			defer = self.protocol.sendCommand("pause", [1])
		elif isinstance(event, events.NextEvent):
			defer = self.protocol.sendCommand("next")
		elif isinstance(event, events.VolumeQueryEvent):
			ev = events.VolumeStatusEvent(self.QueryVolume())
			self.evManager.Notify(ev)
		elif isinstance(event, events.VolumeSetEvent):
			self.SetVolume(event.volume,False)
		elif isinstance(event, events.VolumeDownEvent):
			self.SetVolume(-10)
		elif isinstance(event, events.MuteEvent):
			self.SetVolume(0,False)
		elif isinstance(event, events.VolumeUpEvent):
			self.SetVolume(10)
		elif isinstance(event, events.SearchEvent):
			self.searchtype = event.searchtype
			self.searchstring = event.searchstring
			defer = self.protocol.sendCommand("search",[event.searchtype,event.searchstring])
			defer.addCallback(self.CallbackSearch)
		elif isinstance(event, events.PlaylistEvent):
			defer = self.protocol.sendCommand("playlistinfo")
			defer.addCallback(self.CallbackPlaylistInfo)
		elif isinstance(event, events.BrowseEvent):
			self.browsepath = event.path
			defer = self.protocol.sendCommand("lsinfo", [event.path])
			defer.addCallback(self.CallbackBrowseResult)
		elif isinstance(event, events.PlaylistAddEvent):
			defer = self.protocol.sendCommand("add", [event.path])
		elif isinstance(event, events.PlaylistClearEvent):
			deferc = self.protocol.sendCommand("clear")
			defer = self.protocol.sendCommand("playlistinfo")
			defer.addCallback(self.CallbackPlaylistInfo)
		elif isinstance(event, events.PlaylistDelEvent):
			deferd = self.protocol.sendCommand("deleteid", [event.id])
			defer = self.protocol.sendCommand("playlistinfo")
			defer.addCallback(self.CallbackPlaylistInfo)
		elif isinstance(event, events.PlaylistMoveEvent):
			defer = self.protocol.sendCommand("moveid", [event.moveid, event.insertbeforeid])
		elif isinstance(event, events.UpdateDatabaseEvent):
			defer = self.protocol.sendCommand("update")
		elif isinstance(event, events.RandomEvent):
			defer = self.protocol.sendCommand("random", [event.Random])
		elif isinstance(event, events.RepeatEvent):
			defer = self.protocol.sendCommand("repeat", [event.Repeat])
		elif isinstance(event, events.ServerUpdateRequestEvent):
			deferc = self.protocol.sendCommand("currentsong")
			deferc.addCallback(self.CallbackCurrentsong)
			defers = self.protocol.sendCommand("status")
			defers.addCallback(self.CallbackStatus)
		elif isinstance(event, events.QuitEvent):
			# FIXME gracefull disconnect
			# FIXME cleanup display
			reactor.stop()

	def EventPlayerCallback(self, result):
		defer = self.protocol.sendCommand("currentsong")
		defer.addCallback(self.CallbackCurrentsong)
		defer = self.protocol.sendCommand("status")
		defer.addCallback(self.CallbackStatus)

	def EventOptionsCallback(self, result):
		defer = self.protocol.sendCommand("status")
		defer.addCallback(self.CallbackStatus)

	def EventMixerCallback(self, result):
		defer = self.protocol.sendCommand("status")
		defer.addCallback(self.CallbackStatus)

	def CallbackStatus(self, status):
		if status.has_key("state"):
			self.State = status["state"]
		if status.has_key("random"):
			self.Random = (status["random"] == "1")
		if status.has_key("repeat"):
			self.Repeat = (status["repeat"] == "1")
		if status.has_key("time"):
			self.Time = status["time"]
		if status.has_key("volume"):
			self.Volume = int(status["volume"])
		event = events.PlayUpdateEvent(self.State, self.Time, self.Random, self.Repeat, self.Volume)
		self.evManager.Notify(event)

	def CallbackCurrentsong(self, currentsong):
		if currentsong.has_key("id"):
			self.ID = currentsong["id"]
		else:
			self.ID = None
		if ((currentsong.has_key("artist")) and (currentsong.has_key("title")) and (currentsong.has_key("album"))):
			Artist = currentsong.artist.decode('utf-8')
			Album = currentsong.album.decode('utf-8')
			Title = currentsong.title.decode('utf-8')
			ChangedTitle = (self.Title != Title and self.Artist == Artist and self.Album == Album)
			ChangedAlbum = (self.Artist != Artist or self.Album != Album)
			event = events.CurrentSongInfoEvent(Title, Album, Artist, ChangedTitle, ChangedAlbum, self.ID)
			self.Artist = Artist
			self.Album = Album
			self.Title = Title
		elif ((currentsong.has_key("file")) and (currentsong.has_key("title"))):
			# probably a stream
			Artist = ""
			Album = event.currentsong.file.decode('utf-8')
			Title = event.currentsong.title.decode('utf-8')
			ChangedTitle = (self.Title != Title and self.Artist == Artist and self.Album == Album)
			ChangedAlbum = (self.Artist != Artist or self.Album != Album)
			event = events.CurrentSongInfoEvent(Title, Album, Artist, ChangedTitle, ChangedAlbum, self.ID)
			self.Artist = Artist
			self.Album = Album
			self.Title = Title
		else:
			self.Artist = ""
			self.Album = ""
			self.Title = ""
			event = events.CurrentSongInfoEvent("", "", "", True, True, self.ID)
		self.evManager.Notify(event)

	def CallbackPlaylistInfo(self, playlist):
		ev = events.PlaylistResultEvent(playlist)
		self.evManager.Notify(ev)

	def CallbackBrowseResult(self, browse):
		ev = events.BrowseResultEvent(self.browsepath, browse)
		self.browsepath = ""
		self.evManager.Notify(ev)

	def CallbackSearch(self, searchresults):
		ev = events.SearchResultEvent(self.searchtype, self.searchstring, searchresults)
		self.searchtype = ""
		self.searchstring = ""
		self.evManager.Notify(ev)

	def SetVolume(self, VolumeChange, relative=True):
		Volume = self.Volume
		if relative:
			Volume += VolumeChange
		else:
			Volume = VolumeChange
		if Volume < 0:
			Volume = 0
		if Volume > 100:
			Volume = 100
		defer = self.protocol.sendCommand("setvol", [Volume])

	def QueryVolume(self):
		self.Volume = int(self.connection.do.status().volume)
		return self.Volume

#==============================================================================
class Input:
	def __init__(self, evManager, Config):
		self.evManager = evManager
		self.Config = Config

	def GetInput(self):
		# Handle Input Events
		input = False
		for inputevent in pygame.event.get():
			if inputevent.type == pygame.QUIT:
				if self.Config.AllowQuit:
					event = events.QuitEvent()
					self.evManager.Notify(event)
					input = True
			elif inputevent.type == pygame.KEYDOWN and inputevent.key == pygame.K_ESCAPE:
				if self.Config.AllowQuit:
					event = events.QuitEvent()
					self.evManager.Notify(event)
					input = True
			elif inputevent.type == pygame.KEYUP:
				event = events.KeyboardEvent(inputevent.key,pygame.key.get_mods())
				self.evManager.Notify(event)
				input = True
			elif inputevent.type == pygame.KEYDOWN:
				pass
			elif inputevent.type == pygame.ACTIVEEVENT:
				pass
			elif inputevent.type == pygame.MOUSEMOTION:
				pass
			elif inputevent.type == pygame.MOUSEBUTTONDOWN:
				pass
			elif inputevent.type == pygame.VIDEORESIZE:
				event = events.WindowResizeEvent(inputevent.size)
				self.evManager.Notify(event)
				input = True
			elif inputevent.type == pygame.MOUSEBUTTONUP:
				event = events.MouseClickEvent(inputevent.button,inputevent.pos)
				self.evManager.Notify(event)
				input = True
			else:
				print "Input: %s"%inputevent.type
		return input # Disyplay is redrawn only when true is returned

#==============================================================================
class Infrared:
	def __init__(self, evManager, Config):
		self.evManager = evManager
		self.evManager.RegisterListener(self)

		self.Config = Config
		self.logger = logging.getLogger('pympdtouchgui')
		try:
			pylircinitresult = pylirc.init("pympdtouchgui", Config.LircrcPath, False)
			if not pylircinitresult:
				self.logger.warn("Could not initialize pylirc")
		except RuntimeError,err:
			if err == "Unable to initialize lirc!":
				self.logger.warn("Could not initialize pylirc")
		except IOError,err:
			if err == "Unable to read configuration!":
				self.logger.warn("could not read lircrc")

	def Notify(self, event):
		if isinstance(event, events.TickEvent):
			buttons = pylirc.nextcode(1)
			while buttons:
				for code in buttons:
					ev = events.InfraredEvent(code["config"],code["repeat"])
					self.evManager.Notify(ev)
				buttons = pylirc.nextcode(1)

	def kill(self):
		pylirc.exit()

#==============================================================================
class EventManager:
	def __init__(self):
		from weakref import WeakKeyDictionary
		self.listeners = WeakKeyDictionary()
		self.eventQueue = []

	def RegisterListener(self, listener):
		self.listeners[listener] = 1

	def UnregisterListener(self, listener):
		if listener in self.listeners.keys():
			del self.listeners[listener]

	def Notify(self, event):
		for listener in self.listeners.keys():
			if listener is None:
				del self.listeners[listener]
				continue
			listener.Notify(event)

#==============================================================================
class PowerManager:
	def __init__(self, evManager, Config):
		self.evManager = evManager
		self.evManager.RegisterListener(self)

		self.Config = Config
		self.logger = logging.getLogger('pympdtouchgui')

	def PowerOff(self):
		self.logger.debug("Poweroff")
		self.ExecuteCommand(self.Config.CommandSleep)

	def PowerOn(self):
		self.logger.debug("Poweron")
		self.ExecuteCommand(self.Config.CommandWakeup)

	def Notify(self, event):
		if isinstance(event, events.PowerEvent):
			if event.PowerDown:
				self.PowerOff()
			else:
				self.PowerOn()

	def ExecuteCommand(self,command):
		if command != "":
			if os.path.isfile(command):
				exe = os.path.split(command)[1]
				result = os.spawnlp(os.P_NOWAIT, command, exe)

#==============================================================================
class ClockManager:
	def __init__(self, evManager, Config):
		self.evManager = evManager
		self.evManager.RegisterListener(self)

		self.Config = Config
		self.logger = logging.getLogger('pympdtouchgui')

		self.VolumeNormal = 0
		self.StepCount = 1
		self.StepsDone = 0
		self.VolumeStepSize = 0
		self.VolumeDuration = 1

		#Amplifier
		self.LastPlayTime = "00:000"
		self.LastPowerState = True # FIXME Find out Powerstate from hardware
		self.LastPlayingTime = datetime.datetime.now()

		#Screensaver
		self.LastInputTime = datetime.datetime.now()
		self.ScreensaverActive = False
		self.LastScreensaverImageChange = datetime.datetime.now()

		#Alarmclock
		self.Today = datetime.datetime.now().day
		self.waketimetoday = datetime.datetime.now()
		self.waketimetomorrow = datetime.datetime.now()
		self.AlarmRinging = False
		self.Sleeping = False
		self.AlarmTodayDone = True
		self.AlarmWaitingForPlay = True
		self.AlarmPlayStartTime = datetime.datetime.now()

		self.UpdateTimes(True)
		self.CheckIfAlarm(True)

	def Notify(self, event):
		if isinstance(event, events.PlayUpdateEvent):
			if self.AlarmWaitingForPlay:
				# if status is playing, but time marker does not advance. File not loaded up to cachelimit yet?
				if event.state == "play" and event.time != self.LastPlayTime:
					self.AlarmWaitingForPlay = False
					self.AlarmPlayStartTime = datetime.datetime.now()
				self.LastPlayTime = event.time
			if self.Config.PowerOffTimeoutEnabled:
				if event.state == "play":
					self.LastPlayingTime = datetime.datetime.now()
					if not self.LastPowerState:
						self.LastPowerState = True
						ev = events.MainAreaEvent("Status")
						self.evManager.Notify(ev)
						ev = events.PowerEvent(False) # PowerOn
						self.evManager.Notify(ev)
				elif event.state == "stop":
					if self.LastPlayingTime + self.Config.PowerOffTimeout < datetime.datetime.now():
						if self.LastPowerState:
							self.LastPowerState = False
							ev = events.MainAreaEvent("SleepImage")
							self.evManager.Notify(ev)
							ev = events.PowerEvent(True) # PowerOff
							self.evManager.Notify(ev)
		elif (isinstance(event, events.MouseClickEvent) or isinstance(event, events.KeyboardEvent) or isinstance(event, events.InfraredEvent)):
		# FIXME Mousemoveevent
			if self.Config.ScreensaverMode != "none":
				self.LastInputTime = datetime.datetime.now()
			if self.ScreensaverActive:
				self.ScreensaverActive = False
				#FIXME jump to last active window
				self.LastScreensaverImageChange = datetime.datetime.now()
				ev = events.ScreensaverEvent(False)
				self.evManager.Notify(ev)

		elif isinstance(event, events.TickEvent):
			self.UpdateTimes()
			self.CheckIfAlarm()
			self.CheckIfSleep()
			if self.AlarmRinging and self.Config.AlarmClock.ClockSwitchStyle != "hard":
				diff = datetime.datetime.now() - self.AlarmPlayStartTime
				StepsDone = int(diff.seconds/self.VolumeDuration)
				ev = events.VolumeSetEvent(int(StepsDone * self.VolumeStepSize))
				self.evManager.Notify(ev)
				if StepsDone >= self.StepCount:
					self.AlarmRinging = False
					ev = events.VolumeSetEvent(self.VolumeNormal)
					self.evManager.Notify(ev)
			if self.Sleeping and self.Config.AlarmClock.ClockSwitchStyle != "hard":
				diff = datetime.datetime.now() - self.Config.AlarmClock.SleepClockTime
				StepsDone = int(diff.seconds/self.VolumeDuration)
				ev = events.VolumeSetEvent(int((self.StepCount-StepsDone) * self.VolumeStepSize))
				self.evManager.Notify(ev)
				if StepsDone >= self.StepCount:
					self.Sleeping = False
					ev = events.StopEvent()
					self.evManager.Notify(ev)
					ev = events.PowerEvent()
					self.evManager.Notify(ev)
					ev = events.VolumeSetEvent(self.VolumeNormal)
					self.evManager.Notify(ev)
			if self.Config.ScreensaverMode != "none":
				if self.LastInputTime + self.Config.ScreensaverTimeout < datetime.datetime.now():
					if not self.ScreensaverActive:
						self.ScreensaverActive = True
						ev = events.ScreensaverEvent()
						self.evManager.Notify(ev)
			if self.LastScreensaverImageChange + self.Config.ScreensaverRefreshTimeout < datetime.datetime.now():
				ev = events.ScreensaverChangeEvent()
				self.evManager.Notify(ev)
				self.LastScreensaverImageChange = datetime.datetime.now()
		elif isinstance(event, events.VolumeStatusEvent):
			self.VolumeNormal = event.volume
		elif isinstance(event, events.ReloadConfigEvent):
			self.UpdateTimes(True)
			self.CheckIfAlarm(True)

	def GetNormalVolume(self):
		event = events.VolumeQueryEvent()
		self.evManager.Notify(event)

	def UpdateTimes(self, InitMode=False):
		# Load the AlarmClock Time for the Next day?
		if self.Today != datetime.datetime.now().day or InitMode:
			now = datetime.datetime.now()
			self.waketimetoday = datetime.datetime(now.year,now.month,now.day,self.Config.AlarmClock.AlarmClockTime[now.weekday()][0],self.Config.AlarmClock.AlarmClockTime[now.weekday()][1])

			# timedelta is (days, seconds, microseconds, milliseconds, minutes, hours, weeks)
			tomorrow = now + datetime.timedelta(1)
			self.waketimetomorrow = datetime.datetime(tomorrow.year,tomorrow.month,tomorrow.day,self.Config.AlarmClock.AlarmClockTime[tomorrow.weekday()][0],self.Config.AlarmClock.AlarmClockTime[tomorrow.weekday()][1])
			self.AlarmTodayDone = False

	def CheckIfAlarm(self, InitMode=False):
		difference = self.waketimetoday - datetime.datetime.now()
		if difference < datetime.timedelta(0,0,0):
			if not self.AlarmTodayDone:
				if not InitMode:
					if self.Config.AlarmClock.AlarmClockEnabled[datetime.datetime.now().weekday()]:
						self.GetNormalVolume()
						self.Alarm(self.VolumeNormal,self.Config.AlarmClock.ClockSwitchStyle, self.Config.AlarmClock.ClockSwitchDuration)
				self.AlarmTodayDone = True

	def CheckIfSleep(self):
		if self.Config.AlarmClock.SleepClockEnabled:
			difference = self.Config.AlarmClock.SleepClockTime - datetime.datetime.now()
			if difference < datetime.timedelta(0,0,0):
				self.Config.AlarmClock.SleepClockEnabled = False
				self.GetNormalVolume()
				self.Sleep(self.VolumeNormal,self.Config.AlarmClock.ClockSwitchStyle, self.Config.AlarmClock.ClockSwitchDuration)

	def Wakeup(self, Volume, SwitchStyle="hard", SwitchDuration=40):
		self.Alarm(self, Volume, SwitchStyle, SwitchDuration)

	def Alarm(self, Volume, SwitchStyle="hard", SwitchDuration=40):
		ev = events.MainAreaEvent("WakeupImage")
		self.evManager.Notify(ev)
		if SwitchStyle != "hard":
			self.StepCount = min(Volume,SwitchDuration)
			if self.StepCount == 0:
				self.StepCount = 1
			self.VolumeStepSize = Volume/float(self.StepCount)
			self.VolumeDuration = int(SwitchDuration/self.StepCount)

			self.AlarmRinging = True
			self.AlarmWaitingForPlay = True
			ev = events.VolumeSetEvent(0)
			self.evManager.Notify(ev)
		ev = events.PowerEvent(False) # PowerOn
		self.evManager.Notify(ev)
		ev = events.PlayEvent()
		self.evManager.Notify(ev)

	def Sleep(self, Volume, SwitchStyle="hard", SwitchDuration=40, Command=""):
		ev = events.MainAreaEvent("SleepImage")
		self.evManager.Notify(ev)
		if SwitchStyle != "hard":
			self.StepCount = min(Volume,SwitchDuration)
			if self.StepCount == 0:
				self.StepCount = 1
			self.VolumeStepSize = Volume/float(self.StepCount)
			self.VolumeDuration = int(SwitchDuration/self.StepCount)

			self.Sleeping = True
		else:
			ev = events.StopEvent()
			self.evManager.Notify(ev)
			ev = events.PowerEvent(True) # PowerOff
			self.evManager.Notify(ev)


#==============================================================================
class Config:
	def __init__(self, ConfigFiles, argv):
		self.logger = logging.getLogger('pympdtouchgui')

		# Defaults for VideoOptions
		self.Fullscreen = False
		self.VirtualKeyboard = False
		self.ScreenSizeAuto = True
		self.ScreenWidth = 0
		self.ScreenHeight = 0

		# Subsections of Config
		self.Sizes = None
		self.Theme = None
		self.AlarmClock = None
		self.ClockStateFile = "/var/lib/pympdtouchgui/clock-state"

		# Defaults for ServerOptions
		self.ConnectHost = "127.0.0.1"
		self.ConnectPort = 6600
		self.ConnectPassword = None

		# Defaults for AlbumartOptions
		self.Debug = False
		self.AlbumArtDir = None
		self.AlbumArtFromAmazon = False
		self.AmazonID = "0MR5G85VBCCM2KS8RK82"

		# Defaults for MiscOptions
		self.ThemeDir = os.path.expanduser("/usr/share/pympdtouchgui/themes/default")
		self.CommandlineConfigFile = None
		self.AllowQuit = True
		self.PowerOffTimeoutEnabled = False
		self.PowerOffTimeout = datetime.timedelta(0,1200) # 20 Minutes
		self.CommandWakeup = None
		self.CommandSleep = None

		self.ScreensaverTimeout = datetime.timedelta(0,600) # 10 Minutes
		self.ScreensaverRefreshTimeout = datetime.timedelta(0,60) # 1 Minute
		self.ScreensaverPath = os.path.expanduser("~/pictures")
		self.ScreensaverMode = "none"
		# timedelta is (days, seconds, microseconds, milliseconds, minutes, hours, weeks)

		self.FontName = None
		self.FontAntialias = True

		self.Lirc = False
		self.LircrcPath = os.path.expanduser("~/.lircrc")

		self.Browser = "firefox"

		#DaemonOptions
		self.Daemonize = None
		self.Pidfile = None
		self.Logfile = None
		self.LowerToGroup = None
		self.LowerToUser = None

		# Frequencies in milliseconds
		self.ClockFreq = 400                # This is the main loop
		self.FreqDisplayUpdate = 400        # How often do we redraw the display
		self.FreqDisplayUpdateBlink = 400   # How fast does the prompt blink

		for ConfigFile in ConfigFiles:
			self.ConfigFileParse(ConfigFile)
		self.ConfigOptParse(argv)
		if self.CommandlineConfigFile:
			self.ConfigFileParse(self.CommandlineConfigFile)


	def ConfigFileParse(self,ConfigFile):
		conf = ConfigParser.ConfigParser()
		filename = os.path.realpath(os.path.expanduser(ConfigFile))
		isfile = os.path.isfile(filename)
		if isfile:
			self.logger.info("Using Configuration from %s"%os.path.expanduser(ConfigFile))
			conf.read(filename)
			if conf.has_section("connection"):
				if conf.has_option("connection", "host"):
					self.ConnectHost = conf.get("connection", "host")
				if conf.has_option("connection", "port"):
					self.ConnectPort = conf.getint("connection", "port")
				if conf.has_option("connection", "password"):
					self.ConnectPassword = conf.get("connection", "password")

			if conf.has_section("display"):
				if conf.has_option("display", "fullscsreen"):
					self.Fullscreen = conf.getboolean("display", "fullscreen")
				if conf.has_option("display", "width"):
					self.ScreenWidth = conf.getint("display", "width")
				if conf.has_option("display", "height"):
					self.ScreenHeight = conf.getint("display", "height")

			if conf.has_section("timer"):
				if conf.has_option("timer", "clockfreq"):
					self.ClockFreq = conf.getint("timer", "clockfreq")
				if conf.has_option("timer", "freqdisplayupdate"):
					self.FreqDisplayUpdate = conf.getint("timer", "freqdisplayupdate")
				if conf.has_option("timer", "freqdisplayupdateblink"):
					self.FreqDisplayUpdateBlink = conf.getint("timer", "freqdisplayupdateblink")

			if conf.has_section("albumart"):
				if conf.has_option("albumart", "dir"):
					self.AlbumArtDir = os.path.expanduser(conf.get("albumart", "dir"))
				if conf.has_option("albumart", "fetchfromamazon"):
					self.AlbumArtFromAmazon = conf.getboolean("albumart", "fetchfromamazon")
				if conf.has_option("albumart", "amazonid"):
					self.AmazonID = conf.get("albumart", "amazonid")

			if conf.has_section("alarmclock"):
				if conf.has_option("alarmclock", "statefile"):
					self.ClockStateFile = os.path.expanduser(conf.get("alarmclock", "statefile"))

			if conf.has_section("other"):
				if conf.has_option("other", "themedir"):
					self.ThemeDir = os.path.expanduser(conf.get("other", "themedir"))
				if conf.has_option("other", "onscreenkeyboard"):
					self.VirtualKeyboard = conf.getboolean("other", "onscreenkeyboard")
				if conf.has_option("other", "browser"):
					self.Browser = os.path.expanduser(conf.get("other", "browser"))
				if conf.has_option("other", "lirc"):
					self.Lirc = conf.getboolean("other", "lirc")
				if conf.has_option("other", "lircrc"):
					self.LircrcPath = os.path.expanduser(conf.get("other", "lircrc"))
				if conf.has_option("other", "allowquit"):
					self.AllowQuit = conf.getboolean("other", "allowquit")
				if conf.has_option("other", "powerofftimeoutenabled"):
					self.PowerOffTimeoutEnabled = conf.getboolean("other", "powerofftimeoutenabled")
				if conf.has_option("other", "powerofftimeout"):
					# timedelta is (days, seconds, microseconds, milliseconds, minutes, hours, weeks)
					self.PowerOffTimeout = datetime.timedelta(0,conf.getint("other", "powerofftimeout"))
				if conf.has_option("other", "commandwakeup"):
					self.CommandWakeup = os.path.expanduser(conf.get("other", "commandwakeup"))
				if conf.has_option("other", "commandsleep"):
					self.CommandSleep = os.path.expanduser(conf.get("other", "commandsleep"))

				if conf.has_option("other", "screensavertimeout"):
					# timedelta is (days, seconds, microseconds, milliseconds, minutes, hours, weeks)
					self.ScreensaverTimeout = datetime.timedelta(0,conf.getint("other", "screensavertimeout"))
				if conf.has_option("other", "screensaverrefresh"):
					# timedelta is (days, seconds, microseconds, milliseconds, minutes, hours, weeks)
					self.ScreensaverRefreshTimeout = datetime.timedelta(0,conf.getint("other", "screensaverrefresh"))
				if conf.has_option("other", "screensaverpath"):
					self.ScreensaverPath = os.path.expanduser(conf.get("other", "screensaverpath"))
				if conf.has_option("other", "screensavermode"):
					self.ScreensaverMode = conf.get("other", "screensavermode")
					if self.ScreensaverMode not in ["none", "linear", "random", "randombydir"]:
						self.logger.fatal("Invalid ScreensaverMode in configfile")
						sys.exit(123)

			if conf.has_section("daemon"):
				if conf.has_option("daemon", "daemonize"):
					self.Daemonize = conf.getboolean("daemon", "daemonize")
				if conf.has_option("daemon", "pidfile"):
					self.Pidfile = os.path.expanduser(conf.get("daemon", "pidfile"))
				if conf.has_option("daemon", "logfile"):
					self.Logfile = os.path.expanduser(conf.get("daemon", "logfile"))
				if conf.has_option("daemon", "lowertouser"):
					self.LowerToUser = conf.get("daemon", "lowertouser")
				if conf.has_option("daemon", "lowertogroup"):
					self.LowerToGroup = conf.get("daemon", "lowertogroup")

			if self.ScreenWidth and self.ScreenHeight:
				self.ScreenSizeAuto = False
		return isfile

	def ConfigOptParse(self,argv):
		parser = optparse.OptionParser()
		parser.add_option('-i', '--connect-ip',            dest='ConnectHost',           action='store',       type="string", help='ip/hostname to connect to', default=None)
		parser.add_option('-p', '--connect-port',          dest='ConnectPort',           action='store',       type="int",    help='port to connect to', default=None)
		parser.add_option('-P', '--password',              dest='ConnectPassword',       action='store',       type="string", help='password to authenticate with', default=None)
		parser.add_option('-k', '--keyboard',              dest='VirtualKeyboard',       action='store_true',                 help='enable onscreen-keyboard', default=None)
		parser.add_option('-f', '--fullscreen',            dest='Fullscreen',            action='store_true',                 help='fullscreen', default=None)
		parser.add_option('-s', '--size',                  dest='ScreenSize',            action='store',       type="string", help='viewable area', default=None, metavar="WIDTHxHEIGHT")
		parser.add_option('-c', '--configfile',            dest='CommandlineConfigFile', action='store',       type="string", help='path to an alternate configfile', default=None)
		parser.add_option('-d', '--daemonize',             dest='Daemonize',             action='store_true',                 help='go into background and just use gui', default=None)
		parser.add_option('-l', '--lirc',                  dest='Lirc',                  action='store_true',                 help='enable infrared control via lirc', default=None)
		parser.add_option('-L', '--lircrc',                dest='LircrcPath',            action='store',       type="string", help='path to lircrc', default=None)
		parser.add_option('-C', '--clockstatefile',        dest='ClockStateFile',        action='store',       type="string", help='path to a clockstatefile', default=None)
		parser.add_option('-a', '--album-art-dir',         dest='AlbumArtDir',           action='store',       type="string", help='directory for Album-Art', default=None)
		parser.add_option('-A', '--album-art-from-amazon', dest='AlbumArtFromAmazon',    action='store_true',                 help='fetch Album-Art from Amazon', default=None)
		parser.add_option('-I', '--amazon-id',             dest='AmazonID',              action='store',       type="string", help=optparse.SUPPRESS_HELP, default=None)
		parser.add_option('-S', '--screensaverpath',       dest='ScreensaverPath',       action='store',       type="string", help='directory that contains images to be used for screensaver', default=None)
		parser.add_option('-T', '--screensavertimeout',    dest='ScreensaverTimeout',    action='store',       type="int",    help='timeout for screensaver (in seconds)', default=None)
		parser.add_option('-t', '--theme-dir',             dest='ThemeDir',              action='store',       type="string", help='theme directory', default=None)
		group1 = optparse.OptionGroup(parser, 
		"SDL honours the environment variable SDL_VIDEODRIVER to select a Video Driver. Possible Values for SDL_VIDEODRIVER on windows are",
		"     windib, directx ")
		parser.add_option_group(group1)
		group2 = optparse.OptionGroup(parser, 
		"Possible Values for SDL_VIDEODRIVER on Linux are",
		"     x11, dga, fbcon, directfb, ggi, vgl, svgalib, aalib")
		parser.add_option_group(group2)

		(options, args) = parser.parse_args()
		if len(args) != 0:
			parser.error("don't know what to do with additional arguments")

		if options.ConnectHost != None:
			self.ConnectHost = options.ConnectHost
		if options.ConnectPort != None:
			self.ConnectPort = options.ConnectPort
			try:
				assert self.ConnectPort >= 0 and self.ConnectPort <= 65535
			except:
				parser.error("invalid parameter for --connect-port")
		if options.ConnectPassword != None:
			self.ConnectPassword = options.ConnectPassword
		if options.VirtualKeyboard != None:
			self.VirtualKeyboard = options.VirtualKeyboard
		if options.Fullscreen != None:
			self.Fullscreen = options.Fullscreen
		if options.ScreenSize != None:
			try:
				self.ScreenWidth,self.ScreenHeight = map(int,options.ScreenSize.split("x"))
				assert self.ScreenWidth >= 320 and self.ScreenWidth < 4096
				assert self.ScreenHeight >= 200 and self.ScreenHeight < 4096
				self.ScreenSizeAuto = False
			except:
				parser.error("invalid parameter for --size")
		if options.CommandlineConfigFile != None:
			self.CommandlineConfigFile = options.CommandlineConfigFile
		if options.Daemonize != None:
			self.Daemonize = options.Daemonize
		if options.Lirc != None:
			self.Lirc = options.Lirc
		if options.LircrcPath != None:
			self.LircrcPath = options.LircrcPath
		if options.ClockStateFile != None:
			self.ClockStateFile = options.ClockStateFile
		if options.AlbumArtDir != None:
			#FIXME test if dir exists
			self.AlbumArtDir = options.AlbumArtDir
		if options.AlbumArtFromAmazon != None:
			self.AlbumArtFromAmazon = options.AlbumArtFromAmazon
		if options.AmazonID != None:
			self.AmazonID = options.AmazonID
		if options.ScreensaverPath != None:
			self.ScreensaverPath = options.ScreensaverPath
			if self.ScreensaverMode == "none":
				self.ScreensaverMode = "randombydir"
		if options.ScreensaverTimeout != None:
			self.ScreensaverTimeout = options.ScreensaverTimeout
			if self.ScreensaverMode == "none":
				self.ScreensaverMode = "randombydir"
			try:
				assert self.ScreensaverTimeout > 0 and self.ScreensaverTimeout <= 43200 # does it make sense to use a screensaver after more than 12 hours?
			except:
				parser.error("invalid parameter for --screensavertimeout")
		if options.ThemeDir != None:
			#FIXME test if dir exists
			self.ThemeDir = options.ThemeDir



	def ChangeTheme(self, Theme):
		self.Theme = Theme

	def RecalculateSizes(self):
		self.Sizes.Positions["PlayControlButton"] = self.Theme.PositionPlayControlButton
		self.Sizes.Positions["InfoArea"] = self.Theme.PositionInfoArea
		self.Sizes.Positions["MenuButton"] = self.Theme.PositionMenuButton
		self.Sizes.Positions["VirtualKeyboardButton"] = self.Theme.PositionVirtualKeyboardButton
		self.Sizes.Resize()

#==============================================================================
class AlarmClockConfig:
	def __init__(self, ConfigFile):
		self.logger = logging.getLogger('pympdtouchgui')

		# Defaults for AlarmClockOptions
		self.AlarmClockEnabled = {}
		self.AlarmClockTime = {}
		for day in xrange(0,7):
			self.AlarmClockEnabled[day] = False
			self.AlarmClockTime[day] = (7,01)

		self.ClockSwitchStyle = "hard"
		self.ClockSwitchDuration = 120

		self.SleepClockEnabled = False
		self.SleepClockTime = datetime.datetime.now() + datetime.timedelta(0,0,0,0,30) # 30 Minutes
		# timedelta is (days, seconds, microseconds, milliseconds, minutes, hours, weeks)

		self.ConfigFile = ConfigFile

		self.ConfigFileParse()

	def ConfigFileParse(self):
		conf = ConfigParser.ConfigParser()
		filename = os.path.realpath(os.path.expanduser(self.ConfigFile))
		isfile = os.path.isfile(filename)
		if isfile:
			self.logger.info("Using Configuration from %s"%filename)
			conf.read(filename)
			if conf.has_section("alarmclock"):
				if conf.has_option("alarmclock", "enabled"):
					self.AlarmClockEnabled = self.AlarmclockParseEnabled(conf.get("alarmclock", "enabled"))
				if conf.has_option("alarmclock", "time"):
					self.AlarmClockTime = self.AlarmclockParseTime(conf.get("alarmclock", "time"))
				if conf.has_option("alarmclock", "switchstyle"):
					self.ClockSwitchStyle = self.AlarmclockParseSwitchStyle(conf.get("alarmclock", "switchstyle"))
				if conf.has_option("alarmclock", "switchduration"):
					self.ClockSwitchDuration = conf.getint("alarmclock", "switchduration")

	def ConfigFileWrite(self):
		if self.ConfigFile:
			filename = os.path.expanduser(self.ConfigFile)
			if os.path.isfile(filename):
				conf = ConfigParser.ConfigParser()
				self.logger.info("Updating Configfile %s"%filename)
				conf.read(filename)
				if not conf.has_section("alarmclock"):
					conf.add_section("alarmclock")

				AlarmClockEnabled = []
				AlarmClockTime = []
				for day in xrange(0,7):
					AlarmClockEnabled.append(str(self.AlarmClockEnabled[day]))
					AlarmClockTime.append("%02d:%02d"%self.AlarmClockTime[day])

				textenabled = ",".join(AlarmClockEnabled)
				conf.set("alarmclock","enabled",textenabled)

				texttime = ','.join(AlarmClockTime)
				conf.set("alarmclock","time",texttime)

				try:
					f = open(filename,"w")
					conf.write(f)
					f.close()
				except:
					self.logger.warn("Could not write clockstate %s"%filename)

	def AlarmclockParseEnabled(self, string):
		parts = string.split(",")
		if not len(parts) == 7:
			self.logger.fatal("Time not parseable (Week is expected to have 7 Days, but got only %s sets of Data)"%len(parts))
			sys.exit(99)
		else:
			newparts = {}
			for i in xrange(0,7):
				newparts[i] = (parts[i].lower() == "true")
			return newparts

	def AlarmclockParseTime(self, string):
		parts = string.split(",")
		if not len(parts) == 7:
			self.logger.fatal("Time not parseable (Week is expected to have 7 Days, but got only %s sets of Data)"%len(parts))
			sys.exit(99)
		else:
			newparts = {}
			for i in xrange(0,7):
				parts2 = parts[i].split(":")
				if not len(parts2) == 2:
					self.logger.fatal("Time not parseable (expecting a hour:minute pair, but got a %s-tuple)"%len(parts2))
					sys.exit(99)
				else:
					newparts[i] = (int(parts2[0]),int(parts2[1]))
			return newparts

	def AlarmclockParseSwitchStyle(self, string):
		ClockSwitchStyles = ["hard", "linear"]
		if string not in ClockSwitchStyles:
			self.logger.fatal("Clockswitchstyle can be only 'hard' or 'linear', not '%s'."%string)
			sys.exit(99)
		return string

#==============================================================================
class Sizes:
	def __init__(self, ScreenSize):
		self.logger = logging.getLogger('pympdtouchgui')

		self.MenuButtonSize = 0

		self.MainAreaSize = (0,0)
		self.MainAreaPosition = (0,0)
		self.FontSizeStatus = 0
		self.FontSizeBrowse = 0
		self.FontSizePlaylist = 0
		self.FontSizeSearch = 0
		self.FontSizeKeyboardSearch = 0
		self.FontSizeKeyboardBrowse = 0
		self.FontSizeSearchResult = 0
		self.FontSizeVirtualKeyboard = 0
		self.FontSizeInfoArea = 0
		self.FontSizeAlarmClock = 0
		self.FontSizeSleepClock = 0

		self.MenuStartButtonPosition = (0,0)
		self.MenuStartButtonSize = (0,0)

		self.InfoAreaSize = (0,0)
		self.InfoAreaPosition = (0,0)
		self.FontSizeInfoArea = 0

		self.ButtonAreaSize = (0,0)
		self.ButtonAreaPosition = (0,0)

		self.KeyboardButtonSize = (0,0)
		self.KeyboardButtonPosition = (0,0)

		self.Positions={}
		self.Positions["PlayControlButton"] = ("Edge",("Bottom","Center"))
		self.Positions["InfoArea"] = ("Edge",("Top","Center"))
		self.Positions["MenuButton"] = ("Corner",("Bottom","Left"))
		self.Positions["VirtualKeyboardButton"] = ("Corner",("Bottom","Right"))

		self.ScreenSize = ScreenSize
		self.Resize()

	def Resize(self):
		self.MenuButtonSize = int(min(self.ScreenSize[0]/10, self.ScreenSize[1]/8))

		self.FontSizeStatus = int(self.MenuButtonSize/4*3)
		self.FontSizeBrowse = int(self.FontSizeStatus /3*2)
		self.FontSizePlaylist = int(self.FontSizeStatus /3*2)
		self.FontSizeSearch = self.FontSizeStatus
		self.FontSizeKeyboardSearch = self.FontSizeSearch
		self.FontSizeKeyboardBrowse = int(self.FontSizeKeyboardSearch /3 *2)
		self.FontSizeSearchResult = int(self.FontSizeStatus/3*2)
		self.FontSizeVirtualKeyboard = self.FontSizeStatus
		self.FontSizeInfoArea = int(self.FontSizeStatus/4*3)
		self.FontSizeAlarmClock = self.FontSizeStatus
		self.FontSizeSleepClock = self.FontSizeStatus

		#FIXME
		if not self.Positions.has_key("PlayControlButton"):
			pass
		if not self.Positions.has_key("InfoArea"):
			pass
		if not self.Positions.has_key("MenuButton"):
			pass
		if not self.Positions.has_key("VirtualKeyboardButton"):
			pass



		# Check if no Position is occupied more than once
		PositionEdgeOccupied={}
		PositionEdgeOccupied["Bottom"] = False
		PositionEdgeOccupied["Left"] = False
		PositionEdgeOccupied["Right"] = False
		PositionEdgeOccupied["Top"] = False
		PositionCornerOccupied={}
		PositionCornerOccupied["BottomLeft"] = False
		PositionCornerOccupied["TopLeft"] = False
		PositionCornerOccupied["BottomRight"] = False
		PositionCornerOccupied["TopRight"] = False

		for PositionKey in self.Positions:
			PositionEntry = self.Positions[PositionKey]
			if PositionEntry[0] == "Edge":
				if PositionEntry[1][0] in PositionEdgeOccupied.keys():
					if PositionEdgeOccupied[PositionEntry[1][0]]:
						self.logger.fatal("The %s Edge is used twice"%PositionEntry[1][0])
						sys.exit(99)
					else:
						PositionEdgeOccupied[PositionEntry[1][0]] = True
				else:
					self.logger.fatal("Position %s not known "%PositionEntry[1][0])
					sys.exit(99)
			elif PositionEntry[0] == "Corner":
				if PositionEntry[1][0]+PositionEntry[1][1] in PositionCornerOccupied.keys():
					if PositionCornerOccupied[PositionEntry[1][0]+PositionEntry[1][1]]:
						self.logger.fatal("The %s Corner is used twice")
						sys.exit(99)
					else:
						PositionCornerOccupied[PositionEntry[1][0]+PositionEntry[1][1]] = True
				elif PositionEntry[1][1]+PositionEntry[1][0] in PositionCornerOccupied.keys():
					if PositionCornerOccupied[PositionEntry[1][1]+PositionEntry[1][0]]:
						self.logger.fatal("The %s Corner is used twice")
						sys.exit(99)
					else:
						PositionCornerOccupied[PositionEntry[1][1]+PositionEntry[1][0]] = True
				else:
					self.logger.fatal("Position %s not known "%PositionEntry[1][0])
					sys.exit(99)
			else:
				self.logger.warn("PositionType %s not known"%PositionEntry[0])


		# Now calculate sizes
		if self.Positions["MenuButton"][0] == "Edge":
			self.logger.fatal("Placing Buttons on a Edge is notsupported")
			sys.exit(99)
		elif self.Positions["MenuButton"][0] == "Corner":
			if self.Positions["MenuButton"][1][0] == "Left" and self.Positions["MenuButton"][1][1] == "Top"\
				or self.Positions["MenuButton"][1][1] == "Left" and self.Positions["MenuButton"][1][0] == "Top":
				self.MenuStartButtonPosition = (0, 0)
			elif self.Positions["MenuButton"][1][0] == "Right" and self.Positions["MenuButton"][1][1] == "Top"\
				or self.Positions["MenuButton"][1][1] == "Right" and self.Positions["MenuButton"][1][0] == "Top":
				self.MenuStartButtonPosition = (self.ScreenSize[0] - self.MenuButtonSize, 0)
			elif self.Positions["MenuButton"][1][0] == "Left" and self.Positions["MenuButton"][1][1] == "Bottom"\
				or self.Positions["MenuButton"][1][1] == "Left" and self.Positions["MenuButton"][1][0] == "Bottom":
				self.MenuStartButtonPosition = (0, self.ScreenSize[1] - self.MenuButtonSize)
			elif self.Positions["MenuButton"][1][0] == "Right" and self.Positions["MenuButton"][1][1] == "Bottom"\
				or self.Positions["MenuButton"][1][1] == "Right" and self.Positions["MenuButton"][1][0] == "Bottom":
				self.MenuStartButtonPosition = (self.ScreenSize[0] - self.MenuButtonSize, self.ScreenSize[1] - self.MenuButtonSize)
		self.MenuStartButtonSize = (self.MenuButtonSize,self.MenuButtonSize)

		if self.Positions["PlayControlButton"][0] == "Edge":
			if self.Positions["PlayControlButton"][1][0] == "Bottom":
				if PositionCornerOccupied["BottomLeft"] or PositionCornerOccupied["BottomRight"]:
					self.ButtonAreaSize = (self.ScreenSize[0] - self.MenuButtonSize * 2, self.MenuButtonSize)
					self.ButtonAreaPosition = (self.MenuButtonSize, self.ScreenSize[1]-self.MenuButtonSize)
				else:
					self.ButtonAreaSize = (self.ScreenSize[0], self.MenuButtonSize)
					self.ButtonAreaPosition = (0, self.ScreenSize[1]-self.MenuButtonSize)
			elif self.Positions["PlayControlButton"][1][0] == "Top":
				if PositionCornerOccupied["TopLeft"] or PositionCornerOccupied["TopRight"]:
					self.ButtonAreaSize = (self.ScreenSize[0] - self.MenuButtonSize * 2, self.MenuButtonSize)
					self.ButtonAreaPosition = (self.MenuButtonSize,0)
				else:
					self.ButtonAreaSize = (self.ScreenSize[0], self.MenuButtonSize)
					self.ButtonAreaPosition = (0,0)
			elif self.Positions["PlayControlButton"][1][0] == "Right":
				if PositionCornerOccupied["BottomRight"] or PositionCornerOccupied["TopRight"]:
					self.ButtonAreaSize = (self.MenuButtonSize, self.ScreenSize[1] - self.MenuButtonSize * 2)
					self.ButtonAreaPosition = (self.ScreenSize[0] - self.MenuButtonSize,self.MenuButtonSize)
				else:
					self.ButtonAreaSize = (self.MenuButtonSize, self.ScreenSize[1])
					self.ButtonAreaPosition = (self.ScreenSize[0] - self.MenuButtonSize,0)
			elif self.Positions["PlayControlButton"][1][0] == "Left":
				if PositionCornerOccupied["BottomLeft"] or PositionCornerOccupied["TopLeft"]:
					self.ButtonAreaSize = (self.MenuButtonSize, self.ScreenSize[1] - self.MenuButtonSize * 2)
					self.ButtonAreaPosition = (0,self.MenuButtonSize)
				else:
					self.ButtonAreaSize = (self.MenuButtonSize, self.ScreenSize[1])
					self.ButtonAreaPosition = (0,0)
			else:
				pass #ERROR!
		elif self.Positions["PlayControlButton"][0] == "Corner":
			self.logger.fatal("The PlayControlbuttons are too many to be placed in a corner")
			sys.exit(99)

		if self.Positions["InfoArea"][0] == "Edge":
			if self.Positions["InfoArea"][1][0] == "Bottom":
				if PositionCornerOccupied["BottomLeft"] or PositionCornerOccupied["BottomRight"]:
					self.InfoAreaSize = (self.ScreenSize[0] - self.MenuButtonSize * 2, self.MenuButtonSize)
					self.InfoAreaPosition = (self.MenuButtonSize, self.ScreenSize[1])
				else:
					self.InfoAreaSize = (self.ScreenSize[0], self.MenuButtonSize)
					self.InfoAreaPosition = (0, self.ScreenSize[1])
			elif self.Positions["InfoArea"][1][0] == "Top":
				if PositionCornerOccupied["TopLeft"] or PositionCornerOccupied["TopRight"]:
					self.InfoAreaSize = (self.ScreenSize[0] - self.MenuButtonSize * 2, self.MenuButtonSize)
					self.InfoAreaPosition = (self.MenuButtonSize,0)
				else:
					self.InfoAreaSize = (self.ScreenSize[0], self.MenuButtonSize)
					self.InfoAreaPosition = (0,0)
			elif self.Positions["InfoArea"][1][0] == "Right":
				if PositionCornerOccupied["BottomRight"] or PositionCornerOccupied["TopRight"]:
					self.InfoAreaSize = (self.MenuButtonSize, self.ScreenSize[1] - self.MenuButtonSize * 2)
					self.InfoAreaPosition = (self.ScreenSize[0] - self.MenuButtonSize,self.MenuButtonSize)
				else:
					self.InfoAreaSize = (self.MenuButtonSize, self.ScreenSize[1])
					self.InfoAreaPosition = (self.ScreenSize[0] - self.MenuButtonSize,0)
			elif self.Positions["InfoArea"][1][0] == "Left":
				if PositionCornerOccupied["BottomLeft"] or PositionCornerOccupied["TopLeft"]:
					self.InfoAreaSize = (self.MenuButtonSize, self.ScreenSize[1] - self.MenuButtonSize * 2)
					self.InfoAreaPosition = (0,self.MenuButtonSize)
				else:
					self.InfoAreaSize = (self.MenuButtonSize, self.ScreenSize[1])
					self.InfoAreaPosition = (0,0)
			else:
				pass #ERROR!
		elif self.Positions["InfoArea"][0] == "Corner":
			self.logger.fatal("The InfoArea is too large to be placed in a corner")
			sys.exit(99)

		if self.Positions["VirtualKeyboardButton"][0] == "Edge":
			self.logger.fatal("Placing Buttons on a Edge is notsupported")
			sys.exit(99)
		elif self.Positions["VirtualKeyboardButton"][0] == "Corner":
			if self.Positions["VirtualKeyboardButton"][1][0] == "Left" and self.Positions["VirtualKeyboardButton"][1][1] == "Top"\
				or self.Positions["VirtualKeyboardButton"][1][1] == "Left" and self.Positions["VirtualKeyboardButton"][1][0] == "Top":
				self.KeyboardButtonPosition = (0, 0)
			elif self.Positions["VirtualKeyboardButton"][1][0] == "Right" and self.Positions["VirtualKeyboardButton"][1][1] == "Top"\
				or self.Positions["VirtualKeyboardButton"][1][1] == "Right" and self.Positions["VirtualKeyboardButton"][1][0] == "Top":
				self.KeyboardButtonPosition = (self.ScreenSize[0] - self.MenuButtonSize, 0)
			elif self.Positions["VirtualKeyboardButton"][1][0] == "Left" and self.Positions["VirtualKeyboardButton"][1][1] == "Bottom"\
				or self.Positions["VirtualKeyboardButton"][1][1] == "Left" and self.Positions["VirtualKeyboardButton"][1][0] == "Bottom":
				self.KeyboardButtonPosition = (0, self.ScreenSize[1] - self.MenuButtonSize)
			elif self.Positions["VirtualKeyboardButton"][1][0] == "Right" and self.Positions["VirtualKeyboardButton"][1][1] == "Bottom"\
				or self.Positions["VirtualKeyboardButton"][1][1] == "Right" and self.Positions["VirtualKeyboardButton"][1][0] == "Bottom":
				self.KeyboardButtonPosition = (self.ScreenSize[0] - self.MenuButtonSize, self.ScreenSize[1] - self.MenuButtonSize)
			self.KeyboardButtonSize = (self.MenuButtonSize,self.MenuButtonSize)

		# Heuristics for single Buttons in Corners
		if PositionCornerOccupied["TopRight"] and ((not PositionEdgeOccupied["Top"]) and (not PositionEdgeOccupied["Right"])):
			if PositionEdgeOccupied["Bottom"]:
				PositionEdgeOccupied["Top"] = True
			else:
				PositionEdgeOccupied["Right"] = True
		if PositionCornerOccupied["TopLeft"] and ((not PositionEdgeOccupied["Top"]) and (not PositionEdgeOccupied["Left"])):
			if PositionEdgeOccupied["Bottom"]:
				PositionEdgeOccupied["Top"] = True
			else:
				PositionEdgeOccupied["Left"] = True
		if PositionCornerOccupied["BottomRight"] and ((not PositionEdgeOccupied["Bottom"]) and (not PositionEdgeOccupied["Right"])):
			if PositionEdgeOccupied["Top"]:
				PositionEdgeOccupied["Bottom"] = True
			else:
				PositionEdgeOccupied["Right"] = True
		if PositionCornerOccupied["BottomLeft"] and ((not PositionEdgeOccupied["Bottom"]) and (not PositionEdgeOccupied["Left"])):
			if PositionEdgeOccupied["Top"]:
				PositionEdgeOccupied["Bottom"] = True
			else:
				PositionEdgeOccupied["Left"] = True

		self.MainAreaSize = (self.ScreenSize[0], self.ScreenSize[1])
		self.MainAreaPosition = (0,0)
		if PositionEdgeOccupied["Left"]:
			self.MainAreaSize = (self.MainAreaSize[0] - self.MenuButtonSize,self.MainAreaSize[1])
			self.MainAreaPosition = (self.MainAreaPosition[0] + self.MenuButtonSize,self.MainAreaPosition[1])
		if PositionEdgeOccupied["Right"]:
			self.MainAreaSize = (self.MainAreaSize[0] - self.MenuButtonSize,self.MainAreaSize[1])
		if PositionEdgeOccupied["Top"]:
			self.MainAreaSize = (self.MainAreaSize[0],self.MainAreaSize[1] - self.MenuButtonSize)
			self.MainAreaPosition = (self.MainAreaPosition[0],self.MainAreaPosition[1] + self.MenuButtonSize)
		if PositionEdgeOccupied["Bottom"]:
			self.MainAreaSize = (self.MainAreaSize[0],self.MainAreaSize[1] - self.MenuButtonSize)

#==============================================================================
class Theme:
	def __init__(self):
		self.logger = logging.getLogger('pympdtouchgui')

		self.ColorBackground = (0,0,0)
		# Status
		self.ColorForegroundStatus = (255,255,255)
		# Info
		self.ColorForegroundInfo = (255,255,255)
		# Menu
		self.ColorForegroundMenu = (255,255,255)
		self.ColorForegroundButtons = (255,255,255)
		# Browse
		self.ColorForegroundBrowseText = (255,255,255)
		self.ColorBackgroundBrowseCursorLine = (255,0,0)
		self.ColorForegroundBrowseCursorLine = (255,255,255)
		self.ColorBackgroundBrowseSelectLine = (255,0,0)
		self.ColorForegroundBrowseSelectLine = (255,255,255)
		# Search
		self.ColorForegroundSearchText = (255,255,255)
		# Playlist
		self.ColorBackgroundPlaylistHighlightLine = (255,0,0)
		self.ColorForegroundPlaylistHighlightLine = (255,255,255)
		self.ColorBackgroundPlaylistCursorLine = (255,0,0)
		self.ColorForegroundPlaylistCursorLine = (255,255,255)
		self.ColorForegroundPlaylistText = (255,255,255)
		# Scroll
		self.ColorForegroundScrollLines = (255,255,255)
		self.ColorForegroundScrollMiddleSlider = (255,255,255)
		self.ColorForegroundScrollFirstLastSlider = (0,0,0)
		# VirtualKeyboard
		self.ColorBackgroundVirtualKeyboardSelect = (255,0,0)
		self.ColorForegroundVirtualKeyboardSelect = (255,255,255)
		self.ColorForegroundVirtualKeyboardText = (255,255,255)

		# Positions
		self.PositionPlayControlButton = ("Edge",("Bottom","Center"))
		self.PositionInfoArea = ("Edge",("Top","Center"))
		self.PositionMenuButton = ("Corner",("Bottom","Left"))
		self.PositionVirtualKeyboardButton = ("Corner",("Bottom","Right"))

	def LoadTheme(self, ThemeDir):
		ColorSectionName="Colors"
		PositionSectionName="Position"
		conf = ConfigParser.ConfigParser()
		ThemeConf = os.path.join(ThemeDir,"themeconfig")
		if os.path.isfile(ThemeConf):
			self.logger.info("Using Theme from %s"%ThemeConf)
			conf.read(ThemeConf)
			if conf.has_option(ColorSectionName, "Background"):
				self.ColorBackground = self.ParseColor(conf.get(ColorSectionName, "Background"))
			# Status
			if conf.has_option(ColorSectionName, "ForegroundStatus"):
				self.ColorForegroundStatus = self.ParseColor(conf.get(ColorSectionName, "ForegroundStatus"))
			# Info
			if conf.has_option(ColorSectionName, "ForegroundInfo"):
				self.ColorForegroundInfo = self.ParseColor(conf.get(ColorSectionName, "ForegroundInfo"))
			# Menu
			if conf.has_option(ColorSectionName, "ForegroundMenu"):
				self.ColorForegroundMenu = self.ParseColor(conf.get(ColorSectionName, "ForegroundMenu"))
			if conf.has_option(ColorSectionName, "ForegroundButtons"):
				self.ColorForegroundButtons = self.ParseColor(conf.get(ColorSectionName, "ForegroundButtons"))
			# Browse
			if conf.has_option(ColorSectionName, "ForegroundBrowseText"):
				self.ColorForegroundBrowseText = self.ParseColor(conf.get(ColorSectionName, "ForegroundBrowseText"))
			if conf.has_option(ColorSectionName, "BackgroundBrowseCursorLine"):
				self.ColorBackgroundBrowseCursorLine = self.ParseColor(conf.get(ColorSectionName, "BackgroundBrowseCursorLine"))
			if conf.has_option(ColorSectionName, "ForegroundBrowseCursorLine"):
				self.ColorForegroundBrowseCursorLine = self.ParseColor(conf.get(ColorSectionName, "ForegroundBrowseCursorLine"))
			# Search
			if conf.has_option(ColorSectionName, "ForegroundSearchText"):
				self.ColorForegroundSearchText = self.ParseColor(conf.get(ColorSectionName, "ForegroundSearchText"))
			# Playlist
			if conf.has_option(ColorSectionName, "BackgroundPlaylistHighlightLine"):
				self.ColorBackgroundPlaylistHighlightLine = self.ParseColor(conf.get(ColorSectionName, "BackgroundPlaylistHighlightLine"))
			if conf.has_option(ColorSectionName, "ForegroundPlaylistHighlightLine"):
				self.ColorForegroundPlaylistHighlightLine = self.ParseColor(conf.get(ColorSectionName, "ForegroundPlaylistHighlightLine"))
			if conf.has_option(ColorSectionName, "BackgroundPlaylistCursorLine"):
				self.ColorBackgroundPlaylistCursorLine = self.ParseColor(conf.get(ColorSectionName, "BackgroundPlaylistCursorLine"))
			if conf.has_option(ColorSectionName, "ForegroundPlaylistCursorLine"):
				self.ColorForegroundPlaylistCursorLine = self.ParseColor(conf.get(ColorSectionName, "ForegroundPlaylistCursorLine"))
			if conf.has_option(ColorSectionName, "ForegroundPlaylistText"):
				self.ColorForegroundPlaylistText = self.ParseColor(conf.get(ColorSectionName, "ForegroundPlaylistText"))
			# Scroll
			if conf.has_option(ColorSectionName, "ForegroundScrollLines"):
				self.ColorForegroundScrollLines = self.ParseColor(conf.get(ColorSectionName, "ForegroundScrollLines"))
			if conf.has_option(ColorSectionName, "ForegroundScrollMiddleSlider"):
				self.ColorForegroundScrollMiddleSlider = self.ParseColor(conf.get(ColorSectionName, "ForegroundScrollMiddleSlider"))
			if conf.has_option(ColorSectionName, "ForegroundScrollFirstLastSlider"):
				self.ColorForegroundScrollFirstLastSlider = self.ParseColor(conf.get(ColorSectionName, "ForegroundScrollFirstLastSlider"))
			# VirtualKeyboard
			if conf.has_option(ColorSectionName, "BackgroundVirtualKeyboardSelect"):
				self.ColorBackgroundVirtualKeyboardSelect = self.ParseColor(conf.get(ColorSectionName, "BackgroundVirtualKeyboardSelect"))
			if conf.has_option(ColorSectionName, "ForegroundVirtualKeyboardSelect"):
				self.ColorForegroundVirtualKeyboardSelect = self.ParseColor(conf.get(ColorSectionName, "ForegroundVirtualKeyboardSelect"))
			if conf.has_option(ColorSectionName, "ForegroundVirtualKeyboardText"):
				self.ColorForegroundVirtualKeyboardText = self.ParseColor(conf.get(ColorSectionName, "ForegroundVirtualKeyboardText"))

			# Positions
			if conf.has_option(PositionSectionName, "PlayControlButtons"):
				self.PositionPlayControlButton = self.ParsePosition(conf.get(PositionSectionName, "PlayControlButtons"))
			if conf.has_option(PositionSectionName, "InfoArea"):
				self.PositionInfoArea = self.ParsePosition(conf.get(PositionSectionName, "InfoArea"))
			if conf.has_option(PositionSectionName, "MenuButton"):
				self.PositionMenuButton = self.ParsePosition(conf.get(PositionSectionName, "MenuButton"))
			if conf.has_option(PositionSectionName, "VirtualKeyboardButton"):
				self.PositionVirtualKeyboardButton = self.ParsePosition(conf.get(PositionSectionName, "VirtualKeyboardButton"))

	def ParseColor(self, ColorString):
		# expecting a colortriple like "(123,123,123)"
		if ColorString[0]=="(" and ColorString[-1]==")":
			rgb = ColorString[1:-1].split(",")
			if len(rgb) == 3:
				return (int(rgb[0]),int(rgb[1]),int(rgb[2]))
			else:
				self.logger.fatal("In ThemeConfigfile: Colorvalue is supposed to be a comma separated RGB Triple like `(123,123,123)' but was a %s-Tuple `%s'"%(len(rgb),ColorString))
				sys.exit(123)
		else:
			self.logger.fatal("In ThemeConfigfile: Colorvalue is supposed to be a RGB Triple in round brackets, but at least one bracket is missing in `%s'"%ColorString)
			sys.exit(123)

	def ParsePosition(self, PostionString):
		# expecting something like "Edge,Bottom,Center"
		PositionArray = PostionString.split(",")
		if len(PositionArray) == 3:
			if PositionArray[0] in ["Edge","Corner"]:
				PositionType = PositionArray[0]
				if PositionArray[1] in ["Top","Bottom", "Left","Right"]:
					PositionPrimary = PositionArray[1]
					if PositionArray[0] == "Corner":
						if PositionArray[2] in ["Top","Bottom", "Left","Right"]:
							PositionSecondary = PositionArray[2]
							return (PositionType,(PositionPrimary,PositionSecondary))
						else:
							self.logger.fatal("Position in ThemeConfigfile is supposed to be a comma separated triple with a Position (Top, Bottom, Left or Right) at the third place. Found `%s'"%PositionArray[2])
							sys.exit(123)
					elif PositionArray[0] == "Edge":
						if PositionArray[2] in ["Top","Bottom", "Left","Right","Center","Middle"]:
							PositionSecondary = PositionArray[2]
							return (PositionType,(PositionPrimary,PositionSecondary))
						else:
							self.logger.fatal("Position in ThemeConfigfile is supposed to be a comma separated triple with a Position (Top, Bottom, Left, Right, Center or Middle) at the third place. Found `%s'"%PositionArray[2])
							sys.exit(123)
					else:
						# Not possible due to earlier checks, error anyway
						self.logger.fatal("This Error should have been caught earlier.")
						sys.exit(123)
				else:
					self.logger.fatal("Position in ThemeConfigfile is supposed to be a comma separated triple with a Position (Top, Bottom, Left or Right) at the second place. Found `%s'"%PositionArray[1])
					sys.exit(123)
			else:
				self.logger.fatal("Position in ThemeConfigfile is supposed to be a comma separated triple with a Position Type (Edge or Corner) at the first place. Found `%s'"%PositionArray[0])
				sys.exit(123)
		else:
			self.logger.fatal("Position in ThemeConfigfile is supposed to be a comma separated triple. Found `%s'"%PostionString)
			sys.exit(123)

#==============================================================================
def videoerror():
	logger = logging.getLogger('pympdtouchgui')
	logger.fatal("Couldn't initialize Video")
	logger.fatal("Either you specified a wrong SDL_VIDEODRIVER in your environment,")
	logger.fatal("or SDL doesn't support the specified SDL_VIDEODRIVER")
	logger.fatal("Possible Values for SDL_VIDEODRIVER on windows are")
	logger.fatal("     windib, directx")
	logger.fatal("Possible Values for SDL_VIDEODRIVER on Linux are")
	logger.fatal("     x11, dga, fbcon, directfb, ggi, vgl, svgalib, aalib")
	sys.exit(1)

def daemonize(user=None, group=None):
	logger = logging.getLogger('pympdtouchgui')
	uid=None
	gid=None

	if AllowDaemonize:
		logger.info("Going into background")
		if user != None:
			try:
				uid=pwd.getpwnam(user)[2]
			except KeyError:
				logger.warn("Couldn't find out uid for user '%s'"%user)
		if group != None:
			try:
				gid=grp.getgrnam(group)[2]
			except KeyError:
				logger.warn("Couldn't find out gid for group '%s'"%group)
			logger.info("Lowering user to %s (%s) and group %s (%s)"%(user,uid,group,gid))

		try:
			pid = os.fork()
			if pid != 0:
				os._exit(0)

			else:
				os.setsid()
				pid = os.fork()
				if pid != 0:
					os._exit(0)
				else:
					os.umask(UMASK)
					os.chdir(WORKDIR)

					maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
					if maxfd == resource.RLIM_INFINITY:
						maxfd = MAXFD

					for fd in range(0, maxfd):
						try:
							os.ttyname(fd) # close TTYs
						except:
							continue

						try:
							os.close(fd)
						except OSError:
							pass

					os.open(NULL_DEVICE, os.O_RDWR)
					os.dup2(0, 1)
					os.dup2(0, 2)
					if gid != None:
						try:
							os.setgid(gid)
						except OSError, (errno, error):
							logger.warn("can't setgid(%d): %s"%(gid, error))
					if uid != None:
						try:
							os.setuid(uid)
						except OSError, (errno, error):
							logger.warn("can't setuid(%d): %s"%(uid, error))

					logger.info("Running in background as pid %s"%os.getpid())
		except OSError, e:
			logger.error("Error during daemonizing: %s" %e.strerror)
			sys.exit(123)
	else:
		logger.warn("not going into background")



def main(argv):
	print "PyMPDTouchGUI %s, Copyright (C) 2007-2009 Timo Boettcher"%VERSION
	print "PyMPDTouchGUI comes with ABSOLUTELY NO WARRANTY."
	print "This is free software, and you are welcome to redistribute it"
	print "under certain conditions; see shipped license (GPL2) for details."
	print ""

	logger = logging.getLogger('pympdtouchgui')
	logger.setLevel(logging.INFO)

	ch = logging.StreamHandler(sys.stdout)
	ch.setLevel(logging.INFO)
	chformatter = logging.Formatter('%(message)s', '%T')
	ch.setFormatter(chformatter)
	logger.addHandler(ch)

	# Read Config and Theme
	MyConfig = Config(["/etc/pympdtouchguirc","~/.pympdtouchgui/config"],argv)
	MyConfig.PyLircFound = PyLircFound
	MyAlarmClockConfig = AlarmClockConfig(MyConfig.ClockStateFile)
	MyConfig.AlarmClock = MyAlarmClockConfig
	MyTheme = Theme()
	MyTheme.LoadTheme(MyConfig.ThemeDir)
	MyConfig.ChangeTheme(MyTheme)


	if MyConfig.Logfile:
		logdir = os.path.dirname(MyConfig.Logfile)
		if os.path.exists(logdir):
			try:
				fh = logging.FileHandler(MyConfig.Logfile)
			except IOError, e:
				if e.__str__().find("Permission denied"):
					logger.fatal("Permission denied on writing into logfile %s"%MyConfig.Logfile)
					sys.exit(123)
				else:
					logger.fatal(e)
					sys.exit(123)
			fh.setLevel(logging.DEBUG)
			fhformatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%T')
			fh.setFormatter(fhformatter)
			logger.addHandler(fh)
			logger.info("Startup, config read done")
			logger.info("Logging into file %s"%MyConfig.Logfile)
		else:
			logger.fatal("Directory for logging (%s) does not exist"%logdir)
			sys.exit(123)

	evManager = EventManager()

	# Find a working Screenresolution and activate it
	MyDisplay = DisplayView(evManager, MyConfig)
	if not MyDisplay.VideoInitialized():
		videoerror()
	# Calculate sizes for Widgets in current Screenresolution
	MyConfig.RecalculateSizes()
	# Create Widgets
	MyDisplay.CreateWidgets()

	input = Input(evManager, MyConfig)
	if MyConfig.Lirc:
		if MyConfig.PyLircFound:
			logger.info("Infrared support enabled")
			infrared = Infrared(evManager, MyConfig)
		else:
			logger.warn("Infrared support requested but disabled, pylirc not found")

	serverConnection = ServerConnection(evManager, MyConfig, MyDisplay.display.Update, input.GetInput)
	textLog = TextLog(evManager, MyConfig)

	myClockmananger = ClockManager(evManager, MyConfig)
	Powermananger = PowerManager(evManager, MyConfig)

	if MyConfig.Daemonize:
		logger.removeHandler(ch)
		daemonize(user=MyConfig.LowerToUser, group=MyConfig.LowerToGroup)

	serverConnection.connect()
	sys.exit(0)


if __name__=="__main__":
	main(sys.argv[1:])

