# -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Copyright (C) 2015 - 2018 David Mohammed <fossfreedom@ubuntu.com>
#
# This program 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, 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 program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.

import gettext
import re
import webbrowser

from gi.repository import GLib
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository import Pango
from gi.repository import Peas
from gi.repository import PeasGtk

from alttoolbar_preferences import CoverLocale


class PluginListRow(Gtk.ListBoxRow):
    def __init__(self, plugin, switch_callback):
        super(PluginListRow, self).__init__()

        self.plugin = plugin
        self._refresh = False

        self._switch_callback = switch_callback

        label1 = Gtk.Label()
        escape = GLib.markup_escape_text(plugin.get_name())
        label1.set_markup("<b>" + escape + "</b>")
        label1.set_ellipsize(Pango.EllipsizeMode.END)
        label1.props.halign = Gtk.Align.START
        label1.set_has_tooltip(True)
        label1.props.margin_top = 5
        label1.connect('query-tooltip', self._display_tooltip)
        label2 = Gtk.Label(plugin.get_description())
        label2.set_ellipsize(Pango.EllipsizeMode.END)
        label2.props.halign = Gtk.Align.START
        label2.set_has_tooltip(True)
        label2.connect('query-tooltip', self._display_tooltip)
        label2.props.margin_bottom = 5

        switch = Gtk.Switch.new()
        self._switch = switch
        switch.props.valign = Gtk.Align.CENTER

        sensitive = False

        try:
            if plugin.is_available():
                sensitive = True
            switch.set_active(plugin.is_loaded())
        except:
            pass

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)
        box.pack_start(label1, True, False, 0)
        box.pack_start(label2, True, False, 1)

        outerbox = Gtk.Box()
        outerbox.set_orientation(Gtk.Orientation.HORIZONTAL)
        outerbox.pack_start(Gtk.Label("  "), False, False, 0)
        outerbox.pack_start(box, False, False, 1)
        outerbox.pack_end(switch, False, False, 3)

        self.add(outerbox)
        self.outerbox = outerbox

        if not sensitive:
            self.add_error()

        switch.connect('notify::active', self._switch_changed)

    def _display_tooltip(self, label, x, y, mode, tooltip):
        if label.get_layout().is_ellipsized():
            tooltip.set_text(label.get_text())
            return True
        return False

    def _switch_changed(self, switch, *args):
        if self._refresh:
            return False

        self._refresh = True

        def delay(*args):
            print("switch_changed")
            print(switch.get_active())
            self._switch_callback(switch, self.plugin)

            self._refresh = False

        GLib.timeout_add(250, delay, None)

    def add_error(self):
        icon = Gio.ThemedIcon(name="dialog-error-symbolic")
        error_image = Gtk.Image()
        error_image.props.margin = 5
        error_image.set_from_gicon(icon, Gtk.IconSize.BUTTON)
        error_image.show_all()
        error_image.set_has_tooltip(True)
        error_image.set_tooltip_text(_('The plugin cannot be enabled'))
        self.outerbox.pack_end(error_image, False, False, 4)
        self.set_sensitive(False)

    def refresh(self, *args):
        try:

            if not self.plugin.is_available():
                self.add_error()

            if self._switch.get_active() == self.plugin.is_loaded():
                return

            self._switch.set_active(self.plugin.is_loaded())
        except:
            self.add_error()


class PluginDialog(Gtk.Dialog):
    def __init__(self, parent_window, has_headerbar):
        if has_headerbar:
            super(PluginDialog, self).__init__(use_header_bar=True,
                                               parent=parent_window,
                                               flags=Gtk.DialogFlags.MODAL)
        else:
            super(PluginDialog, self).__init__(parent=parent_window,
                                               flags=Gtk.DialogFlags.MODAL)

        self._has_headerbar = has_headerbar
        self._parent_window = parent_window

        listbox = Gtk.ListBox.new()
        listbox.set_sort_func(self._listbox_sort, None)
        self._listbox = listbox

        self._items = {}

        self._peas = Peas.Engine.get_default()
        plugins = self._peas.get_plugin_list()
        self._peas.connect_after('unload-plugin', self._on_load_unload_plugin)
        self._peas.connect_after('load-plugin', self._on_load_unload_plugin)

        for plugin in plugins:
            if not plugin.is_builtin() and not plugin.is_hidden():
                row = PluginListRow(plugin, self._switch_callback)
                self._items[plugin.get_module_name()] = row
                listbox.add(row)

        # locale stuff
        cl = CoverLocale()
        cl.switch_locale(cl.Locale.RB)

        def extract_text(str):
            # remove _ and (_A) type expressions
            translation = gettext.gettext(str)
            translation = re.sub('\(..\)', '', translation, flags=re.DOTALL)
            translation = translation.replace('_', '')
            return translation

        toolbar = Gtk.Toolbar.new()
        context = toolbar.get_style_context()
        context.add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)

        item = Gtk.ToolItem.new()

        btn = Gtk.Button()
        icon = Gio.ThemedIcon(name="preferences-system-symbolic")
        image = Gtk.Image()
        image.props.margin = 3
        btn.add(image)
        btn.set_tooltip_text(extract_text("_Preferences"))
        image.set_from_gicon(icon, Gtk.IconSize.BUTTON)
        box = Gtk.Box()
        box.pack_start(btn, False, False, 0)
        item.add(box)
        toolbar.insert(item, 0)

        btn.connect('clicked', self._preferences_button_clicked)
        self._preferences_button = btn

        minitoolbar_box = Gtk.ButtonBox()
        context = minitoolbar_box.get_style_context()
        context.add_class('linked')
        minitoolbar_box.set_layout(Gtk.ButtonBoxStyle.START)

        btn = Gtk.Button()
        icon = Gio.ThemedIcon(name="preferences-system-details-symbolic")
        image = Gtk.Image()
        image.props.margin = 3
        btn.add(image)
        btn.set_tooltip_text(extract_text("_About"))
        image.set_from_gicon(icon, Gtk.IconSize.BUTTON)
        minitoolbar_box.add(btn)
        minitoolbar_box.child_set_property(btn, "non-homogeneous", True)
        btn.connect('clicked', self._info_button_clicked)
        self._info_button = btn

        btn = Gtk.Button()
        icon = Gio.ThemedIcon(name="help-contents-symbolic")
        image = Gtk.Image()
        image.props.margin = 3
        btn.add(image)
        btn.set_tooltip_text(extract_text("_Help"))
        image.set_from_gicon(icon, Gtk.IconSize.BUTTON)
        minitoolbar_box.add(btn)
        minitoolbar_box.child_set_property(btn, "non-homogeneous", True)
        btn.connect('clicked', self._help_button_clicked)
        self._help_button = btn

        item = Gtk.SeparatorToolItem.new()
        item.props.draw = False

        toolbar.insert(item, 1)
        toolbar.child_set_property(item, "expand", True)

        item = Gtk.ToolItem.new()
        item.add(minitoolbar_box)
        toolbar.insert(item, 2)

        contentbox = Gtk.Box()
        contentbox.set_orientation(Gtk.Orientation.VERTICAL)

        scrollwindow = Gtk.ScrolledWindow.new(None, None)
        scrollwindow.add(listbox)
        scrollwindow.props.hexpand = True
        scrollwindow.props.vexpand = True

        contentbox.pack_start(scrollwindow, True, True, 0)
        contentbox.pack_start(toolbar, False, False, 1)

        self.props.title = _("Configure Plugins")

        if not self._has_headerbar:
            self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
        else:
            headerbar = self.get_header_bar()
            headerbar.set_show_close_button(True)

        contentbox.show_all()

        area = self.get_content_area()
        area.add(contentbox)

        listbox.connect('row-selected', self._listbox_row_selected)

    def _on_load_unload_plugin(self, engine, plugin):
        module_name = plugin.get_module_name()
        print(module_name)

        if module_name in self._items:
            self._items[module_name].refresh()

    def _listbox_sort(self, row1, row2, *args):
        return row1.plugin.get_name().lower() > row2.plugin.get_name().lower()

    def _switch_callback(self, switch, plugin):
        value = switch.get_active()

        if value and not plugin.is_loaded():
            self._peas.load_plugin(plugin)

        if not value and plugin.is_loaded():
            self._peas.unload_plugin(plugin)

        row = switch.get_parent().get_parent()
        self._listbox.select_row(row)
        self._listbox_row_selected(_, row)

    def _get_preference_widget(self, row):
        try:
            ext = self._peas.create_extension(row.plugin,
                                              PeasGtk.Configurable,
                                              None)
            widget = ext.create_configure_widget()
            cl = CoverLocale()
            cl.switch_locale(cl.Locale.RB)
            return widget
        except:
            pass

        return None

    def _listbox_row_selected(self, listbox, row):
        if row:

            has_preference = False
            widget = self._get_preference_widget(row)
            if widget:
                has_preference = True

            self._preferences_button.set_sensitive(has_preference)

            help_link = row.plugin.get_help_uri()

            if help_link:
                self._help_button.set_sensitive(True)
            else:
                self._help_button.set_sensitive(False)

    def _help_button_clicked(self, *args):
        row = self._listbox.get_selected_row()
        help_link = row.plugin.get_help_uri()

        webbrowser.open(help_link)

    def _info_button_clicked(self, *args):
        if self._has_headerbar:
            dlg = Gtk.Dialog(use_header_bar=True, flags=Gtk.DialogFlags.MODAL)
            dlg.get_header_bar().set_show_close_button(True)
        else:
            dlg = Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
            dlg.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)

        row = self._listbox.get_selected_row()

        title = row.plugin.get_name()
        version = row.plugin.get_version()
        dlg.props.title = _("About this plugin")

        area = dlg.get_content_area()

        widget = Gtk.Box()
        widget.set_orientation(Gtk.Orientation.VERTICAL)

        website = row.plugin.get_website()
        copyright = row.plugin.get_copyright()
        description = row.plugin.get_description()
        # authors = row.plugin.get_authors()
        help = row.plugin.get_help_uri()

        pos = 0

        def get_label(label):
            label = Gtk.Label(label)
            label.set_line_wrap(True)
            label.set_justify(Gtk.Justification.CENTER)
            label.set_max_width_chars(60)
            return label

        label = Gtk.Label()
        escape = GLib.markup_escape_text(title)
        label.set_markup("<b>" + escape + "</b>")
        label.set_justify(Gtk.Justification.CENTER)
        label.props.margin_bottom = 5

        widget.pack_start(label, False, False, pos)
        pos += 1

        if version:
            label = get_label(_("Version: ") + version)
            label.props.margin_bottom = 5

            widget.pack_start(label, False, False, pos)
            pos += 1

        if description:
            label = get_label(description)
            label.props.margin_bottom = 5

            widget.pack_start(label, False, False, pos)
            pos += 1

        if copyright:
            label = get_label(copyright)
            label.props.margin_bottom = 5

            widget.pack_start(label, False, False, pos)
            pos += 1

        if title == _("Alternative Toolbar"):
            # special case for the this plugin
            grid = Gtk.Grid()
            grid.props.halign = Gtk.Align.CENTER

            label = Gtk.Label(_("Developer:"))
            label.props.halign = Gtk.Align.END

            grid.attach(label, 0, 0, 1, 1)

            link = Gtk.Label()
            link.props.halign = Gtk.Align.START
            m = " <a href=\"https://github.com/fossfreedom\">David " \
                "Mohammed</a>"
            link.set_markup(m)
            grid.attach(link, 1, 0, 1, 1)

            label = Gtk.Label(_("Designer:"))
            label.props.halign = Gtk.Align.END

            grid.attach(label, 0, 1, 1, 1)

            link = Gtk.Label()
            link.props.halign = Gtk.Align.START
            m = " <a href=\"https://github.com/me4oslav\">Georgi " \
                "Karavasilev</a>"
            link.set_markup(m)
            grid.attach(link, 1, 1, 1, 1)

            widget.pack_start(grid, False, False, pos)

            grid.props.margin_bottom = 5
            pos += 1

        box = Gtk.Box()
        box.set_homogeneous(True)

        def launch_browser(button, uri):
            webbrowser.open(uri)

        button = Gtk.Button(_("Help"))
        if help:
            button.connect('clicked', launch_browser, help)
        else:
            button.set_sensitive(False)

        box.pack_start(button, False, True, 0)

        button = Gtk.Button(_("Homepage"))
        if help:
            button.connect('clicked', launch_browser, website)
        else:
            button.set_sensitive(False)

        box.pack_start(Gtk.Label(""), False, True, 1)
        box.pack_start(Gtk.Label(""), False, True, 2)

        box.pack_start(button, False, True, 3)

        widget.pack_start(box, False, True, pos)
        # pos += 1

        widget.show_all()
        frame = Gtk.Frame.new("")
        frame.props.margin = 8
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        frame.add(widget)
        frame.show_all()

        area.add(frame)
        dlg.set_resizable(False)

        dlg.run()
        dlg.destroy()

    def _preferences_button_clicked(self, *args):
        row = self._listbox.get_selected_row()

        widget = self._get_preference_widget(row)

        if not widget:
            return

        if self._has_headerbar:
            dlg = Gtk.Dialog(use_header_bar=True, flags=Gtk.DialogFlags.MODAL)
            dlg.get_header_bar().set_show_close_button(True)
        else:
            dlg = Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
            dlg.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)

        dlg.props.title = row.plugin.get_name()
        area = dlg.get_content_area()
        area.add(widget)
        dlg.set_resizable(False)
        dlg.run()
        dlg.destroy()
