import re
import datetime

from pyramid.i18n import TranslationString as _
from colander import (
    deferred,
    SchemaNode,
    String,
    OneOf,
    Range,
    Sequence,
    Length,
    ContainsOnly,
    Int,
    Decimal,
    Boolean,
    Regex,
    Email,
    Date,
    DateTime,
    Mapping,
    drop,
)

from . import registry, TypeField, TypeFieldNode
from .json import JSONList


__all__ = ['IntField', 'StringField', 'RangeField',
           'RegexField', 'EmailField', 'URLField',
           'EnumField', 'ChoicesField', 'DecimalField',
           'DateField', 'DateTimeField', 'GroupField',
           'AnnotationField']


@registry.add('int')
class IntField(TypeField):
    node = Int
    hint = _('An integer')


@registry.add('string')
class StringField(TypeField):
    node = String
    hint = _('A set of characters')


@registry.add('text')
class TextField(TypeField):
    node = String
    hint = _('A text')


@registry.add('annotation')
class AnnotationField(TypeField):
    required = False

    @classmethod
    def definition(cls, **kwargs):
        schema = SchemaNode(Mapping(unknown="preserve"))

        schema.add(SchemaNode(String(), name='label', missing=u''))
        schema.add(SchemaNode(String(), name='type',
                              validator=OneOf(["annotation"])))
        return schema


@registry.add('decimal')
class DecimalField(TypeField):
    node = Decimal
    hint = _('A decimal number')


@registry.add('boolean')
class BooleanField(TypeField):
    node = Boolean
    hint = _('True or false')


@registry.add('enum')
class EnumField(TypeField):
    node = String
    hint = _('A choice among values')

    @classmethod
    def definition(cls, **kwargs):
        schema = super(EnumField, cls).definition()
        schema.add(SchemaNode(Sequence(), SchemaNode(String()),
                              name='choices', validator=Length(min=1)))
        return schema

    @classmethod
    def validation(cls, **kwargs):
        kwargs['validator'] = OneOf(kwargs['choices'])
        return super(EnumField, cls).validation(**kwargs)


@registry.add('choices')
class ChoicesField(TypeField):
    node = JSONList
    hint = _('Some choices among values')

    @classmethod
    def definition(cls, **kwargs):
        schema = super(ChoicesField, cls).definition()
        schema.add(SchemaNode(Sequence(), SchemaNode(String()),
                              name='choices', validator=Length(min=1)))
        return schema

    @classmethod
    def validation(cls, **kwargs):
        kwargs['validator'] = ContainsOnly(kwargs['choices'])
        return super(ChoicesField, cls).validation(**kwargs)


@registry.add('range')
class RangeField(TypeField):
    node = Int
    hint = _('A number with limits')

    @classmethod
    def definition(cls, **kwargs):
        schema = super(RangeField, cls).definition()
        schema.add(SchemaNode(Int(), name='min'))
        schema.add(SchemaNode(Int(), name='max'))
        return schema

    @classmethod
    def validation(cls, **kwargs):
        kwargs['validator'] = Range(min=kwargs.get('min'),
                                    max=kwargs.get('max'))
        return super(RangeField, cls).validation(**kwargs)


@registry.add('regex')
class RegexField(TypeField):
    """Allows to validate a field with a python regular expression."""
    node = String
    hint = _('A string matching a pattern')