##############################################################################
#
# 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.
#
##############################################################################
"""Modules with defered attributes

$Id: deferredmodule.py 70575 2006-10-08 13:33:58Z flox $
"""
import sys
import warnings
import zope.proxy


class Deferred(object):

    def __init__(self, name, specifier):
        self.__name__ = name
        self.specifier = specifier

    _import_chicken = {}, {}, ['*']

    def get(self):

        specifier = self.specifier
        if ':' in specifier:
            module, name = specifier.split(':')
        else:
            module, name = specifier, ''

        v = __import__(module, *self._import_chicken)
        if name:
            for n in name.split('.'):
                v = getattr(v, n)
        return v

class DeferredAndDeprecated(Deferred):

    def __init__(self, name, specifier, message):
        super(DeferredAndDeprecated, self).__init__(name, specifier)
        self.message = message

    def get(self):
        warnings.warn(
            self.__name__ + " is deprecated. " + self.message,
            DeprecationWarning, stacklevel=3)
        
        return super(DeferredAndDeprecated, self).get()


class ModuleProxy(zope.proxy.ProxyBase):
    __slots__ = ('__deferred_definitions__', )

    def __init__(self, module):
        super(ModuleProxy, self).__init__(module)
        self.__deferred_definitions__ = {}

    def __getattr__(self, name):
        try:
            get = self.__deferred_definitions__.pop(name)
        except KeyError:
            raise AttributeError, name
        v = get.get()
        setattr(self, name, v)
        return v

def initialize(level=1):
    __name__ = sys._getframe(level).f_globals['__name__']
    module = sys.modules[__name__]
    if not (type(module) is ModuleProxy):
        module = ModuleProxy(module)
        sys.modules[__name__] = module

    if level == 1:
        return
    return module

def define(**names):
    module = initialize(2)
    __deferred_definitions__ = module.__deferred_definitions__
    for name, specifier in names.iteritems():
        __deferred_definitions__[name] = Deferred(name, specifier)

def defineFrom(from_name, *names):
    module = initialize(2)
    __deferred_definitions__ = module.__deferred_definitions__
    for name in names:
        specifier = from_name + ':' + name
        __deferred_definitions__[name] = Deferred(name, specifier)

def deprecated(message, **names):
    module = initialize(2)
    __deferred_definitions__ = module.__deferred_definitions__
    for name, specifier in names.iteritems():
        __deferred_definitions__[name] = DeferredAndDeprecated(
            name, specifier, message)

def deprecatedFrom(message, from_name, *names):
    module = initialize(2)
    __deferred_definitions__ = module.__deferred_definitions__
    for name in names:
        specifier = from_name + ':' + name
        __deferred_definitions__[name] = DeferredAndDeprecated(
            name, specifier, message)
