# encoding: UTF-8
#
# Copyright 2012-2013 Alejandro Autalán
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
#
# For further info, check  http://pygubu.web.here
from __future__ import unicode_literals, print_function
import logging

try:
    import tkinter as tk
    import tkinter.ttk as ttk
except:
    import Tkinter as tk
    import ttk

from pygubu import builder
from pygubu.widgets.simpletooltip import create as create_tooltip
from pygubudesigner.widgets.propertyeditor import create_editor
from pygubudesigner import properties
from pygubudesigner.i18n import translator as _

logger = logging.getLogger(__name__)
CLASS_MAP = builder.CLASS_MAP


class PropertiesEditor(object):
    def __init__(self, frame, **kw):
        self._current = None
        self._sframe = frame
        self._frame = None
        self._propbag = {}
        self._id_validator = kw.get('id_validator', None)
        self._create_properties()
        self.hide_all()

    def _create_properties(self):
        """Populate a frame with a list of all editable properties"""
        self._frame = f = ttk.Labelframe(self._sframe.innerframe,
                                         text=_('Widget properties'))
        f.configure(padding=4)
        f.grid(sticky='nswe')

        label_tpl = "{0}:"
        row = 0
        col = 0

        groups = (
            ('00', _('Required'), properties.WIDGET_REQUIRED_OPTIONS,
             properties.REQUIRED_OPTIONS),
            ('01', _('Standard'), properties.WIDGET_STANDARD_OPTIONS,
             properties.TK_WIDGET_OPTIONS),
            ('02', _('Specific'), properties.WIDGET_SPECIFIC_OPTIONS,
             properties.TK_WIDGET_OPTIONS),
            ('03', _('Custom'), properties.WIDGET_CUSTOM_OPTIONS,
             properties.CUSTOM_OPTIONS),
        )

        for gcode, gname, plist, propdescr in groups:
            padding = '0 0 0 5' if row == 0 else '0 5 0 5'
            label = ttk.Label(self._frame, text=gname,
                              font='TkDefaultFont 10 bold', padding=padding,
                              foreground='#000059')
            label.grid(row=row, column=0, sticky='we', columnspan=2)
            row += 1
            for name in plist:
                kwdata = propdescr[name]
                labeltext = label_tpl.format(name)
                label = ttk.Label(self._frame, text=labeltext, anchor=tk.W)
                label.grid(row=row, column=col, sticky=tk.EW, pady=2)
                label.tooltip = create_tooltip(label, '?')
                widget = self._create_editor(self._frame, name, kwdata)
                widget.grid(row=row, column=col+1, sticky=tk.EW, pady=2)
                row += 1
                self._propbag[gcode+name] = (label, widget)
                logger.debug('Created property: %s-%s', gname,name)
                # add validator for widget id
                if gcode == '00' and name == 'id':
                    widget.set_unique_cb(self._id_validator)

    def _create_editor(self, master, pname, wdata):
        editor = None
        wtype = wdata.get('editor', None)

        #I don't have class name at this moment
        #so setup class specific values on update_property_widget
        editor = create_editor(wtype, master)

        def make_on_change_cb(pname, editor):
            def on_change_cb(event):
                self._on_property_changed(pname, editor)
            return on_change_cb

        editor.bind('<<PropertyChanged>>', make_on_change_cb(pname, editor))
        return editor

    def _on_property_changed(self, name, editor):
        self._current.widget_property(name, editor.value)

    def update_editor(self, label, editor, wdescr, pname, propdescr):
        pdescr = propdescr.copy()
        classname = wdescr.classname

        if classname in pdescr:
            pdescr = dict(pdescr, **pdescr[classname])

        params = pdescr.get('params', {})
        editor.parameters(**params)
        default = pdescr.get('default', '')
        
        help = pdescr.get('help', None)
        if isinstance(help, dict):
            for k, v in help.items():
                if classname.startswith(k):
                    help = v
                    break
        label.tooltip.text = help

        value = wdescr.widget_property(pname)
        if not value and default:
            value = default
        editor.edit(value)

    def edit(self, wdescr):
        self._current = wdescr
        wclass = wdescr.classname
        class_descr = CLASS_MAP[wclass].builder
        
        # GroupCode, PropertyType, dict, tuple
        groups = (
            ('00', None, properties.WIDGET_REQUIRED_OPTIONS,
             properties.REQUIRED_OPTIONS),
            ('01', 'OPTIONS_STANDARD', properties.WIDGET_STANDARD_OPTIONS,
             properties.TK_WIDGET_OPTIONS),
            ('02', 'OPTIONS_SPECIFIC', properties.WIDGET_SPECIFIC_OPTIONS,
             properties.TK_WIDGET_OPTIONS),
            ('03', 'OPTIONS_CUSTOM', properties.WIDGET_CUSTOM_OPTIONS,
             properties.CUSTOM_OPTIONS)
        )
        for gcode, attrname, proplist, gproperties in groups:
            for name in proplist:
                propdescr = gproperties[name]
                label, widget = self._propbag[gcode + name]
                if gcode == '00' or name in getattr(class_descr, attrname):
                    self.update_editor(label, widget, wdescr, name, propdescr)
                    label.grid()
                    widget.grid()
                else:
                    #hide property widget
                    label.grid_remove()
                    widget.grid_remove()
        self._sframe.reposition()

    def hide_all(self):
        """Hide all properties from property editor."""
        self.current = None

        for _v, (label, widget) in self._propbag.items():
            label.grid_remove()
            widget.grid_remove()
