# This file is part of gnome-tweak-tool.
#
# Copyright (c) 2011 John Stowers
#
# gnome-tweak-tool 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.
#
# gnome-tweak-tool 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 gnome-tweak-tool.  If not, see <http://www.gnu.org/licenses/>.

import os.path
import shutil
import zipfile
import tempfile

import os

from gi.repository import Gtk
from gi.repository import GLib

from gtweak.gsettings import GSettingsSetting
from gtweak.gshellwrapper import GnomeShell
from gtweak.tweakmodel import Tweak, TweakGroup
from gtweak.widgets import GConfComboTweak, GSettingsComboEnumTweak, \
        GSettingsSwitchTweak, build_label_beside_widget, \
        build_horizontal_sizegroup

EXTENSIONS_PATH = os.path.join(GnomeShell.DATA_DIR, 'extensions')

class ExtensionManager(object):
    def __init__(self):
        self.settings = GSettingsSetting('org.gnome.shell')

    def enable(self, key):
        # Remove an extension from the disabled extension if present
        disabled_extensions = set(self.settings.get_value('disabled-extensions'))
        if key in disabled_extensions:
            disabled_extensions.remove(key)
            self.settings.set_value('disabled-extensions', \
                                    list(disabled_extensions))

    def disable(self, key):
        # Add an extension to the disabled extensions
        disabled_extensions = set(self.settings.get_value('disabled-extensions'))
        if not key in disabled_extensions:
            disabled_extensions.add(key)
            self.settings.set_value('disabled-extensions', \
                                    list(disabled_extensions))

EXTENSION_MANAGER = ExtensionManager()

class ExtensionsSelector(Tweak):
    def __init__(self, **options):

        Tweak.__init__(self, "Shell extensions", \
                "Install custom or user extensions for gnome-shell", **options)
        
        error = "Unknown"
        
        try:
            self._shell = GnomeShell()
        except:
            error = "Shell not running"
        try:
            self.extensions = self._shell.list_extensions()
            error = None
        except Exception, e:
            error = "Could not list shell extensions"

        self.name = "extensions"

        if error:
            info = Gtk.InfoBar()
            info.props.message_type = Gtk.MessageType.INFO
            info.get_content_area().add(Gtk.Label(error))
            self.widget = build_label_beside_widget(self.name, info)
            self.widget_for_size_group = info
        else:
            self.hb = Gtk.VBox()
            button = Gtk.Button('Restart gnome-shell')
            button.connect('clicked', self._restart)
            self.hb.pack_start(button, False, False, 0)
            chooser = _ExtensionZipChooser()
            self.hb.pack_start(chooser, False, False, 0)
            self.hb.pack_start(Gtk.Label('Available extensions'), \
                    False, False, 5)
            # Load extensions
            self.__load_extensions(self.hb, self.extensions)
            self.widget = self.hb
            self.widget_for_size_group = self.hb

    def __load_extensions(self, container, values):
        for k, v in values.items():
            w = ExtensionToggler(k)
            
            if v.get('state') == 1:
                w.set_active(True)

            widget = build_label_beside_widget(v.get('name'), w)
            container.pack_start(widget, False, False, 5)

    def _restart(self, btn):
        self._shell.restart()

class ExtensionToggler(Gtk.Switch):
    
    def __init__(self, extension):
        Gtk.Switch.__init__(self)
        self.connect('notify::active', self.toggled)
        self.extension = extension

    def toggled(self, btn, data):
        if btn.get_active():
            #Extension must be active
            EXTENSION_MANAGER.enable(self.extension)
        else:
            #Extension must be disabled
            EXTENSION_MANAGER.disable(self.extension)

class _ExtensionZipChooser(Gtk.FileChooserButton):
    def __init__(self):
        Gtk.FileChooserButton.__init__(self, title="Select extension file")

        f = Gtk.FileFilter()
        f.add_mime_type("application/zip")
        self.set_filter(f)

        #self.set_width_chars(15)
        self.set_local_only(True)
        self.connect("file-set", self._on_file_set)

    def _on_file_set(self, chooser):
        f = self.get_filename()

        with zipfile.ZipFile(f, 'r') as z:
            try:
                #check this looks like a valid extension
                metadata_file = z.open('metadata.json')
                metadata = eval(metadata_file.read()) 
                uuid = metadata.get('uuid')

                self._extract_extension_zip(z, uuid)

            except KeyError:
                #does not look like a valid extension
                self.notify_error("Invalid extension file")
        #set button back to default state
        self.unselect_all()

    def _extract_extension_zip(self, z, extension_uuid):
        #Extract the extension in the local extension path
        tmp = tempfile.mkdtemp()
        dest = os.path.join(EXTENSIONS_PATH, extension_uuid)
        try:
            if os.path.exists(dest):
                shutil.rmtree(dest)
            z.extractall(tmp)
            shutil.copytree(tmp, dest)
        except OSError:
            self.notify_error("Error installing extension")

sg = build_horizontal_sizegroup()

TWEAK_GROUPS = (
        TweakGroup(
            "Extensions",
            ExtensionsSelector(size_group=sg),
	),
)
