#
#  CaidDisplay - Converter
#
#  Coded by Dr.Best & weazle (c) 2010
#  Support: www.dreamboxtools.de
#
#  This plugin is licensed under the Creative Commons 
#  Attribution-NonCommercial-ShareAlike 3.0 Unported 
#  License. To view a copy of this license, visit
#  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
#  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
#
#  Alternatively, this plugin may be distributed and executed on hardware which
#  is licensed by Dream Multimedia GmbH.

#  This plugin is NOT free software. It is open source, you are allowed to
#  modify it (if you keep the license), but it may not be commercially 
#  distributed other than under the conditions noted above.
#

from Components.Converter.Converter import Converter
from enigma import iServiceInformation, iPlayableService, iPlayableServicePtr, eServiceReference
from Components.Element import cached
from os.path import isfile
from Poll import Poll
from Components.config import config
import re
from Tools.Directories import fileExists
from Screens.InfoBar import InfoBar

class CaidDisplay(Poll, Converter, object):
	SINGLELINE=0
	DOUBLELINE=1
	VERTICAL=2

	ecmDict = { }
	ecmMappingFile = "/etc/enigma2/ecmaddressmapping.cfg"
	
	def __init__(self, type):
		Poll.__init__(self)
		Converter.__init__(self, type)
		self.showFTA = False
		if type == "Vertical":
			self.type = self.VERTICAL
		elif type == "Double":
			self.type = self.DOUBLELINE
		elif type == "showFTA":
			self.type = self.SINGLELINE
			self.showFTA = True
		elif type == "showFTA2":
			self.type = self.DOUBLELINE
			self.showFTA = True
		else:
			self.type = self.SINGLELINE
		
		self.systemCaids = {
			"06" : "I",
			"01" : "S",
			"18" : "N",
			"05" : "V",
			"0B" : "CO",
			"17" : "B",
			"0D" : "CW",
			"4A70" : "DC",
			"4AF4": "MA",
			"4AFC": "PA",
			"4B64":	"SAM",
			"55" : "BG",
			"09" : "ND",
			"++" : "CI+",
			"56" : "VM",
			"07" : "DI",
			"10" : "TB",
			"22" : "CC",
			"26" : "BI",
			"27" : "EX",
			"48" : "AG",
			"0E" : "PV",
			"7B" : "DR",
			"A1" : "RC"}

		self.poll_interval = 2000
		self.poll_enabled = True

		self.loadMappingFile()

	def loadMappingFile(self):
		if isfile(self.ecmMappingFile):
			try:
				f = open(CaidDisplay.ecmMappingFile, "r")
				for line in f.readlines():
					split = line.rstrip("\n").split(" ")
					if len(split) == 2:
						CaidDisplay.ecmDict[split[0]] = split[1]
				f.close()
			except:
				pass

	@cached
	def get_caidlist(self):
		caidlist = {}
		if config.merlin2.skin_showencryption.value:
			service = self.source.service
			if service:
				info = service and service.info()
				if info:
					caids = info.getInfoObject(iServiceInformation.sCAIDs)
					if caids:
						for caid in caids:
							c = "%x" % int(caid)
							if len(c) == 3:
								c = "0%s" % c
							
							c = c.upper()
							if c[:2] not in ("4A", "4B"):
								c = c[:2]
							
							if c in self.systemCaids and c not in caidlist:
								caidlist[c] = (self.systemCaids.get(c),0)
						ecm_info = self.ecmfile()
						if ecm_info:
							emu_caid = ecm_info.get("caid", "")
							if emu_caid and emu_caid != "0x000":
								c = emu_caid.lstrip("0x")
								if len(c) == 3:
									c = "0%s" % c
								c = c.upper()
								if c[:2] not in ("4A", "4B"):
									c = c[:2]
								caidlist[c] = (self.systemCaids.get(c),1)
						
						else:
							ci_info = self.cifile()
							if ci_info:
								ci_caid = ci_info.get("caid", "")
								if ci_caid:
									caidlist["++"] = (self.systemCaids.get("++"),1)
					else: caidlist = None
				else: caidlist = None
			
			return caidlist

	getCaidlist = property(get_caidlist)

	@cached
	def getText(self):
		textvalue = ""
		if config.merlin2.skin_showdecryption.value:
			service = self.source.service
			if service:
				info = service and service.info()
				if info:
					if info.getInfoObject(iServiceInformation.sCAIDs):
						ecm_info = self.ecmfile()

						if ecm_info:
							# caid
							caid = ecm_info.get("caid", "")
							caid = caid.lstrip("0x")
							caid = caid.upper()
							caid = caid.zfill(4)
							# hops
							hops = ecm_info.get("hops", None)
							if hops and hops != "0":
								hops = "hop: %s" % hops
							else:
								hops = ""
							# ecm time	
							ecm_time = ecm_info.get("ecm time", None)
							if ecm_time:
								if hops != "":
									hops += " - "
								if "msec" in ecm_time:
									ecm_time = "(%s)" % ecm_time						
								elif ecm_time != "nan":
									if ecm_time.find('.') != -1:
										ecm_time = "(%s s)" % ecm_time
									else:
										ecm_time = "(%s ms)" % ecm_time
								else:
									ecm_time = ""
							# address
							address = ecm_info.get("address", "")
							if address:
								if address == "/dev/sci0":
									address = "Slot #1"
								elif address == "/dev/sci1":
									address = "Slot #2"
								else:
									host = address.split(":")[0]
									if address in self.ecmDict:
										address = self.ecmDcit[address]
									elif host in self.ecmDict:
										address = self.ecmDict[host]
							# source	
							# oscam
							oscsource = ecm_info.get("from", None)
							oscreader = None
							if config.merlin2.skin_readersource.value != "Source":
								oscreader = ecm_info.get("reader", None)								
							if oscsource:
								host = oscsource.split(":")[0]
								if host in self.ecmDict:
									oscsource = self.ecmDict[host]
								if config.merlin2.skin_simpledecodeinfo.value:
									if oscsource == "local":
										textvalue = "CRD"
									else:
										textvalue = "NET"
								else:
									if oscreader:
										if config.merlin2.skin_readersource.value == "Reader":
											if self.type == self.SINGLELINE:
												textvalue = "decode: %s - %s %s %s" % (caid, oscreader, hops, ecm_time)
											else:
												textvalue = "decode: %s - %s\n%s %s" % (caid, oscreader, hops, ecm_time)
										elif config.merlin2.skin_readersource.value == "RS":
											if self.type == self.SINGLELINE:
												textvalue = "decode: %s - %s (%s) %s %s" % (caid, oscsource, oscreader, hops, ecm_time)
											else:
												textvalue = "decode: %s - %s (%s)\n%s %s" % (caid, oscsource, oscreader, hops, ecm_time)
									else:
										if self.type == self.SINGLELINE:
											textvalue = "decode: %s - %s %s %s" % (caid, oscsource, hops, ecm_time)
										else:
											textvalue = "decode: %s - %s\n%s %s" % (caid, oscsource, hops, ecm_time)
							# gbox
							decode = ecm_info.get("decode", None)
								
							prov = ecm_info.get("prov", None)

							paddress = slot = level = dist = ecmtime = ""
							if prov:
								prov = prov[0:4]
							if decode:
								ecmtime = ecm_info.get("ecm time", "")
								if decode == "Internal":
									if config.merlin2.skin_simpledecodeinfo.value:
										textvalue = "EMU"
									else:
										textvalue = "decode: Internal %s" % (caid)
								elif decode.startswith("com") or decode.startswith("slot"):
									if config.merlin2.skin_simpledecodeinfo.value:
										textvalue = "CRD"
									else:
										textvalue = "decode: %s - %s (%s ms)" % (caid, decode, ecmtime)
								elif decode == "Network":
									if config.merlin2.skin_simpledecodeinfo.value:
										textvalue = "NET"
									else:
										prov_info = []
										ecmslot = ecm_info.get("slot", None)
										prov_info = self.provfile(prov, caid)
										if len(prov_info) >0 and ecmslot != None:
											for i in range(len(prov_info)):
												if prov_info[i][2] == ecmslot:
													paddress = self.ecmDict.get(prov_info[i][0], prov_info[i][0])
													slot = prov_info[i][2]
													level = prov_info[i][3]
													dist = prov_info[i][4]
													break
										elif len(prov_info) > 0:
											paddress = self.ecmDict.get(prov_info[0][0], prov_info[0][0])
											slot = prov_info[0][2]
											level = prov_info[0][3]
											dist = prov_info[0][4]										
										
										if self.type == self.SINGLELINE:
											textvalue = "NET %s - ID:%s - %s S:%s L:%s D:%s (%s ms)" % (caid, prov, paddress, slot, level, dist, ecmtime)
										else:
											textvalue = "NET %s - ID:%s - %s\nS:%s L:%s D:%s (%s ms)" % (caid, prov, paddress, slot, level, dist, ecmtime)
				
					else:
						if self.showFTA or config.merlin2.skin_showfta.value:
							textvalue = config.merlin2.skin_ftatext.value
		return textvalue 

	text = property(getText)
	
	def cifile(self):
		ciinfo = None
		s_info = None
		info = {}
		service = self.source.service
		sref = None
		
		if isinstance(service, iPlayableServicePtr):
			s_info = service and service.info()
			
			if s_info:
				sref = service and s_info.getInfoString(iServiceInformation.sServiceref)
		
		if sref is not None:
			for i in range(2):
				if fileExists("/var/run/ca/ci%d.service" %i):
					ciinfo = open("/var/run/ca/ci%d.service" %i, "r").readlines()
				
				if ciinfo:
					if len(ciinfo) > 0:
						channel = ciinfo[0].strip("\n")
					
						pos = sref.find("http")
						if pos != -1:
							sref = sref[:pos]

						if sref.startswith(channel):
							#if not info.has_key("caid"):
							if "caid" not in info:
								info["caid"] = "++"
							break
		return info

	def ecmfile(self):
		ecm = None
		info = {}
		service = self.source.service
		if service:
			demux = 0
			streaming = service.stream()
			s = streaming and streaming.getStreamingData()
			demux = s and s.get("demux", None)
			
			if fileExists("/tmp/ecm.info"):
				ecm = open("/tmp/ecm.info", "rb").readlines()
			
			if demux > 0:
				if fileExists("/tmp/ecm%d.info" %(demux)):
					ecm = open("/tmp/ecm%d.info" %(demux),"rb").readlines()
				elif fileExists("/tmp/ecm1.info"):
					ecm = open("/tmp/ecm1.info", "rb").readlines()

			if ecm:
				for line in ecm:
					#gbox
					dataLine = re.findall("prov: (.*?), slot: (.*?) level: (.*?) dist: (.*?)$", line)
					caidLine = re.search("ECM on CaID (.*?),", line)
					if len(dataLine) > 0:				
						info["prov"] = dataLine[0][0]
						info["slot"] = dataLine[0][1]
						info["level"] = dataLine[0][2]
						info["dist"] = dataLine[0][3]
					elif caidLine is not None:
						info["caid"] = caidLine.group(1)
					#oscam
					else:
						item = re.split(":|,", line)
						if len(item) > 3:
							info[item[0].strip().lower()] = item[1].strip()
							info[item[2].strip().lower()] = item[3].strip()
						elif len(item) > 1:
							element = item[0].strip().lower()
							# gbox ecm time
							if item[0].strip() == "response":
								element = "ecm time"
							if element == "ecm time" and len(item) == 3:
								item[1] = "%s.%s" %(item[1].strip(), item[2].strip())
							info[element] = item[1].strip()
		return info
	
	def provfile(self, prov, caid):
		cardlist = []
		
		try:
			#provider = open("/tmp/share.info", "rb").readlines()
			f = open("/tmp/share.info", "rb")
			cards = f.read()
			f.close()
		except: pass
		
		if caid == "0500":
			myregex = "CardID [0-9]* at (.*?) Card %s(.*?) Sl:(.*?) Lev:(.*?) dist:(.*?) id:%s\n" %(caid[:-1],prov)
		else:
			myregex = "CardID [0-9]* at (.*?) Card %s(.*?) Sl:(.*?) Lev:(.*?) dist:(.*?) id:%s\n" %(caid,prov)

		cardlist = re.findall(myregex, cards)
		
		return cardlist

	def changed(self, what):
		if (what[0] == self.CHANGED_SPECIFIC and what[1] == iPlayableService.evUpdatedInfo) or what[0] == self.CHANGED_POLL:
			Converter.changed(self, what)
