##############################################################################
#
# Copyright (c) 2007 Zope Foundation 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.
#
##############################################################################
"""Error Views Implementation

$Id$
"""
__docformat__ = "reStructuredText"
import os

import zope.component
import zope.interface
import zope.schema
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
from zope.pagetemplate.interfaces import IPageTemplate

import z3c.form
from z3c.form import interfaces
from z3c.form import util
from z3c.form import value
from z3c.form.i18n import MessageFactory as _


ErrorViewMessage = value.StaticValueCreator(
    discriminators=('error', 'request', 'widget', 'field', 'form', 'content')
)

ComputedErrorViewMessage = value.ComputedValueCreator(
    discriminators=('error', 'request', 'widget', 'field', 'form', 'content')
)


def ErrorViewDiscriminators(
        errorView,
        error=None,
        request=None,
        widget=None,
        field=None,
        form=None,
        content=None):
    zope.component.adapter(
        util.getSpecification(error),
        util.getSpecification(request),
        util.getSpecification(widget),
        util.getSpecification(field),
        util.getSpecification(form),
        util.getSpecification(content))(errorView)


@zope.interface.implementer(interfaces.IErrorViewSnippet)
class ErrorViewSnippet:
    """Error view snippet."""
    zope.component.adapts(
        zope.schema.ValidationError, None, None, None, None, None)

    def __init__(self, error, request, widget, field, form, content):
        self.error = self.context = error
        self.request = request
        self.widget = widget
        self.field = field
        self.form = form
        self.content = content

    def createMessage(self):
        return self.error.doc()

    def update(self):
        value = zope.component.queryMultiAdapter(
            (self.context, self.request, self.widget,
             self.field, self.form, self.content),
            interfaces.IValue, name='message')
        if value is not None:
            self.message = value.get()
        else:
            self.message = self.createMessage()

    def render(self):
        template = zope.component.getMultiAdapter(
            (self, self.request), IPageTemplate)
        return template(self)

    def __repr__(self):
        return '<{} for {}>'.format(
            self.__class__.__name__, self.error.__class__.__name__)


class ValueErrorViewSnippet(ErrorViewSnippet):
    """An error view for ValueError."""
    zope.component.adapts(
        ValueError, None, None, None, None, None)

    defaultMessage = _('The system could not process the given value.')

    def createMessage(self):
        return self.defaultMessage


class InvalidErrorViewSnippet(ErrorViewSnippet):
    """Error view snippet."""
    zope.component.adapts(
        zope.interface.Invalid, None, None, None, None, None)

    def createMessage(self):
        return self.error.args[0]


class MultipleErrorViewSnippet(ErrorViewSnippet):
    """Error view snippet for multiple errors."""
    zope.component.adapts(
        interfaces.IMultipleErrors, None, None, None, None, None)

    def update(self):
        pass

    def render(self):
        return ''.join([view.render() for view in self.error.errors])


@zope.interface.implementer(interfaces.IMultipleErrors)
class MultipleErrors(Exception):
    """An error that contains many errors"""

    def __init__(self, errors):
        self.errors = errors


class ErrorViewTemplateFactory:
    """Error view template factory."""

    template = None

    def __init__(self, filename, contentType='text/html'):
        self.template = ViewPageTemplateFile(
            filename, content_type=contentType)

    def __call__(self, errorView, request):
        return self.template


# Create the standard error view template
StandardErrorViewTemplate = ErrorViewTemplateFactory(
    os.path.join(os.path.dirname(z3c.form.__file__), 'error.pt'), 'text/html')
zope.component.adapter(
    interfaces.IErrorViewSnippet, None)(StandardErrorViewTemplate)
zope.interface.implementer(IPageTemplate)(StandardErrorViewTemplate)
