##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Local utility registration

$Id: utility.py 67820 2006-05-02 09:21:45Z philikon $
"""
from zope.interface import implements
from zope.component import getGlobalSiteManager
from zope.component.interfaces import ComponentLookupError
from zope.app.component import getNextSiteManager

from Acquisition import aq_base
from OFS.Folder import Folder
from Products.Five.site.interfaces import IFiveUtilityRegistry

class SimpleLocalUtilityRegistry(object):
    implements(IFiveUtilityRegistry)

    def __init__(self, context):
        self.context = context
        # make {get|query}NextSiteManager() work without having to
        # resort to Zope 2 acquisition
        self.__parent__ = self.context.getSiteManager()

    @property
    def next(self):
        try:
            return getNextSiteManager(self)
        except ComponentLookupError:
            return getGlobalSiteManager()

    def getUtility(self, interface, name=''):
        """See IFiveUtilityRegistry interface
        """
        c = self.queryUtility(interface, name)
        if c is not None:
            return c
        raise ComponentLookupError(interface, name)

    def queryUtility(self, interface, name='', default=None):
        """See IFiveUtilityRegistry interface
        """
        if getattr(aq_base(self.context), 'utilities', None) is not None:
            for id, utility in self.context.utilities.objectItems():
                if interface.providedBy(utility):
                    if id.find('-') != -1:
                        prefix, utility_name = id.split('-', 1)
                    else:
                        utility_name = ''
                    if name == utility_name:
                        return utility
        return self.next.queryUtility(interface, name, default)

    def getUtilitiesFor(self, interface):
        names = []
        if getattr(aq_base(self.context), 'utilities', None) is not None:
            for id, utility in self.context.utilities.objectItems():
                if interface.providedBy(utility):
                    if id.find('-') != -1:
                        prefix, name = id.split('-', 1)
                    else:
                        name = ''
                    names.append(name)
                    yield (name, utility)
        for name, utility in self.next.getUtilitiesFor(interface):
            if name not in names:
                yield name, utility

    def getAllUtilitiesRegisteredFor(self, interface):
        # This also supposedly returns "overridden" utilities, but we don't
        # keep them around. It also does not return the name-value pair that
        # getUtilitiesFor returns.
        if getattr(aq_base(self.context), 'utilities', None) is not None:
            for utility in self.context.utilities.objectValues():
                if interface.providedBy(utility):
                    yield utility
        for utility in self.next.getAllUtilitiesRegisteredFor(interface):
            yield utility

    def registerUtility(self, interface, utility, name=''):
        # I think you are *really* supposed to:
        # 1. Check if there is a "registrations" object for utilities.
        # 2. If not create one.
        # 3. Get it.
        # 4. Create a registration object for the utility.
        # 5. Rgister the registration object in the registrations.
        # But that is quite complex, and Jim sais he wants to change that
        # anyway, and in any case the way you would normally do this in Zope3
        # and Five would probably differ anyway, so, here is this new
        # Five-only, easy to use method!

        if getattr(aq_base(self.context), 'utilities', None) is None:
            self.context._setObject('utilities', Folder('utilities'))
        utilities = self.context.utilities

        if name == '':
            # Singletons. Only one per interface allowed, so, let's call it
            # by the interface.
            id = interface.getName()
        else:
            id = interface.getName() + '-' + name

        if id in utilities.objectIds():
            raise ValueError("There is already a utility registered for "
                             "%s with the name '%s'" % (interface.getName(),
                                                        name))
        utilities._setObject(id, utility)
