#!/usr/bin/env python

from typing import Any

from com.sun.star.awt import Size, Point
from com.sun.star.beans import NamedValue

from .easymain import log, BaseObject


# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1form_1_1component.html
MODELS = {
    'hidden': 'com.sun.star.form.component.HiddenControl',
    'label': 'com.sun.star.form.component.FixedText',
    'text': 'com.sun.star.form.component.TextField',
    'checkbox': 'com.sun.star.form.component.CheckBox',
}

TYPE_CONTROLS = {
    'com.sun.star.form.OHiddenModel': 'hidden',
    'stardiv.Toolkit.UnoFixedTextControl': 'label',
    'com.sun.star.form.OEditControl': 'text',
    'com.sun.star.form.OCheckBoxControl': 'checkbox',
}


def _set_properties(model, properties):
    keys = tuple(properties.keys())
    values = tuple(properties.values())
    model.setPropertyValues(keys, values)
    return


class FormBaseControl(BaseObject):

    def __init__(self, obj: Any, shape: Any):
        super().__init__(obj)
        self._shape = shape
        self._doc = obj.Parent.Parent.Parent
        try:
            self._view = self._doc.CurrentController.getControl(self.obj)
        except Exception as e:
            self._view = None

    @property
    def name(self):
        return self.obj.Name

    @property
    def properties(self):
        from .easytools import LOInspect
        data = LOInspect(self.obj).properties
        return data
    @properties.setter
    def properties(self, values: dict):
        _set_properties(self.obj, values)

    @property
    def border(self):
        return self.obj.Border
    @border.setter
    def border(self, value):
        # ~ Not work
        self.obj.Border = value

    @property
    def enabled(self):
        return self.obj.Enabled
    @enabled.setter
    def enabled(self, value):
        self.obj.Enabled = value

    @property
    def visible(self):
        return self._view.Visible
    @visible.setter
    def visible(self, value):
        self._view.Visible = value

    @property
    def cell(self):
        return self.obj.ValueBinding.BoundCell
    @cell.setter
    def cell(self, value):
        SERVICE = 'com.sun.star.table.CellValueBinding'
        options = (NamedValue(Name='BoundCell', Value=value.address),)
        value_binding = self._doc.createInstanceWithArguments(SERVICE, options)
        self.obj.ValueBinding = value_binding

    @property
    def anchor(self):
        return self._shape.Anchor
    @anchor.setter
    def anchor(self, value):
        self._shape.Anchor = value.obj
        self._shape.ResizeWithCell = True

    @property
    def width(self):
        return self._shape.Size.Width
    @width.setter
    def width(self, value):
        self._shape.Size = Size(value, self.height)

    @property
    def height(self):
        return self._shape.Size.Height
    @height.setter
    def height(self, value):
        self._shape.Size = Size(self.width, value)

    @property
    def position(self):
        return self._shape.Position
    @position.setter
    def position(self, value):
        self._shape.Position = value

    def center(self):
        cell = self.anchor
        size = cell.Size
        pos = cell.Position
        pos.X += (size.Width / 2) - (self.width / 2)
        self.position = pos
        return

    def set_focus(self):
        self._view.setFocus()
        return


class FormLabel(FormBaseControl):

    def __init__(self, obj: Any, shape: Any):
        super().__init__(obj, shape)

    def __str__(self):
        return f'{self.type}: {self.name}'

    @property
    def type(self):
        return 'label'

    @property
    def value(self):
        return self.obj.Label
    @value.setter
    def value(self, value):
        self.obj.Label = value


class FormText(FormBaseControl):

    def __init__(self, obj: Any, shape: Any):
        super().__init__(obj, shape)

    def __str__(self):
        return f'{self.type}: {self.name}'

    @property
    def type(self):
        return 'text'

    @property
    def value(self):
        return self.obj.Text
    @value.setter
    def value(self, value):
        self.obj.Text = value


class FormCheckBox(FormBaseControl):

    def __init__(self, obj: Any, shape: Any):
        super().__init__(obj, shape)

    def __str__(self):
        return f'{self.type}: {self.name}'

    @property
    def type(self):
        return 'checkbox'

    @property
    def value(self):
        return self.obj.State
    @value.setter
    def value(self, value):
        self.obj.State = value


class FormHidden(FormBaseControl):

    def __init__(self, obj: Any, shape: Any):
        super().__init__(obj, shape)

    def __str__(self):
        return f'{self.type}: {self.name}'

    @property
    def type(self):
        return 'hidden'

    @property
    def value(self):
        return self.obj.HiddenValue
    @value.setter
    def value(self, value):
        self.obj.HiddenValue = value


FORM_CLASSES = {
    'hidden': FormHidden,
    'label': FormLabel,
    'text': FormText,
    'checkbox': FormCheckBox,
}


class LOForm(BaseObject):
    CONTROL_SHAPE = 'com.sun.star.drawing.ControlShape'
    CONTROL_HIDDEN = 'com.sun.star.form.OHiddenModel'

    def __init__(self, obj, draw_page):
        self._dp = draw_page
        self._doc = obj.Parent.Parent
        super().__init__(obj)
        self._init_controls()

    def _init_controls(self):
        for model in self.obj:
            if model.ImplementationName == self.CONTROL_HIDDEN:
                view = None
                tipo = model.ImplementationName
            else:
                view = self._doc.CurrentController.getControl(model)
                tipo = view.ImplementationName

            if not tipo in TYPE_CONTROLS:
                log.error(f'For add form control: {tipo}')
                continue

            control = FORM_CLASSES[TYPE_CONTROLS[tipo]](model, view)
            setattr(self, model.Name, control)
        return

    def __str__(self):
        return f'Form: {self.name}'

    def __contains__(self, item):
        """Contains"""
        return item in self.obj.ElementNames

    def __iter__(self):
        self._i = 0
        return self

    def __next__(self):
        """Interation form"""
        try:
            control = self.obj[self._i]
            control = getattr(self, control.Name)
        except Exception as e:
            raise StopIteration
        self._i += 1
        return control

    def _create_instance(self, name):
        return self._doc.createInstance(name)

    @property
    def name(self):
        return self.obj.Name
    @name.setter
    def name(self, value: str):
        self.obj.setName(value)

    def _default_properties(self, tipo: str, properties: dict, shape: Any):
        WIDTH = 5000
        HEIGHT = 500

        width = properties.pop('Width', WIDTH)
        height = properties.pop('Height', HEIGHT)
        shape.Size = Size(width, height)

        x = properties.pop('X', 0)
        y = properties.pop('Y', 0)
        shape.Position = Point(x, y)

        return properties

    def insert(self, properties: dict):
        return self.add_control(properties)

    def add_control(self, properties: dict):
        tipo = properties.pop('Type').lower()
        name = properties['Name']

        shape = self._create_instance(self.CONTROL_SHAPE)
        self._default_properties(tipo, properties, shape)

        model = self._create_instance(MODELS[tipo])
        _set_properties(model, properties)

        if tipo == 'hidden':
            shape = None
        else:
            shape.Control = model

        self.obj.insertByIndex(self.obj.Count, model)
        if not shape is None:
            self._dp.add(shape)
        control = FORM_CLASSES[tipo](model, shape)
        setattr(self, name, control)

        return control


class LOForms(BaseObject):

    def __init__(self, obj):
        self._dp = obj
        super().__init__(obj.Forms)

    def __getitem__(self, index):
        """Index access"""
        return LOForm(self.obj[index], self._dp)

    def __setitem__(self, key: str, value: Any):
        """Insert new form"""
        self.obj[key] = value

    def __len__(self):
        """Count forms"""
        return len(self.obj)

    def __iter__(self):
        self._i = 0
        return self

    def __next__(self):
        """Interation forms"""
        try:
            form = LOForm(self.obj[self._i], self._dp)
        except Exception as e:
            raise StopIteration
        self._i += 1
        return form

    def __contains__(self, item):
        """Contains"""
        return item in self.obj

    def new_form(self):
        """Create new instance form"""
        form = self.obj.Parent.createInstance('com.sun.star.form.component.Form')
        return form

    def insert(self, name: str):
        """Insert new form

        :param name: Name new form.
        :type name: str
        :return: New instance LOForm.
        :rtype: LOForm
        """
        form = self.new_form()
        self.obj.insertByName(name, form)
        return LOForm(form, self._dp)
