# -*- python -*-

# @HEADER
# ***********************************************************************
#
#          PyTrilinos: Python Interfaces to Trilinos Packages
#                 Copyright (2014) Sandia Corporation
#
# Under the terms of Contract DE-AC04-94AL85000 with Sandia
# Corporation, the U.S. Government retains certain rights in this
# software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the Corporation nor the names of the
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Questions? Contact William F. Spotz (wfspotz@sandia.gov)
#
# ***********************************************************************
# @HEADER

#
# Define the class factory function
def typed_dict(keyType, valueType):
    # Class name
    name = 'dict_of_' + keyType.__name__ + '_to_' + valueType.__name__
    # Class docstring
    if isinstance("", keyType):
        doc = '%s([dict] [key=value, ...])\n\n'
    else:
        doc = '%s([dict])\n\n'
    doc += 'a dictionary whose keys are restricted to type "%s"\n'\
           'and values are of type "%s"' 
    doc = doc % (name, keyType.__name__, valueType.__name__)
    # These functions will be returned as class methods
    def new(cls, source=None, **kwargs):
        return dict.__new__(cls)
    def init(self, source=None, **kwargs):
        if source:
            self.update(source)
        if kwargs:
            self.update(kwargs)
    def setitem(self, key, value):
        if not isinstance(key, self.keyType):
            raise TypeError, 'Expected key of type "%s", got "%s"' \
                  % (self.keyType.__name__, type(key).__name__)
        if not isinstance(value, self.valueType):
            raise TypeError, 'Expected value of type "%s", got "%s"' \
                  % (self.valueType.__name__, type(value).__name__)
        dict.__setitem__(self, key, value)
    def update(self, other):
        for key in other:
            self.__setitem__(key, other[key])
    def fromkeys(self, seq, value=None):
        for key in seq:
            self.__setitem__(key, value)
    def setdefault(self, key, default=None):
        try:
            return self.__getitem__(key)
        except KeyError:
            self.__setitem__(key, default)
            return default
    # Class members
    members = dict(__doc__     = doc,
                   keyType     = keyType,
                   valueType   = valueType,
                   __new__     = new,
                   __init__    = init,
                   __setitem__ = setitem,
                   update      = update,
                   fromkeys    = fromkeys,
                   setdefault  = setdefault)
    # Return the manufactured class
    return type(name, (dict,), members)
