#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Interpreter version: brython (http://brython.info) (like python3)
#
"""
This module provides a collection of classes, which may be used to get/set
values into HTML GUI elements like <input>, <textarea>, <radio> and so on.

This classes may be used as descriptors for properties. They also defines basic
validations.
"""
# Imports =====================================================================
from browser import window
from browser import document

from components import DropdownHandler

from components import InputController

# virtual filesystem / modules provided by REST API
from virtual_fs import periodes


# Functions & classes =========================================================
class StandardElDescriptor(object):
    """
    Descriptor used for standard ``<input>`` element.

    It allows reading / writing of:
        - values
        - dicts (``{"source": .., "val": ..}``), in which case the source is
          highlighted on the right side
        - lists, in which case the element is transformed to typeahead element,
          which works like select
    """
    def __init__(self, el):
        self.el = el

    def __get__(self, obj, objtype):
        return InputController.get_el(self.el)

    def __set__(self, obj, value):
        self._show_error(False)
        InputController.set_el(self.el, value)

    def validate(self):
        if not self.el.required:
            return True

        if InputController.get_el(self.el):
            self._show_error(False)
            return True

        self._show_error(True)
        return False

    def reset(self):
        self.el.value = ""
        self._show_error(False)
        DropdownHandler.hide_dropdown_glyph(self.el.id)

    def _show_error(self, error=True):
        if error:
            self.el.style.border = "2px solid red"
        else:
            self.el.style.border = "0"


class AnnotationDescriptor(StandardElDescriptor):
    """
    Special descriptor used for `Annotation`. This descriptors operates over
    ``<textarea>``, but ignores lines starting with ``--``.

    Accepted datatypes are same as in :class:`StandardElDescriptor`.
    """
    def __get__(self, obj, objtype):
        value = InputController.get_el(self.el)

        active_lines = [
            line.strip()
            for line in value.splitlines()
            if not line.strip().startswith("--")
        ]

        return "\n".join(active_lines)


class PeriodicityDescriptor(StandardElDescriptor):
    """
    Special descriptor used for `periodicity`. If the periodicity is not set,
    the element offers the user list of periodes from ``virtual_fs/``.

    Accepted datatypes are same as in :class:`StandardElDescriptor`.
    """
    def __init__(self):
        super(self.__class__, self).__init__(document["periode"])
        self.__set__(None, periodes.periode_list)

    def __set__(self, obj, value):
        # custom handlers because of custom make_periode_typeahead_tag func
        parent_id = self.el.parent.id
        if "typeahead" not in parent_id.lower():
            parent_id = self.el.parent.parent.id

        if type(value) in [list, tuple] and len(value) > 1:
            window.make_periode_typeahead_tag("#" + parent_id, value)
            DropdownHandler.set_dropdown_glyph(
                self.el.id,
                "glyphicon-menu-down"
            )
            return

        window.destroy_typeahead_tag("#" + parent_id)
        InputController.set_el(self.el, value)


class RadioDescriptor(object):
    """
    Descriptor used to controll radio inputs.
    """
    def __init__(self, name, val_type=bool):
        self.name = name
        self.type = val_type

        self.elements = [
            el
            for el in document.get(selector="input[name='%s']" % name)
        ]
        self.values = {self._get_right_type(el.value) for el in self.elements}

    def _get_right_type(self, val):
        if self.type == bool:
            return val.lower() == "true"

        return self.type(val)

    def __get__(self, obj, objtype):
        for el in self.elements:
            if el.checked:
                return self._get_right_type(el.value)

        return None

    def __set__(self, obj, value):
        def _normalize(val):
            return str(val).lower()

        for el in self.elements:
            if _normalize(el.value) == _normalize(value):
                el.checked = True
                return

        raise ValueError(
            "Can't set the `%s` to `%s`." % (str(el), repr(value))
        )
