# -*- coding: utf-8 -*-
#
# «lirc» - libmythbuntu class for lirc modifications
#
# This script:
# Copyright (C) 2010, John Baab, for Mythbuntu
# Copyright (C) 2007-2008, Mario Limonciello, for Mythbuntu
#
#
# Mythbuntu is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3 of the License, or at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this application; if not, write to the Free Software Foundation, Inc., 51
# Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import re
import subprocess
import os
import shutil

#default remote hwdb
REMOTE_HWDB="/usr/share/lirc/lirc.hwdb"
EXTRA_REMOTE_HWDB="/usr/share/lirc/extras/more_remotes.hwdb"
TRANSMITTER_HWDB="/usr/share/lirc/extras/transmitter.hwdb"

#path to hardware.conf
HARDWARE_CONF="/etc/lirc/hardware.conf"

#Path to remotes
REMOTE_PATH="/usr/share/lirc/remotes/"

#path to main lircd.conf
LIRCD_CONF="/etc/lirc/lircd.conf"

class LircHandler:

    def __init__(self,hw_conf=HARDWARE_CONF):
        #initialize all lists
        self.remote_list=[]
        self.remote="None"
        self.remote_modules=""
        self.remote_device=""
        self.remote_driver=""
        self.remote_lircd_conf=""
        self.remote_count=0
        self.transmitter_list=[]
        self.transmitter="None"
        self.transmitter_modules=""
        self.transmitter_device=""
        self.transmitter_driver=""
        self.transmitter_lircd_conf=""
        self.transmitter_count=0
        self.populate_devices("remote",REMOTE_HWDB)
        self.populate_devices("remote",EXTRA_REMOTE_HWDB)
        self.populate_devices("transmitter",TRANSMITTER_HWDB)
        self.sort_devices()
        #load our current data
        self.read_hardware_conf(hw_conf)

    def sort_devices(self):
        """Sorts the device list for a type"""
        self.remote_list.sort(reverse=True)
        self.transmitter_list.sort(reverse=True)
        self.remote_list.insert(0,"None")
        self.transmitter_list.insert(0,"None")

    def populate_devices(self,type,file):
        """Populates all possible remotes from a hwdb.  Accepts either 'remote' or 'transmitter' for possible types"""
        try:
            hwdb = open(file).readlines()
            hwdb.sort()
            #Filter out uncessary lines
            filter = "^\#|^\["
            #Filter out the /dev/input/eventX remote
            filter += "|http"
            #Filter blaster if we are in remote
            if type == 'remote':
                filter += "|Blaster"
            pattern = re.compile(filter)
            for line in hwdb:
                if pattern.search(line) is None:
                    list = line.split(';')
                    if len(list) > 1:
                        #Make sure we have a config file before including
                        if list[4] != "":
                            if type == "remote":
#                                self.remote_list.append(list[0].translate(bytes.maketrans('',''),','))
                                self.remote_list.append(list[0])
                                self.remote_count = self.remote_count + 1
                            elif type == "transmitter":
                                self.transmitter_list.append(list[0])
#                                self.transmitter_list.append(list[0].translate(bytes.maketrans('',''),','))
                                self.transmitter_count = self.transmitter_count + 1
        except IOError:
            print("Error reading " + file + " to parse remote listing.")
        #if type == "remote":
        #    self.remote_list.append("Custom") 
        #    self.remote_count = self.remote_count + 1
        #elif type == "transmitter":
        #    self.transmitter_list.append("Custom") 
        #    self.transmitter_count = self.transmitter_count + 1

    def set_device(self,device,type):
        """Sets an active remote control or transmitter"""
        if type == "remote":
            count=self.remote_count
            list=self.remote_list
        elif type == "transmitter":
            count=self.transmitter_count
            list=self.transmitter_list
        else:
            print("Invalid device type: " + type)
            return

        found = False
        for item in range(count):
            if list[item] == device[type]:
                if type == "remote":
                    self.remote = list[item]
                elif type == "transmitter":
                    self.transmitter = list[item]
                found = True
                break
        if device[type] == "Custom":
            if type == "remote":
                self.remote=device[type]
                self.remote_modules=device["remote_modules"]
                self.remote_driver=device["remote_driver"]
                self.remote_device=device["remote_device"]
                self.remote_lircd_conf=device["remote_lircd_conf"]
            elif type == "transmitter":
                self.transmitter=device[type]
                self.transmitter_modules=device["transmitter_modules"]
                self.transmitter_driver=device["transmitter_driver"]
                self.transmitter_device=device["transmitter_device"]
                self.transmitter_lircd_conf=device["transmitter_lircd_conf"]

    def get_device_dictionary(self,type):
        """Returns a dictionary of all the info for a given device type"""
        if type == "remote":
            return {"remote":self.remote, "remote_modules":self.remote_modules, "remote_device": self.remote_device, "remote_driver":self.remote_driver, "remote_lircd_conf":self.remote_lircd_conf}
        elif type == "transmitter":
            return {"transmitter":self.transmitter, "transmitter_modules":self.transmitter_modules, "transmitter_device": self.transmitter_device, "transmitter_driver":self.transmitter_driver, "transmitter_lircd_conf":self.transmitter_lircd_conf}

    def get_possible_devices(self,type):
        """Returns all the possible remotes or transmitters"""
        if type == "remote":
            return self.remote_list
        elif type == "transmitter":
            return self.transmitter_list
        else:
            print("Invalid type: " + type)
            return None

    def read_hardware_conf(self,file=HARDWARE_CONF):
        """Reads in a lirc hardware configuration"""
        try:
            in_f=open(file)
            remote_pattern=re.compile("^REMOTE=")
            found_remote=False
            remote_modules_pattern=re.compile("^REMOTE_MODULES=")
            remote_device_pattern=re.compile("^REMOTE_DEVICE=")
            remote_driver_pattern=re.compile("^REMOTE_DRIVER=")
            remote_lircd_conf_pattern=re.compile("^REMOTE_LIRCD_CONF=")
            transmitter_pattern=re.compile("^TRANSMITTER=")
            found_transmitter=False
            transmitter_modules_pattern=re.compile("^TRANSMITTER_MODULES=")
            transmitter_device_pattern=re.compile("^TRANSMITTER_DEVICE=")
            transmitter_driver_pattern=re.compile("^TRANSMITTER_DRIVER=")
            transmitter_lircd_conf_pattern=re.compile("^TRANSMITTER_LIRCD_CONF=")

            for line in in_f:
                if remote_pattern.search(line) and not found_remote:
                    for item in range(self.remote_count):
                        if (not found_remote) and (self.remote_list[item] == line.split('"')[1]):
                            found_remote = True
                            self.remote = line.split('"')[1]
                elif remote_modules_pattern.search(line):
                    self.remote_modules = line.split('"')[1]
                elif remote_device_pattern.search(line):
                    self.remote_device = line.split('"')[1]
                elif remote_driver_pattern.search(line):
                    self.remote_driver = line.split('"')[1]
                elif remote_lircd_conf_pattern.search(line):
                    self.remote_lircd_conf = line.split('"')[1]
                elif transmitter_pattern.search(line) and not found_transmitter:
                    for item in range(self.transmitter_count):
                        if (not found_transmitter) and (self.transmitter_list[item] == line.split('"')[1]):
                            found_transmitter = True
                            self.transmitter = line.split('"')[1]
                elif transmitter_modules_pattern.search(line):
                    self.transmitter_modules = line.split('"')[1]
                elif transmitter_device_pattern.search(line):
                    self.transmitter_device = line.split('"')[1]
                elif transmitter_driver_pattern.search(line):
                    self.transmitter_driver = line.split('"')[1]
                elif transmitter_lircd_conf_pattern.search(line):
                    self.transmitter_lircd_conf = line.split('"')[1]
            if not found_remote:
                self.remote=""
            if not found_transmitter:
                self.transmitter=""
            in_f.close()
        except IOError:
            print("Error opening " + file)

    def write_hardware_conf(self,file=HARDWARE_CONF):
        """Writes out a hardware.conf"""
        patternline="^REMOTE="
        patternline+="|^TRANSMITTER="
        patternline+="|^FORCE_NONINTERACTIVE_RECONFIGURATION="
        #If we are known to be a custom remote, then write out other stuff too
        if self.remote == "Custom":
            custom_remote = True
            patternline+="|^REMOTE_MODULES="
            patternline+="|^REMOTE_DRIVER="
            patternline+="|^REMOTE_LIRCD_CONF="
        else:
            custom_remote = False
        if self.transmitter == "Custom":
            custom_transmitter = True
            patternline+="|^TRANSMITTER_MODULES="
            patternline+="|^TRANSMITTER_DRIVER="
            patternline+="|^TRANSMITTER_LIRCD_CONF="
        else:
            custom_transmitter = False
        pattern=re.compile(patternline)
        found_remote=False
        found_transmitter=False
        lines = None
        try:
            in_f = open(file)
            lines = in_f.readlines()
            in_f.close()
        except IOError:
            print("Unable to find " + file)
        out_f = open(file, 'w')
        for line in lines:
            if pattern.search(line) is None:
                out_f.write(line)
                continue
            else:
                if not found_remote and re.compile("^REMOTE=").search(line):
                    out_f.write("REMOTE=\"" + self.remote + "\"\n")
                    found_remote = True
                    continue
                elif not found_transmitter and re.compile("^TRANSMITTER=").search(line):
                    out_f.write("TRANSMITTER=\"" + self.transmitter + "\"\n")
                    found_transmitter = True
                    continue
                if re.compile("^FORCE_NONINTERACTIVE_RECONFIGURATION=").search(line):
                    #a reconfigure of lirc will be necessary after writing this hardware conf
                    out_f.write("FORCE_NONINTERACTIVE_RECONFIGURATION=\"" + "true" + "\"\n")
                if custom_remote:
                    if re.compile("^REMOTE_MODULES=").search(line):
                        out_f.write("REMOTE_MODULES=\"" + self.remote_modules + "\"\n")
                        continue
                    elif re.compile("^REMOTE_DRIVER=").search(line):
                        out_f.write("REMOTE_DRIVER=\"" + self.remote_driver + "\"\n")
                        continue
                    elif re.compile("^REMOTE_DEVICE=").search(line):
                        out_f.write("REMOTE_DEVICE=\"" + self.remote_device + "\"\n")
                        continue
                    elif re.compile("^REMOTE_LIRCD_CONF=").search(line):
                        out_f.write("REMOTE_LIRCD_CONF=\"" + self.remote_lircd_conf + "\"\n")
                        continue
                if custom_transmitter:
                    if re.compile("^TRANSMITTER_MODULES=").search(line):
                        out_f.write("TRANSMITTER_MODULES=\"" + self.transmitter_modules + "\"\n")
                        continue
                    elif re.compile("^TRANSMITTER_DRIVER=").search(line):
                        out_f.write("TRANSMITTER_DRIVER=\"" + self.transmitter_driver + "\"\n")
                        continue
                    elif re.compile("^TRANSMITTER_DEVICE=").search(line):
                        out_f.write("TRANSMITTER_DEVICE=\"" + self.transmitter_device + "\"\n")
                        continue
                    elif re.compile("^TRANSMITTER_LIRCD_CONF=").search(line):
                        out_f.write("TRANSMITTER_LIRCD_CONF=\"" + self.transmitter_lircd_conf + "\"\n")
                        continue
        if not found_remote:
            out_f.write("REMOTE=\"" + self.remote + "\"\n")
        if not found_transmitter:
            out_f.write("TRANSMITTER=\"" + self.transmitter + "\"\n")
        out_f.close()

    def reconfigure_lirc(self,interactive=False):
        """Restarts & Reconfigures LIRC"""
        if interactive:
            os.putenv('DEBIAN_FRONTEND','gnome')
        else:
            os.putenv('DEBIAN_FRONTEND','noninteractive')
        lirc_command = subprocess.Popen(["/usr/sbin/dpkg-reconfigure", "lirc"],stdout=subprocess.PIPE).communicate()[0]
        print(lirc_command)

    def query_advanced(self,remote_hwdb_file=REMOTE_HWDB,transmitter_hwdb_file=TRANSMITTER_HWDB):
        """Determine if this remote requires interactive configuration"""

        advanced_driver_pattern=re.compile("devinput")
        advanced_modules_pattern=re.compile("serial")

        remote_hwdb = open(remote_hwdb_file).readlines()
        transmitter_hwdb = open(transmitter_hwdb_file).readlines()

        #Filter out uncessary lines
        filter = "^\#|^\["
        pattern = re.compile(filter)
        #search advanced remotes
        for line in remote_hwdb:
            if pattern.search(line) is None:
                list = line.split(";")
                if len(list) > 1 and list[0].translate(bytes.maketrans('',''),',') == self.remote:
                    if advanced_driver_pattern.search(list[1]) or advanced_modules_pattern.search(list[2]):
                        return True
        #search advanced transmitters
        for line in transmitter_hwdb:
            if pattern.search(line) is None:
                list = line.split(";")
                if len(list) > 1 and list[0].translate(bytes.maketrans('',''),',') == self.remote:
                    if advanced_driver_pattern.search(list[1]) or advanced_modules_pattern.search(list[2]):
                        return True
        return False
    def create_lircrc(self,file=LIRCD_CONF,change_permissions=True,irexec=False,irexec_only=False):
        """Generates lircrc files for all possible applications"""

        command = "mythbuntu-lircrc-generator"

        if file != LIRCD_CONF:
            command = command + " -L " + file
        
        if irexec == True:
            command = command + " --irexec 1"

        if irexec_only == True:
            command = command + " --mythtv 0 --mplayer 0 --totem 0 --elisa 0 --xine 0 --vlc 0 --xmame 0 --xmess 0"

        if change_permissions:
            uid = os.getenv('SUDO_UID')
            if uid != None:
                in_f=open("/etc/passwd")
                for line in in_f:
                    fields = line.split(":")
                    if fields[2] == uid:
                        command = "su " + fields[0] + " -c " + command
        os.system(command)
