#------------------------------------------------------------------------------
# Copyright (c) 2013, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import Atom, Int, Bool, Coerced, Enum, List, Unicode, Value

from .geometry import Rect


class dockitem(Atom):
    """ A layout node for declaring a dock layout item.

    """
    #: The name of the item referenced in the layout.
    name = Unicode()

    @classmethod
    def from_dict(cls, dct):
        """ Create a dockitem from a layout dictionary.

        Parameters
        ----------
        dct : dict
            A layout dictionary of 'dockitem' type generated by a
            previous call to 'as_dict'.

        """
        return cls(dct['name'])

    def __init__(self, name):
        """ Initialize an item.

        Parameters
        ----------
        name : unicode
            The unicode name of the dock item to include in the layout.

        """
        self.name = name

    def as_dict(self):
        """ Convert the dock item layout into a layout dictionary.

        """
        return {'type': 'dockitem', 'name': self.name}


class docktabs(Atom):
    """ A layout node for declaring a tabbed layout item.

    """
    #: The index of the selected tab.
    index = Int(0)

    #: The position of the tabs in the widget.
    tab_position = Enum('top', 'bottom', 'left', 'right')

    #: The child dock item nodes to add to the tab layout.
    children = List()

    @classmethod
    def from_dict(cls, dct):
        """ Create a docktabs layout from a layout dictionary.

        Parameters
        ----------
        dct : dict
            A layout dictionary of 'docktabs' type generated by a
            previous call to 'as_dict'.

        """
        children = (dockitem.from_dict(d) for d in dct['children'])
        self = cls(*children)
        self.index = dct['index']
        self.tab_position = dct['tab_position']
        return self

    def __init__(self, *children, **kwargs):
        """ Initialize a docktabs layout.

        Parameters
        ----------
        *children
            The children to add to the layout. The allowed child types
            are 'basestring' and 'dockitem'.

        **kwargs
            Additional configuration data for the layout.

        """
        super(docktabs, self).__init__(**kwargs)
        valid = []
        for child in children:
            if isinstance(child, basestring):
                child = dockitem(child)
            if not isinstance(child, dockitem):
                msg = "'s' is an invalid type for a docktabs child"
                raise TypeError(msg % type(child).__name__)
            valid.append(child)
        self.children = valid

    def as_dict(self):
        """ Convert the docktabs layout into a layout dictionary.

        """
        layout = {
            'type': 'docktabs',
            'index': self.index,
            'tab_position': self.tab_position,
            'children': [c.as_dict() for c in self.children],
        }
        return layout


class docksplit(Atom):
    """ A layout node for declaring a splitter layout item.

    """
    #: The orientation of the splitter.
    orientation = Enum('horizontal', 'vertical')

    #: The default sizes to apply to the splitter. The length should
    #: be equal to the number of children declared for the splitter.
    sizes = List(int)

    #: The child layout nodes to add to the splitter.
    children = List()

    @classmethod
    def from_dict(cls, dct):
        """ Create a split layout from a layout dictionary.

        Parameters
        ----------
        dct : dict
            A layout dictionary of 'docksplit' type generated by a
            previous call to 'as_dict'.

        """
        children = []
        for child in dct['children']:
            t = child['type']
            if t == 'dockitem':
                c = dockitem.from_dict(child)
            elif t == 'docktabs':
                c = docktabs.from_dict(child)
            elif t == 'docksplit':
                c = docksplit.from_dict(child)
            else:
                raise TypeError("invalid child type '%s'" % t)
            children.append(c)
        self = cls(*children)
        self.sizes = dct['sizes']
        self.orientation = dct['orientation']
        return self

    def __init__(self, *children, **kwargs):
        """ Initialize a split layout.

        Parameters
        ----------
        *children
            The children to add to the layout. The allowed child types
            are 'basestring', 'docksplit', 'docktabs', and 'dockitem'.

        **kwargs
            Additional configuration data for the layout.

        """
        super(docksplit, self).__init__(**kwargs)
        valid = []
        allowed = (docksplit, docktabs, dockitem)
        for child in children:
            if isinstance(child, basestring):
                child = dockitem(child)
            if not isinstance(child, allowed):
                msg = "'s' is an invalid type for a docksplit child"
                raise TypeError(msg % type(child).__name__)
            valid.append(child)
        self.children = valid

    def as_dict(self):
        """ Convert the split layout into a layout dictionary.

        """
        layout = {
            'type': 'docksplit',
            'orientation': self.orientation,
            'sizes': list(self.sizes),
            'children': [c.as_dict() for c in self.children],
        }
        return layout


def hdocksplit(*args, **kwargs):
    """ A convenience function for creating a horizontal docksplit.

    """
    kwargs.setdefault('orientation', 'horizontal')
    split = docksplit(*args, **kwargs)
    return split


def vdocksplit(*args, **kwargs):
    """ A convenience function for creating a vertical docksplit.

    """
    kwargs.setdefault('orientation', 'vertical')
    split = docksplit(*args, **kwargs)
    return split


def coerce_rect(value):
    """ Coerce a value to a Rect object.

    """
    if isinstance(value, (list, tuple)):
        return Rect(*value)
    msg = "unable to coerce '%s' to a Rect"
    raise TypeError(msg % type(value).__name__)


class dockarea(Atom):
    """ A layout node for declaring a dock layout area.

    """
    #: Whether or not the area is floating.
    floating = Bool(False)

    #: The geometry to apply to the area if it is floating.
    geometry = Coerced(Rect, (-1, -1, -1, -1), coercer=coerce_rect)

    #: The child layout node for the area.
    child = Value()

    @classmethod
    def from_dict(cls, dct):
        """ Create a dockarea layout from a layout dictionary.

        Parameters
        ----------
        dct : dict
            A layout dictionary of 'dockarea' type generated by a
            previous call to 'as_dict'.

        """
        child = dct['child']
        t = child['type']
        if t == 'dockitem':
            c = dockitem.from_dict(child)
        elif t == 'docktabs':
            c = docktabs.from_dict(child)
        elif t == 'docksplit':
            c = docksplit.from_dict(child)
        else:
            raise TypeError("invalid child type '%s'" % t)
        self = cls(c)
        self.floating = dct['floating']
        self.geometry = dct['geometry']
        return self

    def __init__(self, child, **metadata):
        """ Initialize a floatarea.

        Parameters
        ----------
        child : basestring, docksplit, docktabs, or dockitem
            The primary child layout to use for the float area.

        **metadata
            Additional configuration data for the layout.

        """
        super(dockarea, self).__init__(**metadata)
        if isinstance(child, basestring):
            child = dockitem(child)
        if not isinstance(child, (docksplit, docktabs, dockitem)):
            msg = "'s' is an invalid type for an area child"
            raise TypeError(msg % type(child).__name__)
        self.child = child

    def as_dict(self):
        """ Convert the area layout into a layout dictionary.

        """
        layout = {
            'type': 'dockarea',
            'floating': self.floating,
            'geometry': list(self.geometry),
            'child': self.child.as_dict(),
        }
        return layout


class docklayout(Atom):
    """ The toplevel layout node for declaring dock layouts.

    """
    #: The child layout areas to use with the dock layout.
    children = List()

    @classmethod
    def from_dict(cls, dct):
        """ Create a docklayout from a layout dictionary.

        Parameters
        ----------
        dct : dict
            A layout dictionary of 'docklayout' type generated by a
            previous call to 'as_dict'.

        """
        children = [dockarea.from_dict(d) for d in dct['children']]
        return cls(*children)

    def __init__(self, *children):
        """ Initialize a docklayout.

        Parameters
        ----------
        *children
            The child layout areas to use in the layout. These must
            be instances of 'dockarea', only one of which may be a
            non-floating area.

        """
        valid = []
        nonfloating = False
        for child in children:
            if not isinstance(child, dockarea):
                msg = "'s' is an invalid type for a docklayout child"
                raise TypeError(msg % type(child).__name__)
            if not child.floating:
                if nonfloating:
                    msg = "a docklayout can have at most 1 non-floating "
                    msg += "dock area"
                    raise TypeError(msg)
                nonfloating = True
            valid.append(child)
        self.children = valid

    def as_dict(self):
        """ Convert the dock layout into a layout dictionary.

        """
        layout = {
            'type': 'docklayout',
            'children': [c.as_dict() for c in self.children],
        }
        return layout
