# -*- coding: utf-8 -*-
#
# MerlinRecommendedAddons
# Support: board.dreamboxtools.de
#
# This plugin is open source but it is NOT free software.
#

from Components.ActionMap import HelpableActionMap
from Components.Sources.StaticText import StaticText
from Components.Label import Label, MultiColorLabel
from Components.Sources.List import List
from Screens.Console import Console
from Screens.HelpMenu import HelpableScreen
from Screens.MessageBox import MessageBox
from Screens.Screen import Screen

from Tools.Directories import resolveFilename, SCOPE_PLUGINS
from Tools.HardwareInfo import HardwareInfo
from Tools.LoadPixmap import LoadPixmap
from enigma import eConsoleAppContainer, eSize
from operator import itemgetter
from twisted.web.client import getPage as twisted_getPage
import re
import ast

INSTALLED = re.compile('^\s*Installed\:\s(.*?)$')

class MerlinRecommendedAddons(Screen, HelpableScreen):
	# (packagename, displayname, description, icon(installed-png|not-installed-png), installed(bool))
	skin = """
		<screen name="MerlinRecommendedAddons" position="center,center" size="960,554">
			<ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
			<ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
			<ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
			<ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
			<widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
			<widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
			<widget font="Regular;20" halign="center" name="text" position="0,50" size="960,504" valign="center" zPosition="3"/>
			<widget source="list" render="Listbox" position="10,50" size="940,504" scrollbarMode="showOnDemand" zPosition="1">
				<convert type="TemplatedMultiContent">
					{"template": 
						[
							MultiContentEntryText(pos=(100,4), size=(840,30), font=0, text=1),
							MultiContentEntryText(pos=(100,34), size=(840,26), font=1, text=2),
							MultiContentEntryText(pos=(100,60), size=(840,22), font=2, text=0),
							MultiContentEntryPixmapAlphaBlend(pos=(20,35), size=(14,14), png=3),						
						],
						"fonts": [gFont("Regular",26),gFont("Regular",22),gFont("Regular",18)],
						"itemHeight": 84
					}
				</convert>
			</widget>
		</screen>"""
	
	def __init__(self, session, args = None):
		Screen.__init__(self, session)
		HelpableScreen.__init__(self)

		self["WizardActions"] = HelpableActionMap(self, "WizardActions",
		{
			"ok": 		(self.go,_("Execute an action")),
			"back":		(self.close,_("Close")),
			"up":		(self.moveUp,_("Move up")),
			"down":		(self.moveDown,_("Move down")),
			"left":		(self.pageUp,_("Page up")),
			"right":	(self.pageDown,_("Page down")),
		}, -1)
		self["ColorActions"] = HelpableActionMap(self, "ColorActions",
		{
			"red":		(self.close,_("Close")),
			"green":	(self.go,_("Execute an action")),
		}, -1)


		self["key_red"] = StaticText(_("Close"))
		self["key_green"] = StaticText("")

		
		self.container = eConsoleAppContainer()
		self.appClosed_testconn = self.container.appClosed.connect(self.runFinished)
		self.dataAvail_testconn = self.container.dataAvail.connect(self.dataAvail)
		self.stdErrAvail_testconn = self.container.stderrAvail.connect(self.displayError)
		self.hasColorDisplay = HardwareInfo().get_device_name() in ("dm900","dm920","dm820", "two")
		self.installedIcon = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "/usr/share/enigma2/Merlin/green.png"))
		self.notinstalledIcon = LoadPixmap(resolveFilename(SCOPE_PLUGINS, "/usr/share/enigma2/Merlin/red.png"))
		
		self.onLayoutFinish.append(self.startRun)
		self.onShown.append(self.setWindowTitle)
		
		self.list = []
		self["list"] = List(self.list)


		self.index = 0
		
		self["text"] = Label(_("Downloading addon information. Please wait..."))
		self["text"].show()
		
		self.run = 0
		self.remainingData = ""
		self.linesToProcess = []
		self.scannedPackages = {}

		self["list"].onSelectionChanged.append(self.updateSummary)
		self["list"].onSelectionChanged.append(self.updateButtonText)
		self.onShown.append(self.updateSummary)
	
	def pageUp(self):
		self["list"].moveSelection("pageUp")
		
	def pageDown(self):
		self["list"].moveSelection("pageDown")
		
	def moveUp(self):
		self["list"].moveSelection("moveUp")
		
	def moveDown(self):
		self["list"].moveSelection("moveDown")

		
	def runFinished(self, retval):
		if retval == 0:
			if self.run == 0: #apt-get update finished
				self.run = 1 #start apt-cache policy
				self.container.execute(self.commandList[self.run])
			elif self.run == 1:
				#results of apt-cache policy
				for line in self.linesToProcess:
					if line == '':
						continue
					if line.endswith(':') and line[:-1] in self.recommended_addons:
						packageName = line[:-1]
					elif INSTALLED.match(line) is not None:
						self.scannedPackages[packageName] = False if INSTALLED.match(line).group(1) == "(none)" else True
				if len(self.scannedPackages) > 0:
					self["text"].hide()
					self.createList()
	
	def createList(self):
		self.list = []
		for packagename, value in sorted(self.recommended_addons.items(), key = itemgetter(1)):
			if packagename in self.scannedPackages:
				priority, displayname, description = value
				installed = self.scannedPackages.get(packagename)
				icon = self.installedIcon if installed else self.notinstalledIcon
				self.list.append((packagename, displayname, _(description), icon, installed))

		self["list"].updateList(self.list)
		self["list"].setIndex(self.index)
		self.updateButtonText()
		self.updateSummary()
	
	def updateButtonText(self):
		sel = self["list"].getCurrent()
		if sel is not None:
			if not self["list"].getCurrent()[4]:
				self["key_green"].setText(_("Install"))
			else:
				self["key_green"].setText(_("Uninstall"))
		else:
			self["key_green"].setText("")


	def dataAvail(self, str):
		if self.run > 0:
			str = self.remainingData + str
			lines = str.split("\n")
			
			if len(lines[-1]):
				self.remainingData = lines[-1]
				lines = lines[0:-1]
			else:
				self.remainingData = ""

			if self.run == 1: #apt-cache policy
				self.linesToProcess.extend(lines)

	def createSummary(self):
		return MerlinRecommendedAddonsLCDScreen
		
	def updateSummary(self):
		text = ""
		state = None
		sel = self["list"].getCurrent()
		if sel is not None:
			text = sel[1]
			if self.hasColorDisplay:
				state = 1 if sel[4] else 0
			else:
				text = text + " (" + (_("installed") if sel[4] else _("not installed")) + ")"
		self.summaries.setText(text, state)

	def go(self):
		self.index = self["list"].index
		sel = self["list"].getCurrent()
		if sel is not None:
			if not sel[4]:
				self.session.openWithCallback(self.runInstall, MessageBox, _("Do you really want to INSTALL the addon '%s'?") % sel[0])
			else:
				self.session.openWithCallback(self.runInstall, MessageBox, _("Do you really want to REMOVE the addon '%s'?") % sel[0])

	def runInstall(self, val):
		if val:
			if not self["list"].getCurrent()[4]:
				self.executeAction("install")
			else:
				self.executeAction("remove")

	def executeAction(self, action):
		if action == "install":
			self.session.openWithCallback(self.installFinished, Console, cmdlist = ["apt-get -f --allow-unauthenticated install " + self["list"].getCurrent()[0]])
		elif action == "remove":
			self.session.openWithCallback(self.installFinished, Console, cmdlist = ["apt-get -y autoremove " + self["list"].getCurrent()[0]])
			
	def setWindowTitle(self):
		self.setTitle(_("Recommended addons"))

	def startRun(self):
		self["text"].show()
		twisted_getPage("https://merlinfeed.boxpirates.to/.recommended_addons").addCallback(self.jsonCallback).addErrback(self.jsonCallbackError)

	def jsonCallbackError(self, error = None):
		errormessage = _("Unexpected error!")
		if error is not None:
			errormessage = str(error.getErrorMessage())
		self.displayError(errormessage)
	
	def jsonCallback(self, json_string):
		self.recommended_addons = ast.literal_eval(json_string)
		self.commandList = ["apt-get update","apt-cache policy " + ' '.join(self.recommended_addons)]
		self.container.execute(self.commandList[self.run])

	def installFinished(self):
		self.run = 1 #start apt-cache policy
		self.linesToProcess = []
		self.scannedPackages = {}
		self.container.execute(self.commandList[self.run])

	def displayError(self, data):
		self["text"].setText(data)

class MerlinRecommendedAddonsLCDScreen(Screen):
	skin = (
	"""	<screen name="MerlinRecommendedAddonsLCDScreen" position="0,0" size="132,64" id="1">
			<widget name="plugin" position="4,0" size="132,30" font="Regular;14"/>
			<widget name="addon" position="4,30" size="132,30" font="Regular;12"/>
		</screen>""",
	"""	<screen name="MerlinRecommendedAddonsLCDScreen" position="0,0" size="96,64" id="2">
			<widget name="plugin" position="0,0" size="96,30" font="Regular;14"/>
			<widget name="addon" position="0,30" size="96,30" font="Regular;12"/>
		</screen>""",
	"""	<screen name="MerlinRecommendedAddonsLCDScreen" position="0,0" size="400,240" id="3">
			<widget name="plugin" position="0,0" size="400,50" font="Regular;40"/>
			<widget name="addon" foregroundColors="red,green" position="0,50" size="400,120" font="Regular;50"/>
		</screen>""",
	"""	<screen name="MerlinRecommendedAddonsLCDScreen" position="0,0" size="240,80" id="100">
			<widget name="plugin" position="0,0" size="240,24" font="Regular;20"/>
			<widget name="addon" foregroundColors="red,green" position="0,30" size="240,50" font="Regular;22"/>
		</screen>"""
		 )
	
	def __init__(self,session,parent):
		Screen.__init__(self, session)
		self["plugin"] = Label(_("MerlinRecommendedAddons"))
		self["addon"] = MultiColorLabel("")
		
	def setText(self, text, state=None):
		self["addon"].setText(text)
		if state is not None:
			self["addon"].setForegroundColorNum(state)

