from Screens.Screen import Screen
from API import api
from Components.ActionMap import ActionMap
from Components.config import config
from Components.Harddisk import BlockDevice, harddiskmanager
from Components.Label import Label
from Components.MenuList import MenuList
from Components.Sources.List import List
from Screens.Console import Console
from Screens.MessageBox import MessageBox
from Screens.TextBox import TextBox
from Tools.Directories import fileExists, pathExists, resolveFilename, SCOPE_CONFIG, SCOPE_PLUGINS, SCOPE_SKIN, SCOPE_SYSETC
from Tools.LoadPixmap import LoadPixmap
from enigma import eConsoleAppContainer, eDVBDB, eEnv

from SatLodgeDownloader import SatLodgeDownloader, STATUS_ABORTED, STATUS_DONE, STATUS_FAILED
from SatLodgeManualInstall import SatLodgeManualInstall

from os import listdir, mkdir, path as os_path, rename, statvfs, system
from shutil import rmtree
import xml.etree.cElementTree as ET

def getTextFromFile(name = "about.txt", scope = SCOPE_PLUGINS):
	text = ""
	filename = resolveFilename(scope, name)
	if fileExists(filename):
		file = open(filename, "r")
		for line in file:
			text += line
		file.close()
	return text

satlodgedownloadAboutText = getTextFromFile("SatLodge/SatLodgeDownload/about.txt", SCOPE_PLUGINS)

def getXMLString():
	string = ""
	try:
		file = open(resolveFilename(SCOPE_SYSETC, "satlodge-version"), "r")

#"addons=http://webplus.sat-lodge.it/index.php?dir=/addons_OE25.xml" >> ${S}satlodge-version        
        
		lines = file.readlines()
		for x in lines:
			splitted = x.split("=")
			if splitted[0] == "addons":
				string = splitted[1].strip("\n")
				break
		file.close()
		return string
	except IOError:
		return string

XML_URL = getXMLString()

MODEL_MAP = {"dm520"  : "DM520 HD",
			 "dm525"  : "DM525 HD",
			 "dm820"  : "DM820 HD",
			 "dm900"  : "DM900 UltraHD",
			 "dm920"  : "DM920 UltraHD",
			 "dm7080" : "DM7080 HD"
			}

TYPE_CATEGORY = 0
TYPE_FILE = 1

CATEGORY_PLUGINS = "plugins"
CATEGORY_SETTINGS = "settings"
CATEGORY_PICON = "picon"
CATEGORY_SOFTCAM = "cam"

MB_MSG_INSTALLADDONQUESTION = _("Do you want install the addon:\n%s?")
MB_MSG_INSTALLPICONSQUESTION = _("Do you want install the picons:\n%s?")
MB_MSG_INSTALLSETTINGSQUESTION = _("Do you want install the settings:\n%s?")
MB_MSG_ABORT = _("Installation of:\n%s\naborted!")
MB_MSG_ADDONNOTFOUND = _("Addon:\n%s\nnot found!")
MB_MSG_WRONGFILEEXTENSION = _("Wrong file extension.\nPlease contact Sat-Lodge Team at http://www.Sat-Lodge.it/")
MB_MSG_FAILED = _("Addon:\n%s\ninstallation failed!")
MB_MSG_COMPLETED = _("Installation of addon:\n%s\ncompleted")

MSG_DOWNLOADINGADDON = _("Downloading addon:\n%s\nPlease wait...")
MSG_INSTALLINGADDON = _("Installing addon:\n%s\nPlease wait...")
MSG_INSTALLINGPICONS = _("Installing picons:\n%s\nPlease wait...")
MSG_INSTALLINGSETTINGS = _("Installing settings:\n%s\nPlease wait...")
MSG_ABORT = _("Installation of:\n%s\naborted!\nPress OK if you want to try again")
MSG_ADDONNOTFOUND = _("Addon:\n%s\nnot found!\nPress OK if you want to try again")
MSG_CONTACTSUPPORT = _("Wrong file extension.\nPlease contact Sat-Lodge Team\n\nhttp://www.Sat-Lodge.it/")
MSG_FAILED = _("Addon:\n%s\ninstallation failed!")
MSG_INSTALLEDSUCCESS = _("Addon:\n%s\ninstalled successfully")

INCLUDE_MAP = {"arm"	: ("dm900", "dm920",),
			   "mipsel"	: ("dm520", "dm525", "dm820", "dm7080"),
			   "all"	: ("dm520", "dm525", "dm820", "dm900", "dm920", "dm7080")
			}

PICONSPATH_DEFAULT = eEnv.resolve("${datadir}/enigma2")
SETTINGSPATH_DEFAULT = eEnv.resolve("${sysconfdir}/enigma2")
SETTINGSBACKUP_FOLDER = SETTINGSPATH_DEFAULT + "/settingsback/"

class SatLodgeDownload(Screen):
	skin="""
	<screen name="Sat-LodgeDownload" position="center,center" size="948,582">
		<widget name="key_yellow" position="620,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
		<ePixmap name="yellow" position="620,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
		<widget name="key_red" position="780,500" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
		<ePixmap name="red" position="780,500" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
		<widget source="addonslist" render="Listbox" position="14,49" size="900,480" scrollbarMode="showOnDemand">
			<convert type="TemplatedMultiContent">
				{"template": [
					MultiContentEntryText(pos = (60, 0), size = (520, 25), font=0,color=0xCC0000, flags = RT_HALIGN_LEFT|RT_VALIGN_TOP, text = 0), # index 0 is the title
					MultiContentEntryText(pos = (60, 20), size = (520, 25), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_BOTTOM, text = 1), # index 1 is the comment
					MultiContentEntryText(pos = (750, 0), size = (120, 25), font=1, flags = RT_HALIGN_RIGHT|RT_VALIGN_BOTTOM, text = 2), # index 2 is the date
					MultiContentEntryText(pos = (750, 20), size = (120, 25), font=1, flags = RT_HALIGN_RIGHT|RT_VALIGN_BOTTOM, text = 3), # index 3 is the size
					],
				"fonts": [gFont("Regular", 20),gFont("Regular", 16)],
				"itemHeight": 50
				}
			</convert>
		</widget>
		<widget name="introduction" position="0,500" size="600,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" />
	</screen> """

	VERSION = "2.0"

	def __init__(self, session):
		Screen.__init__(self, session)
		self.modelname = api.enigma2.systeminfo.modelname()
		self["introduction"] = Label(_("Wait please..."))
		self["actions"] = ActionMap(["ColorActions", "InfobarEPGActions", "OkCancelActions"],
		{
			"ok": self.ok,
			"red": self.exit,
			"yellow": self.callManualInstall,
			"cancel": self.exit,
			"showEventInfo": self.handleInfo
		}, -1)
		self["key_red"] = Label(_("Close"))
		self["key_yellow"] = Label(_("Manual install"))

		self.container = eConsoleAppContainer()
		self.container_conn = self.container.appClosed.connect(self.runFinished)

		self["addonslist"] = List()
		self.nodeList = []
		self.currentNode = None
		self.indexList = []
		self.selectedCategory = ""
		self.selectedItem = None
		self.downloadName = ""
		self.fileName = ""
		self.piconsPath = ""
		self.png_category = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN, "extensions/directory.png"))
		self.png_file = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN, "extensions/picture.png"))

		self["addonslist"].onSelectionChanged.append(self.__selectionChanged)
		self.onLayoutFinish.append(self.layoutFinished)

	def __selectionChanged(self):
		if self["addonslist"].list:
			item = self["addonslist"].getCurrent()
			type = item[7]
			if type == TYPE_CATEGORY:
				self["introduction"].setText(_("Select a category"))
			elif type == TYPE_FILE:
				self["introduction"].setText(_("Select an addon to download"))
			else:
				self["introduction"].setText(_("Addons type unknown!"))

	def layoutFinished(self):
		title = _("Sat-Lodge download panel V%s - %s") % (self.VERSION, MODEL_MAP.get(self.modelname, self.modelname.upper()))
		self.setTitle(title)
		print "[Sat-LodgeDownload] Url XML:", XML_URL
		cmd = "wget %s -O /tmp/addons.xml" % XML_URL
		self.container.execute(cmd)

	def runFinished(self, retval):
		if fileExists("/tmp/addons.xml"):
			self.currentNode = self.getMdom("/tmp/addons.xml")
			if self.currentNode:
				list = self.getList(self.currentNode)
				if list:
					self.fillMenu(list)
				else:
					self["introduction"].setText(_("File xml is empty or not correctly formatted!"))
		else:
			self["introduction"].setText(_("Server not found!\nPlease check internet connection..."))

	def getMdom(self, filename):
		try:
			mdom = ET.parse(filename).getroot()
			assert mdom.tag == "Addons", "root element in addons xml must be 'Addons'!"
		except:
			mdom = None
			self["introduction"].setText(_("File xml is not correctly formatted!"))
		return mdom

	def getList(self, parent):
		list = [ ]
		count = 0
		for x in parent:
			item_list = [ ]
			if x.tag == "menu":
				type = TYPE_CATEGORY
				node = x
				png = self.png_category
				count += 1
			elif x.tag == "item":
				type = TYPE_FILE
				node = None
				png = self.png_file
				count += 1
			else:
				print "[Sat-LodgeDownload] Node undefined!"
				count = 0
			if count:
				include = x.get("include", "")
				if include and include in INCLUDE_MAP:
					print "[Sat-LodgeDownload] Tag include is in map"
					if self.modelname in INCLUDE_MAP[include]:
						print "[Sat-LodgeDownload] Include match modelname, item added"
					else:
						print "[Sat-LodgeDownload] Include DON'T match modelname, item discarded"
						continue
				name = x.get("name", "Name??")
				category = x.get("category", "")
				description = x.get("description", "Description??")
				directory = x.get("directory", "")
				file = x.get("file", "")
				size = x.get("size", "")
				date = x.get("date", "")
				pformat = x.get("piconformat", "")
				pfolder = x.get("piconfolder", "")
				print "[Sat-LodgeDownload] Found node:", str(type), category, name, description, directory, file, size, date
				item_list = [name, # 0
							 description, # 1
							 date, # 2
							 size, # 3
							 category, # 4
							 directory, # 5
							 file, # 6
							 type, # 7
							 node, # 8
							 png, # 9
							 (pformat, pfolder) # 10
							]
				list.append(item_list)
		return list

	def fillMenu(self, list, index=0):
		addonslist = [ ]
		for entry in list:
			size = entry[3]
			if size:
				entry[3] = size + " KB"
			addonslist.append(entry)
		self["addonslist"].setList(addonslist)
		if index:
			self["addonslist"].setCurrentIndex(index)
		if self.nodeList:
			self["key_red"].setText(_("Back"))
		else:
			self["key_red"].setText(_("Close"))

	def ok(self):
		if self["addonslist"].list:
			item = self["addonslist"].getCurrent()
			type = item[7]
			if type == TYPE_CATEGORY:
				print "[Sat-LodgeDownload] Selected: category"
				self.indexList.append(self["addonslist"].getIndex())
				self.nodeList.append(self.currentNode)
				node = item[8]
				self.currentNode = node
				list = self.getList(self.currentNode)
				if list:
					self.fillMenu(list)
				else:
					self["introduction"].setText(_("The folder is empty!"))
					self["key_red"].setText(_("Back"))
			elif type == TYPE_FILE:
				print "[Sat-LodgeDownload] Selected: file"
				self.selectedItem = item
				self.downloadName = item[0]
				self.selectedCategory = item[4]
				self.fileName = item[6].strip()
				url = self.readUrl() + item[5].strip() + "/" + self.fileName
				self["introduction"].setText(MSG_DOWNLOADINGADDON % self.downloadName)
				self.session.openWithCallback(self.install, SatLodgeDownloader, url, "/tmp/", self.fileName)
			else:
				print "[Sat-LodgeDownload] Selected: unknown"

	def exit(self):
		if self.nodeList:
			index = self.indexList.pop()
			self.currentNode = self.nodeList.pop()
			list = self.getList(self.currentNode)
			self.fillMenu(list, index)
		else:
			if fileExists("/tmp/addons.xml"):
				system("rm -f /tmp/addons.xml")
			self.container = None
			self.close()

	def callManualInstall(self):
		self.session.open(SatLodgeManualInstall)

	def handleInfo(self):
		text = satlodgedownloadAboutText
		self.session.open(SatlodgeDownloadInfo, text)

	def readUrl(self):
		#return "http://sat-lodge.com/Images/index.php?dir="
		return "http://webplus.sat-lodge.it/"
        
	def setMsgAbort(self):
		print "[Sat-LodgeDownload] Installation of: %s aborted!" % self.downloadName
		self["introduction"].setText(MSG_ABORT % self.downloadName)
		msg = MB_MSG_ABORT % self.downloadName
		self.session.open(MessageBox, msg, MessageBox.TYPE_WARNING, windowTitle = _("Installation aborted"), timeout=5, close_on_any_key = True)

	def setMsgFailed(self):
		print "[Sat-LodgeDownload] Installation of: %s failed!" % self.downloadName
		self["introduction"].setText(MSG_FAILED % self.downloadName)
		msg = MB_MSG_FAILED % self.downloadName
		self.session.open(MessageBox, msg, MessageBox.TYPE_ERROR, windowTitle = _("Installation failed"), timeout=5, close_on_any_key = True)

	def setMsgWrongExtension(self):
		print "[Sat-LodgeDownload] Wrong file extension!"
		self["introduction"].setText(MSG_CONTACTSUPPORT)
		msg = MB_MSG_WRONGFILEEXTENSION
		self.session.open(MessageBox, msg, MessageBox.TYPE_ERROR, windowTitle = _("Wrong file extension"), timeout=5, close_on_any_key = True)

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

	def install(self, retval = STATUS_FAILED):
		if retval == STATUS_FAILED:
			print "[Sat-LodgeDownload] Addon not found:", self.downloadName
			self["introduction"].setText(MSG_ADDONNOTFOUND % self.downloadName)
			msg = MB_MSG_ADDONNOTFOUND % self.downloadName
			self.session.open(MessageBox, msg, MessageBox.TYPE_ERROR, windowTitle = _("Addon not found"), timeout=5, close_on_any_key = True)
		elif retval == STATUS_ABORTED:
			print "[Sat-LodgeDownload] Download of: %s aborted!" % self.downloadName
			self.setMsgAbort()
		else:
			if self.selectedCategory == CATEGORY_PICON:
				self["introduction"].setText(MSG_INSTALLINGPICONS % self.downloadName)
				msg = MB_MSG_INSTALLPICONSQUESTION % self.downloadName
				self.session.openWithCallback(self.openPiconsPathSelection, MessageBox, msg, MessageBox.TYPE_YESNO, windowTitle = _("Install picons"))
			elif self.selectedCategory == CATEGORY_SETTINGS:
				self["introduction"].setText(MSG_INSTALLINGSETTINGS % self.downloadName)
				msg = MB_MSG_INSTALLSETTINGSQUESTION % self.downloadName
				self.session.openWithCallback(self.installPiconsOrSettings, MessageBox, msg, MessageBox.TYPE_YESNO, windowTitle = _("Install settings"))
			else:
				self["introduction"].setText(MSG_INSTALLINGADDON % self.downloadName)
				msg = MB_MSG_INSTALLADDONQUESTION % self.downloadName
				self.session.openWithCallback(self.installAddon, MessageBox, msg, MessageBox.TYPE_YESNO, windowTitle = _("Install addon"))

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

	def openPiconsPathSelection(self, proceed = False):
		if proceed:
			self.session.openWithCallback(self.installPiconsOrSettings, PiconsPathSelection)
		else:
			self.setMsgAbort()
			self.delFile()

	def installPiconsOrSettings(self, proceed = False, path = SETTINGSPATH_DEFAULT):
		if proceed:
			if self.selectedCategory == CATEGORY_SETTINGS:
				print "[Sat-LodgeDownload] Proceed to unpack settings in the folder:", path
				self.backupSettings()
			else:
				print "[Sat-LodgeDownload] Proceed to unpack picons in the folder:", path
				self.piconsPath = path
			try:
				if self.fileName.endswith(".zip"):
					self.openConsole(cmd = ["unzip -o /tmp/" + self.fileName + " -d " + path + "/"])
				elif self.fileName.endswith(".xz"):
					self.openConsole(cmd = ["tar -Jxvf /tmp/" + self.fileName + " -C " + path + "/"])
				elif self.fileName.endswith(".deb"):
					self.openConsole(cmd = ["dpkg-deb -X /tmp/" + self.fileName + " " + path + "/"])
				else:
					self.setMsgWrongExtension()
					self.delFile()
			except:
				self.setMsgFailed()
				self.delFile()
		else:
			self.setMsgAbort()
			self.delFile()

	def installAddon(self, proceed = False):
		if proceed:
			try:
				print "[Sat-LodgeDownload] Proceed to install addon:", self.downloadName
				if self.fileName.endswith(".ipk"):
					self.openConsole(cmd = ["opkg install --force-overwrite /tmp/" + self.fileName])
				elif self.fileName.endswith(".deb"):
					self.openConsole(cmd = ["dpkg -i --force-overwrite /tmp/" + self.fileName])
				else:
					self.setMsgWrongExtension()
					self.delFile()
			except:
				self.setMsgFailed()
				self.delFile()
		else:
			self.setMsgAbort()
			self.delFile()

	def openConsole(self, cmd = []):
		print "[Sat-LodgeDownload] Open CONSOLE"
		self.session.openWithCallback(self.installFinished, Console, title = _("Installing: %s") % self.downloadName, cmdlist = cmd, finishedCallback = self.finishedCallback, closeOnSuccess = False)

	def finishedCallback(self):
		print "[Sat-LodgeDownload] Finished callback"
		msg = MB_MSG_COMPLETED % self.downloadName
		self.session.open(MessageBox, msg, MessageBox.TYPE_INFO, windowTitle = _("Addon installed"), timeout=1, close_on_any_key = True)

	def installFinished(self):
		print "[Sat-LodgeDownload] Finished installation of:", self.downloadName
		self["introduction"].setText(MSG_INSTALLEDSUCCESS % self.downloadName)
		if self.selectedCategory == CATEGORY_SETTINGS:
			self.reloadSettings()
		elif self.selectedCategory == CATEGORY_PICON:
			self.updatePiconsKeys()
		self.delFile()

	def delFile(self):
		print "[Sat-LodgeDownload] Removed:", self.fileName
		if fileExists("/tmp/" + self.fileName):
			system("rm -rf /tmp/" + self.fileName)

	def backupSettings(self):
		print "[Sat-LodgeDownload] Backup settings"
		if pathExists(SETTINGSBACKUP_FOLDER):
			rmtree(SETTINGSBACKUP_FOLDER)
		mkdir(SETTINGSBACKUP_FOLDER)
		files = listdir(SETTINGSPATH_DEFAULT + "/")
		count = 0
		for file in files:
			if file.endswith((".tv", ".radio")) or "lamedb" in file or "blacklist" in file or "whitelist" in file or "satellites" in file:
				print "[Sat-LodgeDownload] File to backup in settings folder:", file
				rename(SETTINGSPATH_DEFAULT + "/" + file, SETTINGSBACKUP_FOLDER + file)
				count += 1
		print "[Sat-LodgeDownload] Backuped %d files" % count

	def reloadSettings(self):
		print "[Sat-LodgeDownload] Reload IPTV"
		self.reloadIPTV()
		print "[Sat-LodgeDownload] Reload settings"
		self.eDVBDB = eDVBDB.getInstance()
		self.eDVBDB.reloadServicelist()
		self.eDVBDB.reloadBouquets()

	def reloadIPTV(self):
		shlist = []
		path = resolveFilename(SCOPE_CONFIG)
		try:
			list = listdir(path)
			for file in list:
				if file.endswith(".sh"):
					shlist.append(path + file)
					print "[Sat-LodgeDownload] Found .sh:", file
		except:
			shlist = []
			print "[Sat-LodgeDownload] Exception in reloadIPTV()"
		if shlist:
			self.session.open(Console, title = _("Reload IPTV"), cmdlist = shlist, closeOnSuccess = True)
		else:
			print "[Sat-LodgeDownload] No .sh file found"

	def updatePiconsKeys(self):
		print "[Sat-LodgeDownload] Update picons keys in settings if necessary"
		format, folder = self.selectedItem[10]
		if format in ("50x30", "100x60"):
			print "[Sat-LodgeDownload] Downloaded picons format: %s. Key config.plugins.InfoBar.PiconsPath not changed" % format
		else:
			print "[Sat-LodgeDownload] Downloaded picons format: %s. Key config.plugins.InfoBar.PiconsPath changed" % format
			config.plugins.InfoBar.PiconsPath.value = self.piconsPath
			config.plugins.InfoBar.PiconsPath.save()

	def getOpenEmbedded(self):
		if os_path.exists("/var/lib/dpkg/status"):
			return True
		return False

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

class SatlodgeDownloadInfo(TextBox):

	IS_DIALOG = True

	def __init__(self, session, text = ""):
		TextBox.__init__(self, session, text)

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

class PiconsPathSelection(Screen):
	skin = """
	<screen position="center,center" size="640,460">
		<ePixmap pixmap="skin_default/buttons/red.png" position="10,0" size="140,40" alphatest="on" />
		<widget name="list" position="10,50" size="620,200" scrollbarMode="showOnDemand" />
		<widget name="freespace" position="10,350" size="620,100" zPosition="10" font="Regular;21" halign="left" valign="bottom" backgroundColor="#25062748" transparent="1" />
	</screen>"""

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

		list = self.createList()
		self["list"] = MenuList(list)
		self["introduction"] = Label(_("Please press OK to select the storage device to use for saving picons\nor EXIT to close and abort the installation."))
		self["freespace"] = Label()

		self["actions"] = ActionMap(["OkCancelActions"],
		{
			"ok": self.okbuttonClick,
			"cancel": self.cancel
		}, -1)

		self["list"].onSelectionChanged.append(self.__selectionChanged)
		self.onLayoutFinish.append(self.layoutFinished)

	def layoutFinished(self):
		self.setTitle(_("Picons path selection")) 
		self.__selectionChanged()

	def createList(self):
		piconspath = config.plugins.InfoBar.PiconsPath.value
		mountpoints = [(PICONSPATH_DEFAULT, None)] + [(p.mountpoint, p) for p in harddiskmanager.getConfiguredStorageDevices()]
		pathlist = [ ]
		for mountpoint in mountpoints:
			if mountpoint[0] == piconspath:
				pathlist.insert(0, mountpoint)
			else:
				pathlist.append(mountpoint)
		return pathlist

	def __selectionChanged(self):
		selection = self["list"].getCurrent()
		if selection[0] == PICONSPATH_DEFAULT:
			status = statvfs("/")
			free = status.f_bavail * status.f_bsize / (1024 * 1024)
			text = _("Free space available on Flash") + ": %d MB" % free
		else:
			name = selection[0].rsplit("/", 1)[1]
			device = selection[1].device
			free = selection[1].free() / (1024 * 1024)
			text = _("Free space available on %s (partition %s)") % (name, device) + ": %d MB" % free
		self["freespace"].setText(text)

	def okbuttonClick(self):
		selection = self["list"].getCurrent()[0]
		print "[PiconsPathSelection] Selected:", selection
		self.close(True, selection)

	def cancel(self):
		self.close(False, "")
