# -*- 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_list(elementType):
    # These functions will be returned as class methods
    def new(cls, *args):
        return list.__new__(cls, args)
    def check(self, *args):
        for it in args:
            if not isinstance(it, self.elementType):
                raise TypeError, 'elements must be of type "%s", but received %s' \
                      % (self.elementType.__name__, str(type(it)))
    def init(self, *args):
        self.check(*args)
    def add(self, y):
        self.check(*y)
        list.__add__(self, y)
    def iadd(self, y):
        self.check(*y)
        list.__iadd__(self, y)
    def setitem(self, index, value):
        self.check(value)
        list.__setitem__(self, index, value)
    def setslice(self, i, j, values):
        self.check(*values)
        list.__setslice__(self, i, j, values)
    def append(self, value):
        self.check(value)
        list.append(self, value)
    def extend(self, values):
        self.check(*value)
        list.extend(self, value)
    def insert(self, value):
        self.check(value)
        list.insert(self, index, value)
    # Class name
    name = 'list_of_' + elementType.__name__
    # Class docstring
    doc = '%s([arg1 [, arg2 ...]])\n\n' \
          'a list whose elements are type-checked to ensure that they\n' \
          'are of type "%s"' 
    doc = doc % (name, elementType.__name__)
    # Class members
    members = dict(__doc__      = doc,
                   elementType  = elementType,
                   __new__      = new,
                   __init__     = init,
                   __add__      = add,
                   __iadd__     = iadd,
                   __setitem__  = setitem,
                   __setslice__ = setslice,
                   append       = append,
                   extend       = extend,
                   insert       = insert)
    # Return the manufactured class
    return type(name, (list,), members)

#
# Create a series of typed list classes for each of the standard python types
list_of_bool  = typed_list(bool )
list_of_int   = typed_list(int  )
list_of_float = typed_list(float)
list_of_str   = typed_list(str  )
list_of_tuple = typed_list(tuple)
list_of_list  = typed_list(list )
list_of_dict  = typed_list(dict )
