##############################################################################
#
# Copyright (c) 2006 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Custom form widgets.

$Id: widgets.py 77186 2007-06-28 19:06:19Z yuppie $
"""

from zope.app.form import InputWidget
from zope.app.form.browser import BrowserWidget
from zope.app.form.browser import MultiSelectSetWidget
from zope.app.form.browser import RadioWidget
from zope.app.form.browser import TextWidget
from zope.app.form.browser import TextAreaWidget
from zope.app.form.interfaces import ConversionError
from zope.app.form.interfaces import IInputWidget
from zope.app.form.interfaces import WidgetInputError
from zope.component import adapts
from zope.component import getUtility
from zope.interface import implementsOnly
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.schema import Set
from zope.schema import Tuple
from zope.schema.interfaces import ISet
from zope.schema.interfaces import ITuple

from Products.CMFCore.interfaces import IMetadataTool
from Products.CMFDefault.exceptions import IllegalHTML
from Products.CMFDefault.utils import scrubHTML
from Products.CMFDefault.utils import Message as _
from schema import IEmailLine
from vocabulary import SimpleVocabulary


# generic widgets

def ChoiceRadioWidget(field, request):
    return RadioWidget(field, field.vocabulary, request)


class EmailInputWidget(TextWidget):

    implementsOnly(IInputWidget)
    adapts(IEmailLine, IBrowserRequest)

    def _toFieldValue(self, input):
        if input == self._missing:
            return self.context.missing_value

        try:
            return str(input.strip())
        except (AttributeError, UnicodeEncodeError), err:
            raise ConversionError(_(u'Invalid email address.'), err)


class TextInputWidget(TextAreaWidget):

    def getInputValue(self):
        value = super(TextInputWidget, self).getInputValue()
        if value:
            try:
                value = scrubHTML(value)
            except IllegalHTML, err:
                self._error = WidgetInputError(self.context.__name__,
                                               self.label, err.args[0])
                raise self._error
        return value


class TupleTextAreaWidget(TextAreaWidget):

    implementsOnly(IInputWidget)
    adapts(ITuple, IBrowserRequest)

    def __init__(self, context, field, request):
        super(TupleTextAreaWidget, self).__init__(context, request)

    def _toFieldValue(self, input):
        input = super(TupleTextAreaWidget, self)._toFieldValue(input)
        if isinstance(input, basestring):
            input = tuple([ l.strip()
                            for l in input.splitlines() if l.strip() ])

        if input == ():
            return self.context.missing_value

        return input

    def _toFormValue(self, value):
        if value is not None:
            value = u'\n'.join(value)
        return super(TupleTextAreaWidget, self)._toFormValue(value)


def TupleInputWidget(field, request):
    return TupleTextAreaWidget(field, field.value_type, request)


# special widgets

class SubjectInputWidget(InputWidget, BrowserWidget):

    implementsOnly(IInputWidget)
    adapts(ISet, IBrowserRequest)

    def __init__(self, context, request):
        super(SubjectInputWidget, self).__init__(context, request)
        self._widgets = {}
        self._widget_keys = (1,)
        self.vocabulary = ()
        context = getattr(self.context.context, 'context',
                          self.context.context)
        mdtool = getUtility(IMetadataTool)
        allowed_subjects = mdtool.listAllowedSubjects(context)
        if allowed_subjects:
            items = [ (str(v), unicode(v), unicode(v))
                      for v in allowed_subjects ]
            self.vocabulary = SimpleVocabulary.fromTitleItems(items)
            self._widget_keys = (0, 1)

    def _getWidget(self, i):
        if i not in self._widgets:
            if i == 0:
                field = Set(__name__='1').bind(self.context)
                widget = MultiSelectSetWidget(field, self.vocabulary,
                                              self.request)
                widget.setPrefix(self.name)
                widget.empty_marker_name = widget.name + "-empty-marker"
                widget.size = 3
                self._widgets[0] = widget
            elif i == 1:
                field = Tuple(__name__='', required=False).bind(self.context)
                widget = TupleInputWidget(field, self.request)
                widget.name = self.name
                widget.height = self.vocabulary and 2 or 6
                self._widgets[1] = widget
        return self._widgets[i]

    def getInputValue(self):
        value = set()
        for k in self._widget_keys:
            value = set(self._getWidget(k).getInputValue() or ())|value
        return value

    def hasInput(self):
        value = False
        for k in self._widget_keys:
            value = self._getWidget(k).hasInput() or value
        return value

    def __call__(self):
        values = {0: [], 1: []}
        if not self._renderedValueSet():
            value = self.getInputValue()
        else:
            value = self._data
        for item in value or ():
            if item in self.vocabulary:
                values[0].append(item)
            else:
                values[1].append(item)
        for k in self._widget_keys:
            self._getWidget(k).setRenderedValue(set(values[k]))
        return '\n'.join([ self._getWidget(k)() for k in self._widget_keys ])
