## -*- coding: utf-8 -*-
#
# «remote» - MCC Infrared device selection plugin
#
# Copyright (C) 2010, John Baab, for Mythbuntu
# Copyright (C) 2009, 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 2 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
##################################################################################

from MythbuntuControlCentre.plugin import MCCPlugin

from mythbuntu_common.lirc import LircHandler
from gi.repository import Gtk
import os
import subprocess
import logging

class RemotePlugin(MCCPlugin):
    """A GUI configuration tool for LIRC"""

    def __init__(self):
        #Initialize parent class
        information = {}
        information["name"] = "Infrared"
        information["icon"] = "gtk-media-record"
        information["ui"] = "tab_remote_control"
        MCCPlugin.__init__(self,information)

        self.count={}
        self.count["remote"]=0
        self.count["transmitter"]=0

    #Helper functions
    def populate_lirc(self):
        """Fills the lirc pages with the appropriate data"""
        def fill_array(list,possible_items):
            """Fills an individual array up"""
            count=0
            for item in possible_items:
                list.append([item])
                count = count + 1
            return count

        for type in ('remote','transmitter'):
            list = self.builder.get_object(type + '_list')
            model = list.get_model()
            self.count[type]=fill_array(model, \
                                        self.lirc.get_possible_devices(type))
            list.set_active_iter(model.get_iter(Gtk.TreePath([0,0])))

    def find_lircrc(self):
        """Determines if there is current a lircrc for the current user"""
        return os.path.exists(os.getenv('HOME') + '/.lircrc')

    #Inherited, overridden functions
    def captureState(self):
        """Determines the state of the items on managed by this plugin"""
        #Parent functionality for state capturing
        MCCPlugin.clearParentState(self)
        #If this is a first run of capturing, we might need to fill
        #in our remote_count
        self.state = {}
        for item in ['lirc','mythbuntu-lirc-generator']:
            self.state[item] = self.query_installed(item)

        #TODO, detect smartphone type somehow.
        self.state['type'] = 'native'

        if self.state['lirc']:
            self.state['type'] = 'lirc'
            if self.count["remote"] is 0:
                self.lirc=LircHandler()
                self.populate_lirc()
            #Read in our /etc/lirc/hardware.conf
            self.lirc.read_hardware_conf()

    def applyStateToGUI(self):
        """Takes the current state in formation and sets the GUI"""

        def match_object(saved_setting, list, count):
            """Attempts to match a saved object to a GTK list of objects"""
            if saved_setting is "Custom":
                return True
            elif saved_setting != "None":
                for item in range(count):
                    model = list.get_model()
                    iter = model.get_iter(Gtk.TreePath([item,0]))
                    list.set_active_iter(iter)
                    if model[iter][0] == saved_setting:
                        return True
            return False

        def load_custom(type,dictionary):
            """Loads a custom remote or transmitter into the GUI"""
            modules=self.builder.get_object(type + '_modules')
            device=self.builder.get_object(type + '_device')
            driver=self.builder.get_object(type + '_driver')
            conf=self.builder.get_object('browse_' + type + '_lircd_conf')
            modules.set_text(dictionary[type + "_modules"])
            driver.set_text(dictionary[type + "_driver"])
            device.set_text(dictionary[type + "_device"])
            conf.select_filename("/usr/share/lirc/" + type )
            if os.path.exists("/usr/share/lirc/" + type + '/' + dictionary[type + "_lircd_conf"]):
                conf.select_filename("/usr/share/lirc/" + type + '/' + dictionary[type + "_lircd_conf"])

        if self.state['type'] == 'lirc':
            self.smartphone_vbox.set_sensitive(False)
            self.lirc_vbox.set_sensitive(True)
            self.lirc_support.set_active(True)
            for type in ('remote','transmitter'):
                dict=self.lirc.get_device_dictionary(type)
                list=self.builder.get_object(type + '_list')
                checkbox=self.builder.get_object(type + 'control')
                found=match_object(dict[type],list,self.count[type])
                checkbox.set_active(found)
                self.toggle_ir(checkbox,True)

                #"Custom" support
                load_custom(type,dict)
        elif self.state['type'] == 'native':
            self.lirc_vbox.set_sensitive(False)
            self.smartphone_vbox.set_sensitive(False)
        else:
            self.lirc_vbox.set_sensitive(False)
            self.smartphone_vbox.set_sensitive(True)

    def compareState(self):
        """Determines what items have been modified on this plugin"""
        def test_basic_changes(type):
            """Test for changes in a regular remote or transmitter"""
            old=self.lirc.get_device_dictionary(type)[type]
            list = self.builder.get_object(type + '_list')
            model = list.get_model()
            current = model[list.get_active_iter()][0]
            if old != current:
                self._markReconfigureRoot(type,current)
            return current

        def test_custom_changes(type):
            """Tests for changes in a custom remote or transmitter"""
            old={}
            new={}
            old['modules']=self.lirc.get_device_dictionary(type)[type + "_modules"]
            old['device']=self.lirc.get_device_dictionary(type)[type + "_device"]
            old['driver']=self.lirc.get_device_dictionary(type)[type + "_driver"]
            old['lircd_conf']=self.lirc.get_device_dictionary(type)[type + "_lircd_conf"]
            new['modules']=self.builder.get_object(type + '_modules').get_text()
            new['device']=self.builder.get_object(type + '_device').get_text()
            new['driver']=self.builder.get_object(type + '_driver').get_text()
            new['lircd_conf']=self.builder.get_object('browse_' + type + '_lircd_conf').get_filename()
            for item in old:
                if old[item] != new[item]:
                    self._markReconfigureRoot(type + '_'+ item,new[item])

        #Prepare for state capturing
        MCCPlugin.clearParentState(self)

        #check for type changes
        if self.native_support.get_active():
            radio = 'native'
        elif self.lirc_support.get_active():
            radio = 'lirc'
        else:
            radio = 'smartphone'

        #figure out if we are installing lirc or removing it
        if self.state['type'] != radio:
                if radio == 'lirc' and not self.state['lirc']:
                    self._markInstall('lirc')
                elif self.state['lirc']:
                    self._markRemove('lirc')

        if self.state['lirc']:
            for type in ('remote','transmitter'):
                value = test_basic_changes(type)
                if value == 'Custom':
                    test_custom_changes(type)

            if self.generate_lircrc_checkbox.get_active():
                if not self.state['mythbuntu-lirc-generator']:
                    self._markInstall('mythbuntu-lirc-generator')
                if self.enable_irexec_checkbox.get_active():
                    self._markReconfigureUser("generate_lircrc_irexec", True)
                else:
                    self._markReconfigureUser("generate_lircrc",True)
            elif self.enable_irexec_checkbox.get_active():
                if not self.state['mythbuntu-lirc-generator']:
                    self._markInstall('mythbuntu-lirc-generator')
                self._markReconfigureUser("generate_lircrc_irexec_only", True)

    def toggle_ir(self,widget,internal=False):
        """Callback used for any widgets in the remote plugin"""

        def toggle_active_section(widget,type):
            """Turns on or off an IR remote"""
            hbox=self.builder.get_object(type + '_hbox')
            list=self.builder.get_object(type + '_list')
            hbox.set_sensitive(widget.get_active())
            if widget.get_active():
                if list.get_active() == 0:
                    list.set_active(1)
            else:
                list.set_active(0)

        def toggle_active_object_selection(widget,type):
            """Toggles the active device selection and related items"""
            control=self.builder.get_object(type + 'control')
            list=self.builder.get_object(type + '_list')
            driver=self.builder.get_object(type + '_driver_hbox')
            modules=self.builder.get_object(type + '_modules_hbox')
            device=self.builder.get_object(type + '_device_hbox')
            config=self.builder.get_object(type + '_configuration_hbox')

            if list.get_model()[list.get_active_iter()][0] == "Custom":
                custom = True
            else:
                custom = False
                if list.get_active() == 0:
                    control.set_active(False)
                    return False

            for item in (driver, modules, device, config):
                if custom:
                    item.show()
                else:
                    item.hide()
            return True

        if internal and self.find_lircrc():
            self.generate_lircrc_checkbox.set_active(False)
            self.enable_irexec_checkbox.set_active(False)

        if widget is not None:
            #toggle types on the page
            if type(widget) is Gtk.RadioButton:
                #they all have callbacks, only use the active one
                if widget.get_active():
                    name = widget.get_name()
                    if name == 'native_support':
                        self.smartphone_vbox.set_sensitive(False)
                        self.lirc_vbox.set_sensitive(False)
                    elif name == 'smartphone_support':
                        self.smartphone_vbox.set_sensitive(True)
                        self.lirc_vbox.set_sensitive(False)
                        self.emit_progress("Smartphone support selected.\n\nYou must enable the 'Network Remote Control interface' in the frontend\n\nSetup > General > Remote Control (6th screen)", 100)
                    #the lirc package needs to be installed to show this
                    elif self.state['lirc']:
                        self.smartphone_vbox.set_sensitive(False)
                        self.lirc_vbox.set_sensitive(True)

            #turn on/off IR remote
            elif widget.get_name() == 'remotecontrol':
                toggle_active_section(widget,"remote")

            #turn on/off IR transmitter
            elif widget.get_name() == "transmittercontrol":
                toggle_active_section(widget,"transmitter")

            #if our selected remote itself changed
            elif widget.get_name() == 'remote_list':
                if toggle_active_object_selection(widget,"remote"):
                    self.generate_lircrc_checkbox.set_active(True)
                else:
                    self.generate_lircrc_checkbox.set_active(False)

            #if our selected transmitter itself changed
            elif widget.get_name() == 'transmitter_list':
                toggle_active_object_selection(widget,"transmitter")

    def user_scripted_changes(self,reconfigure):
        """Local changes that can be performed by the user account.
           This function will be ran by the frontend."""
        for item in reconfigure:
            if item == "generate_lircrc":
                self.lirc.create_lircrc(change_permissions=False)
            elif item == "generate_lircrc_irexec":
                self.lirc.create_lircrc(change_permissions=False,irexec=True)
            elif item == "generate_lircrc_irexec_only":
                self.lirc.create_lircrc(change_permissions=False,irexec=True,irexec_only=True)

    def root_scripted_changes(self,reconfigure):
        """System-wide changes that need root access to be applied.
           This function is ran by the dbus backend"""
        lirc=LircHandler()
        found = False
        for item in reconfigure:
            if item == "remote" or item == "transmitter":
                logging.debug("Setting item %s to %s." % (item,reconfigure[item]))
                lirc.set_device({item:reconfigure[item]},item)
                found = True
        if found:
            logging.debug("Writing out /etc/lirc/hardware.conf")
            lirc.write_hardware_conf()
            logging.debug("Reconfiguring LIRC package")
            lirc.reconfigure_lirc(interactive=False)
        return found
