# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import hash_literals

from dom import clear, ensure_id
from elementmaker import E
from widgets import create_button
from gettext import gettext as _

from book_list.globals import get_session_data
from book_list.top_bar import create_top_bar
from book_list.router import back
# from book_list.theme import get_font_size, get_color

pp_counter = 0
widget_counter = 0

class ConfigItem:

    def __init__(self, item_data):
        nonlocal widget_counter
        widget_counter += 1
        self.widget_id = 'pref-widget-' + widget_counter
        self.item_data = item_data
        self.ignore_ui_value_changed = False

    def initialize(self):
        self.ignore_ui_value_changed = True
        try:
            self.to_ui(self.from_storage())
        finally:
            self.ignore_ui_value_changed = False
        return self

    @property
    def container(self):
        return document.getElementById(self.widget_id)

    @property
    def control(self):
        return self.container.lastChild

    def from_storage(self):
        val = get_session_data().get(self.item_data.name)
        if self.item_data.from_storage:
            val = self.item_data.from_storage(val)
        return val

    def to_storage(self, val):
        if self.item_data.to_storage:
            val = self.item_data.to_storage(val)
        get_session_data().set(self.item_data.name, val)

    def defval(self):
        val = get_session_data().defval(self.item_data.name)
        if self.item_data.from_storage:
            val = self.item_data.from_storage(val)
        return val

    def ui_value_changed(self):
        if self.ignore_ui_value_changed:
            return
        self.to_storage(self.from_ui())

    def reset_to_default(self):
        self.to_ui(self.defval())
        self.ui_value_changed()

    def to_ui(self, val):
        pass

    def from_ui(self):
        pass

class Choices(ConfigItem):

    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text + ': ', style='white-space:pre'),
            E.select(required='1')
        )
        container.appendChild(div)
        select = div.lastChild
        for choice, text in item_data.choices:
            select.appendChild(E.option(text, value=choice))
        select.addEventListener('change', self.ui_value_changed.bind(self))
        select.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    def to_ui(self, val):
        self.control.value = val

    def from_ui(self):
        return self.control.value

class CheckBox(ConfigItem):

    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.input(type='checkbox'),
            E.span(' ' + item_data.text, style='white-space:pre')
        )
        container.appendChild(div)
        control = div.firstChild
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)
        div.lastChild.addEventListener('click', self.toggle.bind(self))

    @property
    def control(self):
        return self.container.firstChild

    def to_ui(self, val):
        self.control.checked = bool(val)

    def from_ui(self):
        return bool(self.control.checked)

    def toggle(self):
        self.to_ui(not self.from_ui())
        self.ui_value_changed()

class SpinBox(ConfigItem):

    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text + ': ', style='white-space:pre'),
            E.input(type='number', step='any', min='1', max='100')
        )
        container.appendChild(div)
        control = div.lastChild
        for attr in 'min max step'.split(' '):
            val = item_data[attr]
            if val is not undefined and val is not None:
                control.setAttribute(attr, '' + val)
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    def to_ui(self, val):
        self.control.value = val

    def from_ui(self):
        return self.control.value

class LineEdit(ConfigItem):

    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text + ': ', style='white-space:pre'),
            E.input(type='text')
        )
        container.appendChild(div)
        control = div.lastChild
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    def to_ui(self, val):
        self.control.value = val or ''

    def from_ui(self):
        return self.control.value or ''

state = {}

def onfocus(name):
    return def(ev):
        c = document.getElementById(state.container_id)
        div = c.querySelector('div[data-name="{}"]'.format(name))
        div.lastChild.style.display = 'block'


def create_prefs_widget(container, prefs_data):
    nonlocal state
    state = {}
    state.container_id = ensure_id(container)
    state.widgets = []
    clear(container)

    for item in prefs_data:
        div = E.div(
            style='margin-bottom:1ex; padding: 1ex 1em; border-bottom: solid 1px currentColor',
            title=item.tooltip,
            data_name=item.name,
            E.div(),
            E.div(
                item.tooltip or '',
                style='font-size:0.8rem; font-style: italic; margin-top:1ex; display:none'
            )
        )
        container.appendChild(div)
        val = get_session_data().get(item.name)
        if item.from_storage:
            val = item.from_storage(val)
        if item.choices:
            cls = Choices
        elif val is True or val is False:
            cls = CheckBox
        elif jstype(val) is 'number':
            cls = SpinBox
        else:
            cls = LineEdit
        state.widgets.push((new cls(item, div.firstChild, onfocus(item.name))).initialize())
    if state.widgets.length:
        container.appendChild(
            E.div(
                style='margin:1rem;',
                create_button(_('Restore default settings'), 'refresh', reset_to_defaults)
            )
        )


def reset_to_defaults():
    for w in state.widgets:
        w.reset_to_default()


def prefs_panel_handler(title_func, get_prefs_data, on_close=None, icon='close'):

    def onkeydown(container_id, close_action, ev):
        if ev.key is 'Escape':
            ev.preventDefault(), ev.stopPropagation()
            close_action()


    def close_action():
        if on_close is not None:
            on_close()
        back()

    def init_prefs_panel(container_id):
        container = document.getElementById(container_id)
        container.addEventListener('keydown', onkeydown.bind(None, container_id, close_action), {'passive': False, 'capture': True})
        container.setAttribute('tabindex', '0')
        create_top_bar(container, title=title_func(), action=close_action, icon=icon)
        container.appendChild(E.div())
        create_prefs_widget(container.lastChild, get_prefs_data())
        container.focus()

    return init_prefs_panel
