##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""View support for adding and configuring utilities and adapters.

$Id: __init__.py 39064 2005-10-11 18:40:10Z philikon $
"""
from zope.component.interfaces import ISiteManager
from zope.security.proxy import removeSecurityProxy
from zope.app import zapi
from zope.app.container.browser.adding import Adding
from zope.app.i18n import ZopeMessageFactory as _
from zope.app.container.interfaces import INameChooser
from zope.app.component.interfaces.registration import ActiveStatus
from zope.app.component.interfaces.registration import InactiveStatus
from zope.app.component.interfaces import ILocalUtility
from zope.app.publisher.browser import BrowserView
from zope.app.component.interfaces import ISite
from zope.app.component.site import LocalSiteManager
from zope.component.exceptions import ComponentLookupError
from zope.component.interfaces import IFactory
from zope.interface.interfaces import IMethod
from zope.schema.interfaces import IField
from zope.app.interface.interfaces import IInterfaceBasedRegistry
from zope.app.component.interface import searchInterface
from zope.app.component.interface import getInterface
from zope.app.component.interface import provideInterface

class ComponentAdding(Adding):
    """Adding subclass used for registerable components."""

    menu_id = "add_component"

    def add(self, content):
        # Override so as to save a reference to the added object
        self.added_object = super(ComponentAdding, self).add(content)
        return self.added_object

    def nextURL(self):
        v = zapi.queryMultiAdapter(
            (self.added_object, self.request), name="registration.html")
        if v is not None:
            url = str(zapi.getMultiAdapter(
                (self.added_object, self.request), name='absolute_url'))
            return url + "/@@registration.html"

        return super(ComponentAdding, self).nextURL()

    def action(self, type_name, id=''):
        # For special case of that we want to redirect to another adding view
        # (usually another menu such as AddUtility)
        if type_name.startswith("../"):
            # Special case
            url = type_name
            if id:
                url += "?id=" + id
            self.request.response.redirect(url)
            return

        # Call the superclass action() method.
        # As a side effect, self.added_object is set by add() above.
        super(ComponentAdding, self).action(type_name, id)

    _addFilterInterface = None

    def addingInfo(self):
        # A site management folder can have many things. We only want 
        # things that implement a particular interface
        info = super(ComponentAdding, self).addingInfo()
        if self._addFilterInterface is None:
            return info
        out = []
        for item in info:
            extra = item.get('extra')
            if extra:
                factoryname = extra.get('factory')
                if factoryname:
                    factory = zapi.getUtility(IFactory, factoryname)
                    intf = factory.getInterfaces()
                    if not intf.extends(self._addFilterInterface):
                        # We only skip new addMenuItem style objects
                        # that don't implement our wanted interface.
                        continue

            out.append(item)

        return out


class UtilityAdding(ComponentAdding):
    """Adding subclass used for adding utilities."""

    menu_id = None
    title = _("Add Utility")

    _addFilterInterface = ILocalUtility

    def add(self, content):
        # Override so as to check the type of the new object.
        if not ILocalUtility.providedBy(content):
            raise TypeError("%s is not a local utility" % content)
        return super(UtilityAdding, self).add(content)

    def nextURL(self):
        v = zapi.queryMultiAdapter(
            (self.added_object, self.request), name="addRegistration.html")
        if v is not None:
            url = zapi.absoluteURL(self.added_object, self.request)
            return url + "/addRegistration.html"

        return super(UtilityAdding, self).nextURL()


class MakeSite(BrowserView):
    """View for converting a possible site to a site."""

    def addSiteManager(self):
        """Convert a possible site to a site

        >>> from zope.app.traversing.interfaces import IContainmentRoot
        >>> from zope.interface import implements

        >>> class PossibleSite(object):
        ...     implements(IContainmentRoot)
        ...     def setSiteManager(self, sm):
        ...         from zope.interface import directlyProvides
        ...         directlyProvides(self, ISite)


        >>> folder = PossibleSite()

        >>> from zope.publisher.browser import TestRequest
        >>> request = TestRequest()

        Now we'll make our folder a site:

        >>> MakeSite(folder, request).addSiteManager()

        Now verify that we have a site:

        >>> ISite.providedBy(folder)
        1

        Note that we've also redirected the request:

        >>> request.response.getStatus()
        302

        >>> request.response.getHeader('location')
        '++etc++site/@@SelectedManagementView.html'

        If we try to do it again, we'll fail:

        >>> MakeSite(folder, request).addSiteManager()
        Traceback (most recent call last):
        ...
        UserError: This is already a site

        """
        if ISite.providedBy(self.context):
            raise zapi.UserError('This is already a site')

        # We don't want to store security proxies (we can't,
        # actually), so we have to remove proxies here before passing
        # the context to the SiteManager.
        bare = removeSecurityProxy(self.context)
        sm = LocalSiteManager(bare)
        self.context.setSiteManager(sm)
        self.request.response.redirect(
            "++etc++site/@@SelectedManagementView.html")
