#
# parental_config.py
#
# Copyright (C) 2014 - 2018 Kano Computing Ltd.
# License: http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL v2
#

from urlparse import urlparse

from gi import require_version
require_version('Gtk', '3.0')

from gi.repository import Gtk

from kano_settings import common
from kano_settings.templates import Template, EditableList
from kano.gtk3.buttons import OrangeButton
from kano.gtk3.kano_dialog import KanoDialog
from kano_profile.tracker import track_data

from kano_settings.config_file import get_setting
from system.advanced import write_whitelisted_sites, write_blacklisted_sites, \
    read_listed_sites, set_parental_level, authenticate_parental_password


class ParentalConfig(Template):
    def __init__(self, win):
        Template.__init__(
            self,
            _("Parental lock"),
            _("Configure your parental lock settings"),
            _("APPLY CHANGES"),
            win.is_plug(),
            True
        )

        self.parental_level = Gtk.VScale(
            adjustment=Gtk.Adjustment(value=0, lower=0, upper=3,
                                      step_incr=1, page_incr=0, page_size=0))
        self.parental_level.get_style_context().add_class('parental_slider')
        self.parental_level.set_draw_value(False)
        self.parental_level.set_round_digits(0)
        self.parental_level.set_inverted(True)
        self.parental_level.set_value(get_setting('Parental-level'))
        self.parental_level.connect('value-changed', self._value_change_handler)

        self._parental_labels = [
            (
                Gtk.Label(_("Low Settings")),
                Gtk.Label(_("Block predefined blacklisted websites and\nactivates SafeSearch on Google and Youtube"))
            ),
            (
                Gtk.Label(_("Medium Settings")),
                Gtk.Label(_("Use safe DNS servers to filter all traffic"))
            ),
            (
                Gtk.Label(_("High Settings")),
                Gtk.Label(_("Enable all filters and restrict search engine access"))
            ),
            (
                Gtk.Label(_("Ultimate Settings")),
                Gtk.Label(_("Only allow access to Kano World activities"))
            )
        ]

        self.blacklist_button = OrangeButton(_("Configure allowed/blocked"))
        self.blacklist_button.connect('button-press-event',
                                      self.go_to_blacklist)

        self._value_change_handler(self.parental_level)

        parental_level_grid = Gtk.Grid()
        parental_level_grid.attach(self.parental_level, 0, 0, 1, 7)
        parental_level_grid.attach(self._parental_labels[3][0], 1, 0, 1, 1)
        parental_level_grid.attach(self._parental_labels[3][1], 1, 1, 1, 1)
        parental_level_grid.attach(self._parental_labels[2][0], 1, 2, 1, 1)
        parental_level_grid.attach(self._parental_labels[2][1], 1, 3, 1, 1)
        parental_level_grid.attach(self._parental_labels[1][0], 1, 4, 1, 1)
        parental_level_grid.attach(self._parental_labels[1][1], 1, 5, 1, 1)
        parental_level_grid.attach(self._parental_labels[0][0], 1, 6, 1, 1)
        parental_level_grid.attach(self._parental_labels[0][1], 1, 7, 1, 1)

        self.box.set_spacing(20)
        self.box.pack_start(parental_level_grid, False, False, 0)
        self.box.pack_start(self.blacklist_button, False, False, 0)

        self.win = win
        self.win.set_main_widget(self)

        self.set_prev_callback(self.go_to_advanced)
        self.win.change_prev_callback(self.win.go_to_home)
        self.win.top_bar.enable_prev()

        self.kano_button.connect('button-release-event', self.apply_changes)
        self.kano_button.connect('key-release-event', self.apply_changes)
        self.win.show_all()

    def go_to_advanced(self, widget):
        from kano_settings.set_advanced import SetAdvanced

        self.win.clear_win()
        SetAdvanced(self.win)

    def apply_changes(self, button, event):
        pw_dialog = ParentalPasswordDialog(self.win)
        if not pw_dialog.verify():
            return

        level = self.parental_level.get_value()
        set_parental_level(level)

        # track which parental control level people use
        track_data('parental-control-level-changed', {
            'level': level
        })

        if level == 3.0:
            # If on the highest parental control, prompt user to relaunch
            # the browser
            kdialog = KanoDialog(
                title_text=_("Settings"),
                description_text=(_("If any browsers are open, please relaunch " \
                                    "them for this setting to take effect")),
                parent_window=self.win
            )
            kdialog.run()

        else:
            # Only reboot for the lower parental controls
            common.need_reboot = True

        self.win.go_to_home()

    def go_to_blacklist(self, button, event):
        self.apply_changes(None, None)
        self.win.clear_win()
        AllowedSites(self.win)

    def _value_change_handler(self, gtk_range):
        for level, (title, desc) in enumerate(self._parental_labels):
            style_title = title.get_style_context()
            style_desc = desc.get_style_context()
            if gtk_range.get_value() == level:
                style_title.add_class('parental_activated')
                style_desc.add_class('parental_desc_activated')
                self.blacklist_button.set_sensitive(not level == 3.0)
            else:
                style_title.remove_class('parental_activated')
                style_title.add_class('normal_label')
                style_desc.remove_class('parental_desc_activated')
                style_desc.add_class('normal_label')


class SiteList(EditableList):

    def __init__(self, size_x=250, size_y=25):
        EditableList.__init__(self, size_x=size_x, size_y=size_y)

    @staticmethod
    def _sanitise_site(url):
        parse = urlparse(url)

        # enforcing some standards (e.g. http://)
        if parse.scheme == '' or parse.netloc == '':
            return None

        # removing the leading 'www.'
        netloc = parse.netloc
        if netloc.startswith('www.'):
            netloc = netloc.split('.', 1)[1]

        return netloc.lower()

    def _item_edited_handler(self, cellrenderertext, path, new_text):
        site = self._sanitise_site(new_text)
        EditableList._item_edited_handler(self, cellrenderertext, path, site)


class AllowedSites(Template):
    def __init__(self, win):
        Template.__init__(
            self,
            _("Allow and Block Sites"),
            _("Add extra sites to block or allow"),
            _("APPLY CHANGES"),
            win.is_plug(),
            True
        )

        self.win = win

        blacklist, whitelist = read_listed_sites()

        self.blacklist = SiteList(size_x=250, size_y=25)
        self.whitelist = SiteList(size_x=250, size_y=25)

        if whitelist:
            for site in whitelist:
                self.whitelist.edit_list_store.append([site])

        if blacklist:
            for site in blacklist:
                self.blacklist.edit_list_store.append([site])

        grid = Gtk.Grid()
        grid.set_column_spacing(40)

        add_label = Gtk.Label(_("Add extra sites to block"))
        add_label.get_style_context().add_class('normal_label')
        grid.attach(add_label, 0, 0, 1, 1)
        grid.attach(self.blacklist, 0, 1, 1, 1)

        remove_label = Gtk.Label(_("Something blocked that shouldn't be?"))
        remove_label.get_style_context().add_class('normal_label')
        grid.attach(remove_label, 1, 0, 1, 1)
        grid.attach(self.whitelist, 1, 1, 1, 1)

        self.box.pack_start(grid, False, False, 0)
        self.box.pack_start(Gtk.Label(''), False, False, 0)

        self.win.set_main_widget(self)

        self.win.top_bar.enable_prev()
        self.win.change_prev_callback(self.go_to_parental_config)
        self.set_prev_callback(self.go_to_parental_config)

        self.kano_button.connect('button-release-event', self.apply_changes)
        self.kano_button.connect('key-release-event', self.apply_changes)
        self.win.show_all()

        self.win.show_all()

    def apply_changes(self, button, event):
        pw_dialog = ParentalPasswordDialog(self.win)
        if not pw_dialog.verify():
            return

        whitelist = [row[0] for row in self.whitelist.edit_list_store]
        blacklist = [row[0] for row in self.blacklist.edit_list_store]

        write_whitelisted_sites(whitelist)
        write_blacklisted_sites(blacklist)

        level = get_setting('Parental-level')
        set_parental_level(level)
        common.need_reboot = True

        # track which parental control level people use
        track_data('parental-control-level-changed', {
            'level': level
        })

        self.win.go_to_home()

    def go_to_parental_config(self, button=None, event=None):
        self.win.clear_win()
        ParentalConfig(self.win)


class ParentalPasswordDialog(KanoDialog):

    def __init__(self, win):
        entry = Gtk.Entry()
        entry.set_visibility(False)
        self.win = win
        KanoDialog.__init__(
            self,
            title_text=_("Parental Authentication"),
            description_text=_("Enter your parental password:"),
            widget=entry,
            has_entry=True,
            global_style=True,
            parent_window=self.win
        )

    def verify(self):
        pw = self.run()

        if authenticate_parental_password(pw):
            return True

        fail = KanoDialog(
            title_text=_("Try again?"),
            description_text=_("The password was incorrect. Changes not applied"),
            parent_window=self.win
        )
        fail.run()

        return False