##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
#
##############################################################################
"""Collect some policies for s few built-in container objects.

   This module defines a registry, ContainerAssertions, that contains
   some data that is used by the zope security policy and by zope
   guards when considering whether to allow access to objects.

   The zope security policy and the zope guards use this data in
   different ways.  The source code for those modules is the best
   source of documentation for their use. :(

   The requirements for the values of ContainerAssertions is provided
   here.

   The keys of ContainerAssertions are built-in types.

   The values must be one of:

   1 -- In this case access to attributes of instances of the type are
        always allowed.  Access to items may be allowed, depending on
        the item type and value. (Use the source.)

   a callable -- In this case, the callable will be called with the
        attribute name and value and should return a true callable or
        1. If 1 is returned, then access may be granted, otherwise the
        second callable will be called with the original object, and
        the attribute name, and should return an object that is
        returned as the value of the attribute.


$Id: SimpleObjectPolicies.py,v 1.12.70.5 2004/01/27 21:49:04 fdrake Exp $
"""

_noroles = [] # this is imported from various places

import Record

# Allow access to unprotected attributes
Record.Record.__allow_access_to_unprotected_subobjects__=1


ContainerAssertions={
    type(()): 1,
    type(''): 1,
    type(u''): 1,
    }

class _dummy_class: pass

from DocumentTemplate.DT_Util import TemplateDict
# Temporarily create a DictInstance so that we can mark its type as
# being a key in the ContainerAssertions.
templateDict = TemplateDict()
try:
    dictInstance = templateDict(dummy=1)[0]
    if type(dictInstance) is not type(_dummy_class()):
        ContainerAssertions[type(dictInstance)]=1
except:
    # Hmm, this may cause _() and _.namespace() to fail.
    # What to do?
    pass

Containers = ContainerAssertions.get

def allow_type(Type, allowed=1):
    """Allow a type and all of its methods and attributes to be used from
    restricted code.  The argument Type must be a type."""
    if type(Type) is not type:
        raise ValueError, "%s is not a type" % `Type`
    if hasattr(Type, '__roles__'):
        raise ValueError, "%s handles its own security" % `Type`
    if not (isinstance(allowed, int) or isinstance(allowed, dict)):
        raise ValueError, "The 'allowed' argument must be an int or dict."
    ContainerAssertions[Type] = allowed

#
#   WAAAA!
#
from BTrees.OOBTree import OOBTree, OOBucket, OOSet
from BTrees.OIBTree import OIBTree, OIBucket, OISet
from BTrees.IOBTree import IOBTree, IOBucket, IOSet
from BTrees.IIBTree import IIBTree, IIBucket, IISet

for tree_type, has_values in [(OOBTree, 1),
                              (OOBucket, 1),
                              (OOSet, 0),
                              (OIBTree, 1),
                              (OIBucket, 1),
                              (OISet, 0),
                              (IOBTree, 1),
                              (IOBucket, 1),
                              (IOSet, 0),
                              (IIBTree, 1),
                              (IIBucket, 1),
                              (IISet, 0),
                             ]:
    tree = tree_type()
    key_type = type(tree.keys())

    if key_type is not list: # lists have their own declarations
        allow_type(key_type)

    if has_values:
        assert key_type is type(tree.values())
        assert key_type is type(tree.items())
