##############################################################################
#
# 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.
#
##############################################################################
"""Global components support

$Id: globalregistry.py 69983 2006-09-05 21:41:15Z ctheune $
"""
import types
from zope.interface import implements
from zope.interface.adapter import AdapterRegistry
from zope.deprecation.deprecation import deprecate, deprecated
from zope.component.registry import Components
from zope.component.interfaces import Invalid, IComponentLookup, IRegistry
from zope.component.interfaces import ComponentLookupError
from zope.interface.interfaces import ISpecification

def GAR(components, registryName):
    return getattr(components, registryName)

class GlobalAdapterRegistry(AdapterRegistry):
    """A global adapter registry

    This adapter registry's main purpose is to be picklable in combination
    with a site manager."""

    def __init__(self, parent, name):
        self.__parent__ = parent
        self.__name__ = name
        super(GlobalAdapterRegistry, self).__init__()

    def __reduce__(self):
        return GAR, (self.__parent__, self.__name__)

########################################################################
#
# BBB 2006/02/28 -- to be removed after 12 months

class _IGlobalSiteManager(IComponentLookup, IRegistry):

    def provideAdapter(required, provided, name, factory, info=''):
        """Register an adapter factory

        :Parameters:
          - `required`: a sequence of specifications for objects to be
             adapted.
          - `provided`: The interface provided by the adapter
          - `name`: The adapter name
          - `factory`: The object used to compute the adapter
          - `info`: Provide some info about this particular adapter.
        """

    def subscribe(required, provided, factory, info=''):
        """Register a subscriber factory

        :Parameters:
          - `required`: a sequence of specifications for objects to be
             adapted.
          - `provided`: The interface provided by the adapter
          - `name`: The adapter name
          - `factory`: The object used to compute the subscriber
          - `info`: Provide some info about this particular adapter.
        """

    def provideUtility(providedInterface, component, name='', info='',
                       strict=True):
        """Register a utility

        If strict is true, then the specified component *must* implement the
        `providedInterface`. Turning strict off is particularly useful for
        tests."""

#
########################################################################


class BaseGlobalComponents(Components):
    implements(_IGlobalSiteManager)

    def _init_registries(self):
        self.adapters = GlobalAdapterRegistry(self, 'adapters')
        self.utilities = GlobalAdapterRegistry(self, 'utilities')

    def __reduce__(self):
        # Global site managers are pickled as global objects
        return self.__name__

    ####################################################################
    #
    # BBB 2006/02/28 -- to be removed after 12 months

    @deprecate("The provideAdapter method of the global site manager has been "
               "deprecated. Use registerAdapter instead.")
    def provideAdapter(self, required, provided, name, factory, info=''):
        self.registerAdapter(factory, required, provided, name, info)

    @deprecate("The subscribe method of the global site manager has been "
               "deprecated. Use registerHandler or registerSubscriptionAdapter "
               "instead.")
    def subscribe(self, required, provided, factory, info=''):
        if provided is None:
            self.registerHandler(factory, required, u'', info)
        else:
            self.registerSubscriptionAdapter(factory, required, provided,
                                             info=info)

    @deprecate("The provideUtility method of the global site manager has been "
               "deprecated. Use registerUtility instead.")
    def provideUtility(self, providedInterface, component, name='', info='',
                       strict=True):
        if strict and not providedInterface.providedBy(component):
            raise Invalid("The registered component doesn't provide "
                          "the promised interface.")

        self.registerUtility(component, providedInterface, name, info)

    @deprecate("The registrations method of the global site manager has been "
               "deprecate. Use either registeredAdapters, registeredUtilities, "
               "or registeredSubscriptionAdapters instead.")
    def registrations(self):
        for reg in self.registeredAdapters():
            yield reg
        for reg in self.registeredSubscriptionAdapters():
            yield reg
        for reg in self.registeredHandlers():
            yield reg
        for reg in self.registeredUtilities():
            yield reg
    #
    ####################################################################    

base = BaseGlobalComponents('base')

from zope.testing.cleanup import addCleanUp
addCleanUp(lambda: base.__init__('base'))
del addCleanUp

globalSiteManager = base
def getGlobalSiteManager():
    return globalSiteManager

# The following APIs provide global registration support for Python code.
# We eventually want to deprecate these in favor of using the global
# component registry directly.

def provideUtility(component, provides=None, name=u''):
    base.registerUtility(component, provides, name, event=False)


def provideAdapter(factory, adapts=None, provides=None, name=''):
    base.registerAdapter(factory, adapts, provides, name, event=False)

def provideSubscriptionAdapter(factory, adapts=None, provides=None):
    base.registerSubscriptionAdapter(factory, adapts, provides, event=False)

def provideHandler(factory, adapts=None):
    base.registerHandler(factory, adapts, event=False)

import zope.component._api # see http://www.zope.org/Collectors/Zope3-dev/674
# Ideally, we will switch to an explicit adapter hook registration.  For now,
# if you provide an adapter, we want to make sure that the adapter hook is
# registered, and that registration depends on code in _api, which itself
# depends on code in this module.  So, for now, we do another of these nasty
# circular import workarounds.  See also standalonetests.py, as run by
# tests.py in StandaloneTests, for a test that fails without this hack, and
# succeeds with it.
