from Products.CMFPlone.utils import safe_callable
from datetime import datetime
from ftw.datepicker import _
from ftw.datepicker.interfaces import IDateTimePickerWidget
from z3c.form import converter
from z3c.form.converter import FormatterValidationError
from zope.component import adapts
from zope.component import getMultiAdapter
from zope.component.hooks import getSite
from zope.i18n import translate
from zope.schema.interfaces import IDate
from zope.schema.interfaces import IDatetime
import pytz


JS_DATE_FORMAT_MAPPER = {'d': '%d', 'm': '%m', 'Y': '%Y',
                         'H': '%H', 'i': '%M'}


def transform_js_format(js_format):
    # Datagrid may ship, more than one with the same id. example TT rows.
    if not js_format:
        js_format = "d.m.Y H:i"
    js_format = isinstance(js_format, list) and js_format[0] or js_format
    for old, new in JS_DATE_FORMAT_MAPPER.items():
        if new not in js_format:
            js_format = js_format.replace(old, new)
    return js_format


class BaseDateConverter(converter.BaseDataConverter):

    def __init__(self, field, widget):
        super(BaseDateConverter, self).__init__(field, widget)
        portal = getSite()
        portal_state = getMultiAdapter((portal, portal.REQUEST),
                                       name=u'plone_portal_state')
        current_language = portal_state.language()
        widget_format = self.widget.config.get('formats').get(
            current_language,
            self.widget.config.get('formats').get(current_language[:2]))
        self.transformed_format = transform_js_format(widget_format)

    def toWidgetValue(self, value):
        if value is self.field.missing_value:
            return u''

        return value.strftime(self.transformed_format)

    def toFieldValue(self, value):
        if value == u'':
            return None

        try:
            datetime_obj = datetime.strptime(value, self.transformed_format)

            if datetime_obj.year >= 1900:
                # Timezone implementation copied from
                # plone.app.z3cform.converters#DatetimeWidgetConverter
                default_zone = self.widget.default_timezone
                zone = (default_zone(self.widget.context)
                        if safe_callable(default_zone)
                        else default_zone)

                if zone:
                    tzinfo = pytz.timezone(zone)
                    datetime_obj = tzinfo.localize(datetime_obj)

                return datetime_obj
            else:
                error = translate(_(u'error_datetime_min_year',
                                    default=u'Min. year is 1900'),
                                  context=self.widget.request)
                raise FormatterValidationError(error, value)
        except ValueError, err:
            pass
        error = translate(_("error_datetime_parse",
                            default=err.args[0],
                            mapping={'input': value,
                                     'format': self.transformed_format}),
                          context=self.widget.request)
        raise FormatterValidationError(error, value)


class DateTimeDataConverter(BaseDateConverter):

    adapts(IDatetime, IDateTimePickerWidget)


class DateDataConverter(BaseDateConverter):

    def __init__(self, field, widget):
        super(DateDataConverter, self).__init__(field, widget)
        self.transformed_format = self.transformed_format.split(" ")[0]

    adapts(IDate, IDateTimePickerWidget)

    def toFieldValue(self, value):
        value = super(DateDataConverter, self).toFieldValue(value)
        if isinstance(value, datetime):
            return value.date()
        return
