# -*- coding: utf-8 -*-
from .exc import FieldNotInstantiated
from . import controls
from .utils import Ordered
from .validators import required
from copy import deepcopy


missing = object()


def get_key(*args):
    '''Like dict.get but looks up keys in multiple dicts.

    :param key: Key to lookup
    :param dicts: Tuple of dicts to use in lookup
    :param default: If passed return this if lookup fails
    '''

    arglen = len(args)
    if arglen not in (2, 3):
        raise ValueError('Must pass at least two args...key and (dicts...)')
    elif arglen == 2:
        key, dicts = args
    else:
        key, dicts, default = args

    for d in dicts:
        value = d.get(key, missing)
        if value is not missing:
            return value

    if 'default' in locals():
        return default

    raise KeyError('{0} does not exist in {1}'.format(key, dicts))


class FieldType(Ordered):
    ''':class:`Form` calls the :meth:`create` to retrieve an appropriate
    control.

    :param nice_name: Nice nice_name of the field (str)
    :param labeled: Field Control has label (bool)
        Overrides the parent Forms labeled attribute for this field only
    :param label_on_top: Label appears on top of the field control (bool)
        Overrides the parent Forms label_on_top attribute for this field only
    :param default: Default value (str)
    '''

    control_cls = None
    control_defaults = None
    field_defaults = {
        'labeled': True,
        'label_on_top': True,
        'default': None,
        'validators': None
    }
    field_keys = ('labeled', 'label_on_top', 'default', 'validators')

    def __init__(self, nice_name, **kwargs):
        super(FieldType, self).__init__()

        self.nice_name = nice_name
        self.control_kwargs = {'name': nice_name}

        # Convert required keyword to required validator
        validators = list(kwargs.pop('validators', []))
        is_required = kwargs.pop('required', False)
        if is_required:
            validators.append(required)
        kwargs['validators'] = validators

        # Set instance attributes from field keys
        for key in self.field_keys:
            set_field_attribute = key in kwargs
            value = kwargs.pop(key, self.field_defaults[key])
            self.control_kwargs[key] = value

            if set_field_attribute:
                setattr(self, key, value)
            else:
                setattr(self, key, None)

        if self.control_defaults:  # If the control has defaults, get em
            for key in self.control_defaults.keys():
                value = kwargs.get(key, self.control_defaults[key])
                self.control_kwargs[key] = value

    def __repr__(self):
        r = '<{}>(nice_name={}, default={})'
        return r.format(self.__class__.__name__, self.nice_name, self.default)

    def create(self):
        return self.control_cls(**self.control_kwargs)


def create_fieldtype(clsname, control_cls, control_defaults=None,
                     field_defaults=None, bases=(FieldType,)):
    '''Convenience function to create a new subclass of :class:`FieldType`.
    *control_defaults* are passed on to *control_cls*. *field_defaults* are
    used as the values of attributes on the returned :class:`FieldType`
    subclass. The keys for both control_defaults and field_defaults are looked
    up in __init__ kwargs param first.

    :param control_cls: PySide widget used to create the control.
    :param control_defaults: Default kwargs to pass to control_cls
    :param field_defaults: Default attr values (labeled, label_on_top, default)

    .. note::

        *control_cls* must  implement the :class:`ControlType` interface
    '''

    bdicts = [b.__dict__ for b in bases]
    orig_defaults = get_key('field_defaults', bdicts)

    if field_defaults:
        defaults = deepcopy(orig_defaults)
        defaults.update(field_defaults)
        field_defaults = defaults
    else:
        field_defaults = orig_defaults

    attrs = {
        'control_cls': control_cls,
        'control_defaults': control_defaults,
        'field_defaults': field_defaults,
    }
    return type(clsname, bases, attrs)


ListField = create_fieldtype(
    'ListField',
    control_cls=controls.ListControl,
    control_defaults={'options': None}
)

BoolField = create_fieldtype(
    'BoolField',
    control_cls=controls.BoolControl,
    field_defaults={'label_on_top': False}
)

StringField = create_fieldtype(
    'StringField',
    control_cls=controls.StringControl,
)

IntField = create_fieldtype(
    'IntField',
    control_cls=controls.IntControl,
    control_defaults={'range': None},
)

FloatField = create_fieldtype(
    'FloatField',
    control_cls=controls.FloatControl,
    control_defaults={'range': None},
)

Int2Field = create_fieldtype(
    'Int2Field',
    control_cls=controls.Int2Control,
    control_defaults={'range1': None, 'range2': None},
)

Float2Field = create_fieldtype(
    'Float2Field',
    control_cls=controls.Float2Control,
    control_defaults={'range1': None, 'range2': None},
)

IntOptionField = create_fieldtype(
    'IntOptionField',
    control_cls=controls.IntOptionControl,
    control_defaults={'options': None},
)

StringOptionField = create_fieldtype(
    'StringOptionField',
    control_cls=controls.StringOptionControl,
    control_defaults={'options': None},
)

ButtonOptionField = create_fieldtype(
    'ButtonOptionField',
    control_cls=controls.ButtonOptionControl,
    control_defaults={'options': None},
)

IntButtonOptionField = create_fieldtype(
    'IntButtonOptionField',
    control_cls=controls.IntButtonOptionControl,
    control_defaults={'options': None},
)

FileField = create_fieldtype(
    'FileField',
    control_cls=controls.FileControl,
    control_defaults={'caption': None, 'filters': None},
)

FolderField = create_fieldtype(
    'FolderField',
    control_cls=controls.FolderControl,
    control_defaults={'caption': None, 'filters': None},
)

SaveFileField = create_fieldtype(
    'SaveFileField',
    control_cls=controls.SaveFileControl,
    control_defaults={'caption': None, 'filters': None},
)

ImageField = create_fieldtype(
    'ImageField',
    control_cls=controls.ImageControl,
)

TextField = create_fieldtype(
    'TextField',
    control_cls=controls.TextControl,
)
InfoField = create_fieldtype(
    'InfoField',
    control_cls=controls.InfoControl,
    control_defaults={'text': None, 'align': 'left'},
    field_defaults={'labeled': False},
)


field_map = {cls.__name__: cls for cls in FieldType.__subclasses__()}
type_map = {
    'image': ImageField,
    'folder': FolderField,
    'text': TextField,
    'file': FileField,
    'str': StringField,
    '(bool,)': ButtonOptionField,
    '(int,)': IntOptionField,
    '(str,)': StringOptionField,
    'int': IntField,
    'float': FloatField,
    '(int, int)': Int2Field,
    '(float, float)': Float2Field,
    'bool': BoolField,
    'list': ListField,
    'info': InfoField,
    str: StringField,
    (bool,): ButtonOptionField,
    (int,): IntOptionField,
    (str,): StringOptionField,
    int: IntField,
    float: FloatField,
    (int, int): Int2Field,
    (float, float): Float2Field,
    bool: BoolField,
    list: ListField,
}
