#!/usr/bin/env python
#############################################################################
# Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999, 2000
# All Rights Reserved.
#
# The software contained on this media is the property of the DSTC Pty
# Ltd.  Use of this software is strictly in accordance with the
# license agreement in the accompanying LICENSE.HTML file.  If your
# distribution of this software does not contain a LICENSE.HTML file
# then you have no rights to use this software in any manner and
# should contact DSTC at the address below to determine an appropriate
# licensing arrangement.
# 
#      DSTC Pty Ltd
#      Level 7, GP South
#      Staff House Road
#      University of Queensland
#      St Lucia, 4072
#      Australia
#      Tel: +61 7 3365 4310
#      Fax: +61 7 3365 4311
#      Email: enquiries@dstc.edu.au
# 
# This software is being provided "AS IS" without warranty of any
# kind.  In no event shall DSTC Pty Ltd be liable for damage of any
# kind arising out of or in connection with the use or performance of
# this software.
#
# Project:      Fnorb
# File:         $Source: /projects/fnorb/Fnorb-1.1/orb/RCS/TypeCode.py,v $
# Version:      @(#)$RCSfile: TypeCode.py,v $ $Revision: 1.33 $
#
#############################################################################
""" Implementation of CORBA TypeCodes.

This module is actually part of the CORBA module and is intended to be
imported into 'CORBA.py' using the statement 'from TypeCode import *'.

"""


# Standard/built-in modules.
import new, types

# Fnorb modules.
import fnorb_thread
import CORBA, IOP, Limits, OctetStream, TypeManager, ThreadSpecificData, Util
import Fnorb

# Fnorb extension modules.
import cdr

import sys


# Kinds of TypeCodes.
tk_null        = Util.EnumMember('tk_null',         0)
tk_void        = Util.EnumMember('tk_void',         1)
tk_short       = Util.EnumMember('tk_short',        2)
tk_long        = Util.EnumMember('tk_long',         3)
tk_ushort      = Util.EnumMember('tk_ushort',       4)
tk_ulong       = Util.EnumMember('tk_ulong',        5)
tk_float       = Util.EnumMember('tk_float',        6)
tk_double      = Util.EnumMember('tk_double',       7)
tk_boolean     = Util.EnumMember('tk_boolean',      8)
tk_char        = Util.EnumMember('tk_char',         9)
tk_octet       = Util.EnumMember('tk_octet',        10)
tk_any         = Util.EnumMember('tk_any',          11)
tk_TypeCode    = Util.EnumMember('tk_TypeCode',     12)
tk_Principal   = Util.EnumMember('tk_Principal',    13)
tk_objref      = Util.EnumMember('tk_objref',       14)
tk_struct      = Util.EnumMember('tk_struct',       15)
tk_union       = Util.EnumMember('tk_union',        16)
tk_enum        = Util.EnumMember('tk_enum',         17)
tk_string      = Util.EnumMember('tk_string',       18)
tk_sequence    = Util.EnumMember('tk_sequence',     19)
tk_array       = Util.EnumMember('tk_array',        20)
tk_alias       = Util.EnumMember('tk_alias',        21)
tk_except      = Util.EnumMember('tk_except',       22)
tk_longlong    = Util.EnumMember('tk_longlong',     23)
tk_ulonglong   = Util.EnumMember('tk_ulonglong',    24)
tk_longdouble  = Util.EnumMember('tk_longdouble',   25)
tk_wchar       = Util.EnumMember('tk_wchar',        26)
tk_wstring     = Util.EnumMember('tk_wstring',      27)
tk_fixed       = Util.EnumMember('tk_fixed',        28)

TCKind         = [tk_null,      tk_void,       tk_short,  tk_long,
		  tk_ushort,    tk_ulong,      tk_float,  tk_double,
		  tk_boolean,   tk_char,       tk_octet,  tk_any,    
		  tk_TypeCode,  tk_Principal,  tk_objref, tk_struct,
		  tk_union,     tk_enum,       tk_string, tk_sequence,
		  tk_array,     tk_alias,      tk_except, tk_longlong,
		  tk_ulonglong, tk_longdouble, tk_wchar,  tk_wstring,
		  tk_fixed]


class TypeCode:
    """ Base class for TypeCodes. """

    # Exceptions.
    class Bounds(CORBA.UserException): pass
    class BadKind(CORBA.UserException): pass

    def __init__(self, kind):
	""" Constructor. """

	self._kind = kind
	return

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	return cmp(self._kind, other._kind)

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._kind,)

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def equal(self, other):
	""" Compare TypeCodes. """

	return cmp(self, other)

    def kind(self):
	""" Return the TypeCode's kind. """

	return self._kind

    def id(self):
	""" Return the TypeCode's repository id. """

	raise TypeCode.BadKind()

    def name(self):
	""" Return the TypeCode's repository name. """

	raise TypeCode.BadKind()

    def member_count(self):
	""" Return the number of members in the TypeCode. """

	raise TypeCode.BadKind()

    def member_name(self, index):
	""" Return the name of the index'th member!. """

	raise TypeCode.BadKind()

    def member_type(self, index):
	""" Return the TypeCode of the index'th member!. """

	raise TypeCode.BadKind()

    def member_label(self, index):
	""" Return the label of the index'th member!. """

	raise TypeCode.BadKind()

    def discriminator_type(self):
	""" Return the discriminator TypeCode. """

	raise TypeCode.BadKind()

    def default_index(self):
	""" Return the index of the default case. """

	raise TypeCode.BadKind()

    def length(self):
	""" Return the length of the TypeCode. """

	raise TypeCode.BadKind()

    def content_type(self):
	""" Return the content type of the TypeCode. """

	raise TypeCode.BadKind()

    def fixed_digits(self):
	""" Return the number of digits. """

	raise TypeCode.BadKind()

    def fixed_scale(self):
	""" Return the scale. """

	raise TypeCode.BadKind()

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_to_constant(self):
	""" Convert the typecode into a typecode constant. """

	# The typecode is marshalled into a CORBA 'encapsulation'. This 
	# preserves the host byte order and hence allows the typecode constant
	# to be unmarshalled on both big and little endian machines.
	encapsulation = OctetStream.Encapsulation()
	cursor = encapsulation.cursor()

	# Marshal the typecode into the encapsulation.
	self._fnorb_marshal(cursor)

	# Convert the encapsulation into an ASCII string representation.
	return cdr.octet_to_ASCII(encapsulation.data())

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	cursor.marshal('L', self._kind.value())
	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	self._kind = TCKind[int(cursor.unmarshal('L'))]
	return

    def _fnorb_marshal_value(self, cursor, value):
 	""" Marshal a VALUE of this type onto an octet stream. """
	pass

    def _fnorb_unmarshal_value(self, cursor):
 	""" Unmarshal a VALUE of this type from an octet stream. """
	pass

#############################################################################
# Empty TypeCodes.
#############################################################################

class EmptyTypeCode(TypeCode):
    pass


class NullTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_null)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_null'


class VoidTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_void)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_void'


class ShortTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_short)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type short onto an octet stream. """

	# cdrmodule interprets the Python value as a long, so we allow
	# IntType and LongType here.
	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)): 
	    raise CORBA.BAD_PARAM()

	# Check that it is in the correct range (MIN_SHORT, MAX_SHORT)
	if value < Limits.MIN_SHORT or value > Limits.MAX_SHORT:
	    raise CORBA.BAD_PARAM()

	cursor.marshal('h', value)

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type short from an octet stream. """

	return cursor.unmarshal('h')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_short'


class LongTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_long)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type long onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)):
	    raise CORBA.BAD_PARAM()

	# Limits check.
	if value < Limits.MIN_LONG or value > Limits.MAX_LONG:
	    raise CORBA.BAD_PARAM()

	cursor.marshal('l', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type long from an octet stream. """

	return cursor.unmarshal('l')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_long'


class LongLongTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_longlong)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type long long onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)):
	    raise CORBA.BAD_PARAM()

	# Limits check.
	if value < Limits.MIN_LONGLONG or value > Limits.MAX_LONGLONG:
	    raise CORBA.BAD_PARAM() # System exception.

	cursor.marshal('n', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type long long from an octet stream. """

	return cursor.unmarshal('n')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_longlong'


class UShortTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_ushort)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type ushort onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)):
	    raise CORBA.BAD_PARAM()

	# Limits check.
	if value < Limits.MIN_USHORT or value > Limits.MAX_USHORT:
	    raise CORBA.BAD_PARAM()


	cursor.marshal('H', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type ushort from an octet stream. """

	return cursor.unmarshal('H')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_ushort'


class ULongTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_ulong)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type ulong onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)):
	    raise CORBA.BAD_PARAM()

	# Limits check.
	if value < Limits.MIN_ULONG or value > Limits.MAX_ULONG:
	    raise CORBA.BAD_PARAM()

	cursor.marshal('L', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type ulong from an octet stream. """

	return cursor.unmarshal('L')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_ulong'


class ULongLongTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_ulonglong)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type ulong long onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)):
	    raise CORBA.BAD_PARAM()

	# Limits check.
	if value < Limits.MIN_ULONGLONG or value > Limits.MAX_ULONGLONG:
	    raise CORBA.BAD_PARAM() # System exception.

	cursor.marshal('N', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type ulong long from an octet stream. """

	return cursor.unmarshal('N')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_ulonglong'


class FloatTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_float)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type float onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType) and
	    not isinstance(value, types.FloatType)):
	    raise CORBA.BAD_PARAM()

	# fixme: need range checking
	cursor.marshal('f', float(value))
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type float from an octet stream. """

	return cursor.unmarshal('f')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_float'


class DoubleTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_double)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type double onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType) and
	    not isinstance(value, types.FloatType)):
	    raise CORBA.BAD_PARAM()

	# fixme: need range checking
	cursor.marshal('d', float(value))
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type double from an octet stream. """

	return cursor.unmarshal('d')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_double'


class LongDoubleTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_longdouble)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type long double onto an octet stream. """

	raise "Cannot marshal 'long double' values."

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type long double from an octet stream. """

	raise "Cannot unmarshal 'long double' values."

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_longdouble'


class BooleanTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_boolean)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type boolean onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.ListType) and
	    not isinstance(value, types.DictType) and
	    not isinstance(value, types.LongType) and
	    not isinstance(value, types.StringType)):
	    raise CORBA.BAD_PARAM()

	# convert to int style boolean
	if value:
	    bvalue = 1
	else:
	    bvalue = 0
	cursor.marshal('b', bvalue)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type boolean from an octet stream. """

	return cursor.unmarshal('b')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_boolean'


class CharTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_char)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type char onto an octet stream. """

	if not isinstance(value, types.StringType):
	    raise CORBA.BAD_PARAM()

	if len(value) != 1:
	    raise CORBA.BAD_PARAM() # System exception.

	cursor.marshal('c', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type char from an octet stream. """

	return cursor.unmarshal('c')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_char'


class WcharTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_wchar)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type wchar onto an octet stream. """

	raise "Cannot marshal 'wchar' values."

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type wchar from an octet stream. """

	raise "Cannot unmarshal 'wchar' values."

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_wchar'


class OctetTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_octet)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type octet onto an octet stream. """

	if (not isinstance(value, types.IntType) and
	    not isinstance(value, types.LongType)):
	    raise CORBA.BAD_PARAM()

	# Check that it is in the correct range (MIN_SHORT, MAX_SHORT)
	if value < Limits.MIN_OCTET or value > Limits.MAX_OCTET:
	    raise CORBA.BAD_PARAM()

	cursor.marshal('o', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type octet from an octet stream. """

	return cursor.unmarshal('o')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_octet'


class AnyTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_any)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type Any onto an octet stream. """

	# fixme: possibly automate some of the Any problems away ??
	if not isinstance(value, CORBA.Any):
	    raise CORBA.BAD_PARAM()

	value._fnorb_marshal(cursor)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type Any from an octet stream. """

	result = new.instance(CORBA.Any, {})
	result._fnorb_unmarshal(cursor)

	return result

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_any'


class TypeCodeTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_TypeCode)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of type typecode onto an octet stream. """

	value._fnorb_marshal(cursor)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of type typecode from an octet stream. """

	tcf = TypeCodeFactory_init()
	return tcf.unmarshal(cursor)

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_TypeCode'


class PrincipalTypeCode(EmptyTypeCode):

    def __init__(self):
	""" Constructor. """

	# Base class constructor.
	TypeCode.__init__(self, tk_Principal)

	return

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	cursor.marshal('O', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	return cursor.unmarshal('O')

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_Principal'

#############################################################################
# Simple TypeCodes.
#############################################################################

class SimpleTypeCode(TypeCode):
    """ Simple TypeCodes. """

    pass


class StringTypeCode(SimpleTypeCode):

    def __init__(self, max_length=0):
	""" Constructor. """

	# Base class constructor.
	SimpleTypeCode.__init__(self, tk_string)

	# Typecode parameters.
	self._max_length = max_length

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._max_length,)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind and self._max_length == other._max_length:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def length(self):
	""" Return the length of the TypeCode. """

	return self._max_length

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	SimpleTypeCode._fnorb_marshal(self, cursor)
	cursor.marshal('L', self._max_length)
	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	SimpleTypeCode._fnorb_unmarshal(self, cursor)
	self._max_length = cursor.unmarshal('L')
	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	# check for correct type
	# Note: could accept lists of ints here but would make clients/servers visibly asymmetric
	if not isinstance(value, types.StringType):
	    raise CORBA.BAD_PARAM()

	if self._max_length > 0 and len(value) > self._max_length:
	    raise CORBA.BAD_PARAM() # System exception.

	cursor.marshal('s', value)
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	value = cursor.unmarshal('s')

	if self._max_length > 0 and len(value) > self._max_length:
	    raise CORBA.BAD_PARAM() # System exception.

	return value

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	if self._max_length > 0:
	    result = 'Fnorb.orb.CORBA.StringTypeCode(%d)' % self._max_length

	else:
	    result = 'Fnorb.orb.CORBA.TC_string'

	return result


class WstringTypeCode(SimpleTypeCode):

    def __init__(self, max_length=0):
	""" Constructor. """

	# Base class constructor.
	SimpleTypeCode.__init__(self, tk_wstring)

	# Typecode parameters.
	self._max_length = max_length

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._max_length,)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind and self._max_length == other._max_length:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def length(self):
	""" Return the length of the TypeCode. """

	return self._max_length

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	SimpleTypeCode._fnorb_marshal(self, cursor)
	cursor.marshal('L', self._max_length)
	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	SimpleTypeCode._fnorb_unmarshal(self, cursor)
	self._max_length = cursor.unmarshal('L')
	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	raise "Cannot marshal 'wstring' values."

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	raise "Cannot unmarshal 'wstring' values."

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	if self._max_length > 0:
	    result = 'Fnorb.orb.CORBA.WstringTypeCode(%d)' % self._max_length

	else:
	    result = 'Fnorb.orb.CORBA.TC_wstring'

	return result


class FixedTypeCode(SimpleTypeCode):

    def __init__(self, digits, scale):
	""" Constructor. """

	# Base class constructor.
	SimpleTypeCode.__init__(self, tk_fixed)

	# Typecode parameters.
	self._digits = digits
	self._scale = scale

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._digits, self._scale)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind \
	   and self._digits == other._digits \
	   and self._scale == other._scale:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def fixed_digits(self):
	""" Return the number of digits. """

	return self._digits

    def fixed_scale(self):
	""" Return the scale. """

	return self._scale

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	SimpleTypeCode._fnorb_marshal(self, cursor)
	cursor.marshal('H', self._digits)
	cursor.marshal('h', self._scale)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	SimpleTypeCode._fnorb_unmarshal(self, cursor)
	self._digits = cursor.unmarshal('H')
	self._scale = cursor.unmarshal('h')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	raise "Cannot marshal 'fixed' values."

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	raise "Cannot unmarshal 'fixed' values."

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.FixedTypeCode(%d, %d)' % (self._digits,
							  self._scale)

#############################################################################
# Complex TypeCodes.
#############################################################################

class ComplexTypeCode(TypeCode):
    """ Complex TypeCodes. """

    pass


class InterfaceTypeCode(ComplexTypeCode):

    def __init__(self, ifr_id='', name=''):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_objref)

	# Typecode parameters.
	self._ifr_id = ifr_id
	self._name = name

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._ifr_id, self._name)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind and \
	   self._ifr_id == other._ifr_id:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def id(self):
	""" Return the TypeCode's repository id. """

	return self._ifr_id

    def name(self):
	""" Return the TypeCode's repository name. """

	return self._name

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	cursor.marshal('s', self._ifr_id)
	cursor.marshal('s', self._name)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._ifr_id = encapsulation_cursor.unmarshal('s')
	self._name = encapsulation_cursor.unmarshal('s')

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

    ## Bugfix: check if value is None *before* checking its
    ## instance type (otherwise, trying to return a None
    ## in place of an InterfaceObject would fail with BAD_PARAM
    
	# Python 'None' is used to represent CORBA 'nil'
	if value is None:
	    value = CORBA.Object(IOP.IOR())

	if (not isinstance(value, CORBA.Object) and
	    not isinstance(value, CORBA.Object_skel)):
	    raise CORBA.BAD_PARAM()

	value._fnorb_marshal(cursor)

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	# Unmarshal the IOR from the octet stream.
	ior = new.instance(IOP.IOR, {})
	ior._fnorb_unmarshal(cursor)

	# If the IOR contains at least one profile then convert it into an
	# active object reference.
	if len(ior.profiles) > 0:
	    object = CORBA.ORB_init()._fnorb_ior_to_object(ior)

	# Otherwise, substitute Python 'None' for CORBA 'nil'!
	else:
	    object = None

	return object

    def _fnorb_code(self):
	""" Return the 'name' of the typecode for stub/skeleton generation. """

	return 'Fnorb.orb.CORBA.TC_Object'


class StructTypeCode(ComplexTypeCode):

    def __init__(self, ifr_id, name, members):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_struct)

	# Typecode parameters.
	self._ifr_id = ifr_id
	self._name = name
	self._members = members

	# Add a '_container' attribute to all complex member typecodes. This
	# attribute is *only* actually used for recursive types that are
	# created *manually* (how rare is that!!!!).
	for member in self._members:
	    if isinstance(member.type, ComplexTypeCode):
		member.type._container = self

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._ifr_id, self._name, self._members)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind \
	   and len(self._members) == len(other._members):
	    for i in range(len(self._members)):
		if self._members[i].type != other._members[i].type:
		    result = 1
		    break
	    else:
		result = 0

	else:
	    result = 1
	    
	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def id(self):
	""" Return the TypeCode's repository id. """

	return self._ifr_id

    def name(self):
	""" Return the TypeCode's repository name. """

	return self._name

    def member_count(self):
	""" Return the number of members in the TypeCode. """

	return len(self._members)

    def member_name(self, index):
	""" Return the name of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].name

    def member_type(self, index):
	""" Return the TypeCode of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].type

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Push the container onto the cursor's stack.
	cursor.stack().push((self, cursor.offset() - 4))

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	cursor.marshal('s', self._ifr_id)
	cursor.marshal('s', self._name)
	cursor.marshal('L', len(self._members))
	# Each member is a 'StructMember' structure which is defined as
	# follows:-
	#
	#    struct StructMember {
	#        Identifier name;
	#        TypeCode type;
	#        IDLType type_def;
	#    };
	for member in self._members:
	    cursor.marshal('s', member.name)
	    member.type._fnorb_marshal(cursor)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	# Pop the container off the cursor's stack.
	cursor.stack().pop()

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Push the container onto the cursor's stack.
	cursor.stack().push((self, cursor.offset() - 4))

	# Create a nil object reference for creating 'StructMember' instances.
	nil = CORBA.ORB_init().nil()

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._ifr_id = encapsulation_cursor.unmarshal('s')
	self._name = encapsulation_cursor.unmarshal('s')
	# Each member is a 'StructMember' structure which is defined as
	# follows:-
	#
	#    struct StructMember {
	#        Identifier name;
	#        TypeCode type;
	#        IDLType type_def;
	#    };
	self._members = []
	for i in range(encapsulation_cursor.unmarshal('L')):
	    member_name = encapsulation_cursor.unmarshal('s')
	    member_type = tcf.unmarshal(encapsulation_cursor)
	    member = CORBA.StructMember(member_name, member_type, nil)
	    self._members.append(member)

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	# Pop the container off the cursor's stack.
	cursor.stack().pop()

	return
    
    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream.

	Input values can be Python dictionaries, or any Python object
	with a __dict__ attribute (ie. a module, a class, or an instance).

	"""
	if type(value) == types.DictionaryType:
	    dict = value

	elif hasattr(value, '__dict__'):
	    dict = value.__dict__

	else:
	    raise CORBA.BAD_PARAM() # System exception.

	# The dictionary must contain an item for *every* member of the
	# structure.
	try:
	    # Marshal each member of the structure.
	    for member in self._members:
		# If the member name is a python keyword then the Python
		# attribute is be prefixed with an underscore.
		py_member_name = Util.python_name(member.name)
		member.type._fnorb_marshal_value(cursor, dict[py_member_name])

	except KeyError:
	    raise CORBA.BAD_PARAM() # System exception.

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	# Unmarshal the contents of the structure.
	dict = {}
	for member in self._members:
	    # If the member name is a python keyword then the Python attribute
	    # must be prefixed with an underscore.
	    py_member_name = Util.python_name(member.name)
	    dict[py_member_name] = member.type._fnorb_unmarshal_value(cursor)

	# Get a reference to the Type Manager.
	tm = TypeManager.TypeManager_init()

	# Find the Python class that implements the structure.
	klass = tm.get_python_object(self._ifr_id)

	# If the class was not found then create a new one with the same name
	# as the structure (this is useful for the DII).
	if klass is None:
	    # Class attributes.
	    klass_attributes = {'_FNORB_ID': self._ifr_id}

	    # Create the class object.
	    klass = new.classobj(self._name, (), klass_attributes)

	    # Add the type to the Type Manager.
	    tm.add_type(self._ifr_id, self._fnorb_to_constant(), klass)

	return new.instance(klass, dict)


class UnionTypeCode(ComplexTypeCode):

    def __init__(self, ifr_id, name, discriminant_type, members):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_union)

	# Typecode parameters.
	self._ifr_id = ifr_id
	self._name = name
	self._discriminant_type = discriminant_type
	self._members = members

	# Get the index of the default member (if there is one).
	self._default_used = self.__get_default_used()

	# Add a '_container' attribute to all complex member typecodes. This
	# attribute is *only* used for recursive types that are created
	# *manually* (how rare is that!!!!).
	for member in self._members:
	    if isinstance(member.type, ComplexTypeCode):
		member.type._container = self

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._ifr_id, self._name, self._discriminant_type,
		self._default_used, self._members)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind \
	   and len(self._members) == len(other._members) \
	   and self._default_used == other._default_used \
	   and self._discriminant_type == other._discriminant_type:

	    for i in range(len(self._members)):
		if self._members[i].type != other._members[i].type:
		    result = 1
		    break

	    else:
		result = 0

	else:
	    result = 1
	    
	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def id(self):
	""" Return the TypeCode's repository id. """

	return self._ifr_id

    def name(self):
	""" Return the TypeCode's repository name. """

	return self._name

    def member_count(self):
	""" Return the number of members in the TypeCode. """

	return len(self._members)

    def member_name(self, index):
	""" Return the name of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].name

    def member_type(self, index):
	""" Return the TypeCode of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].type

    def member_label(self, index):
	""" Return the label of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].label

    def discriminator_type(self):
	""" Return the discriminator TypeCode. """

	return self._discriminant_type

    def default_index(self):
	""" Return the index of the default case. """

	return self._default_used

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Push the container onto the cursor's stack.
	cursor.stack().push((self, cursor.offset() - 4))

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	cursor.marshal('s', self._ifr_id)
	cursor.marshal('s', self._name)
	self._discriminant_type._fnorb_marshal(cursor)
	cursor.marshal('l', self._default_used)
	cursor.marshal('L', len(self._members))
	# Each member is a 'UnionMember' structure which is defined as
	# follows:-
	#
	#    struct UnionMember {
	#        Identifier name;
	#        any label;
	#        TypeCode type;
	#        IDLType type_def;
	#    };
	for member in self._members:
	    # Marshal the member's *label*.
	    label_type = member.label.typecode()
	    label_value = member.label.value()
	    label_type._fnorb_marshal_value(cursor, label_value)
	    # Marshal the member's name and typecode.
	    cursor.marshal('s', member.name)
	    member.type._fnorb_marshal(cursor)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	# Pop the container off the cursor's stack.
	cursor.stack().pop()

 	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Push the container onto the cursor's stack.
	cursor.stack().push((self, cursor.offset() - 4))

	# Create a nil object reference for creating 'UnionMember' instances.
	nil = CORBA.ORB_init().nil()

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._ifr_id = encapsulation_cursor.unmarshal('s')
	self._name = encapsulation_cursor.unmarshal('s')
	self._discriminant_type = tcf.unmarshal(encapsulation_cursor)
	self._default_used = encapsulation_cursor.unmarshal('l')
	# Each member is a 'UnionMember' structure which is defined as
	# follows:-
	#
	#    struct UnionMember {
	#        Identifier name;
	#        any label;
	#        TypeCode type;
	#        IDLType type_def;
	#    };
	self._members = []
	for i in range(encapsulation_cursor.unmarshal('L')):
	    # If there *is* a default case and this is it!
	    if self._default_used >= 0 and i == self._default_used:
		label_type = CORBA.TC_octet

	    else:
		label_type = self._discriminant_type

	    # Unmarshal the label's value.
	    label_value=label_type._fnorb_unmarshal_value(encapsulation_cursor)
		
	    # Wrap the label in an 'any'.
	    label = CORBA.Any(label_type, label_value)

	    # Unmarshal and create a 'UnionMember' instance.
	    member_name = encapsulation_cursor.unmarshal('s')
	    member_type = tcf.unmarshal(encapsulation_cursor)
	    member = CORBA.UnionMember(member_name, label, member_type, nil)
	    self._members.append(member)

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	# Pop the container off the cursor's stack.
	cursor.stack().pop()

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	if not isinstance(value, Fnorb.orb.Util.Union):
	    raise CORBA.BAD_PARAM()

	self._discriminant_type._fnorb_marshal_value(cursor, value.d)
	
	# If there *is* a default case.
	if self._default_used >= 0:
	    for i in range(len(self._members)):
		if i != self._default_used:
		    if self._members[i].label.value() == value.d:
			member_type = self._members[i].type
			break
	    else:
		member_type = self._members[self._default_used].type

	    # Marhal the member value.
	    member_type._fnorb_marshal_value(cursor, value.v)

	# If there is *no* default case.
	else:
	    for member in self._members:
		if member.label.value() == value.d:
		    member.type._fnorb_marshal_value(cursor, value.v)
		    break

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	tag = self._discriminant_type._fnorb_unmarshal_value(cursor)

	# If there *is* a default case.
	if self._default_used >= 0:
	    for i in range(len(self._members)):
		if i != self._default_used:
		    if self._members[i].label.value() == tag:
			member_type = self._members[i].type
			break
	    else:
		member_type = self._members[self._default_used].type

	    # Unmarshal the member value.
	    value = member_type._fnorb_unmarshal_value(cursor)

	# If there is *no* default case.
	else:
	    for member in self._members:
		if member.label.value() == tag:
		    value = member.type._fnorb_unmarshal_value(cursor)
		    break

	    else:
		value = None

	# Get a reference to the Type Manager.
	tm = TypeManager.TypeManager_init()

	# Find the Python class that implements the structure.
	klass = tm.get_python_object(self._ifr_id)

	# If the class was not found then create a new one with the same name
	# as the union (this is useful for the DII).
	if klass is None:
	    # Class attributes.
	    klass_attributes = {'_FNORB_ID': self._ifr_id}

	    # Base classes.
	    bases = (Util.Union,)

	    # Create the class object.
	    klass = new.classobj(self._name, bases, klass_attributes)

	    # Add the type to the Type Manager.
	    tm.add_type(self._ifr_id, self._fnorb_to_constant(), klass)

	return apply(klass, (tag, value))

    #########################################################################
    # Private interface.
    #########################################################################

    def __get_default_used(self):
	""" Return the index of the default member (-1 if there isn't one). """

	i = 0
	for member in self._members:
	    if member.label.typecode().kind() == CORBA.tk_octet \
	       and member.label.value() == 0:
		default_used = i
		break

	    i = i + 1

	else:
	    default_used = -1

	return default_used


class EnumTypeCode(ComplexTypeCode):

    def __init__(self, ifr_id, name, members):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_enum)

	# Typecode parameters.
	self._ifr_id = ifr_id
	self._name = name
	self._members = members

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._ifr_id, self._name, self._members)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind \
	   and len(self._members) == len(other._members):
	    for i in range(len(self._members)):
		if self._members[i] != other._members[i]:
		    result = 1
		    break
	    else:
		result = 0
		    
	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def id(self):
	""" Return the TypeCode's repository id. """

	return self._ifr_id

    def name(self):
	""" Return the TypeCode's repository name. """

	return self._name

    def member_count(self):
	""" Return the number of members in the TypeCode. """

	return len(self._members)

    def member_name(self, index):
	""" Return the name of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index]

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	cursor.marshal('s', self._ifr_id)
	cursor.marshal('s', self._name)
	cursor.marshal('L', len(self._members))
	for member_name in self._members:
	    cursor.marshal('s', member_name)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

 	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._ifr_id = encapsulation_cursor.unmarshal('s')
	self._name = encapsulation_cursor.unmarshal('s')
	self._members = []
	for i in range(encapsulation_cursor.unmarshal('L')):
	    member_name = encapsulation_cursor.unmarshal('s')
	    self._members.append(member_name)

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	if not isinstance(value, Fnorb.orb.Util.EnumMember):
	    raise CORBA.BAD_PARAM()

	cursor.marshal('L', value.value())
	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	value = int(cursor.unmarshal('L'))
	try:
	    value = Util.EnumMember(self._members[value], value)

	except IndexError:
	    # This situation only occurs when unmarshalling the TypeCode for
	    # a union that is switched on an enumeration AND has a default
	    # case!!
	    #
	    # We currently just create a 'dummy' enumeration with an
	    # 'unclashable' name.
	    value = Util.EnumMember("_default", value)

	return value
	

class SequenceTypeCode(ComplexTypeCode):

    def __init__(self, max_length, element_type):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_sequence)

	# Typecode parameters.
	self._element_type = element_type
	self._max_length = max_length

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._element_type, self._max_length)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind and \
	   self._max_length == other._max_length and \
	   self._element_type == other._element_type:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def length(self):
	""" Return the length of the TypeCode. """

	return self._max_length

    def content_type(self):
	""" Return the content type of the TypeCode. """

	return self._element_type

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	# Check if this is actually a recursive sequence.
	#
	# fixme: Can we cache this result? Searching through the cursor stack
	# could take time? I guess its not so bad 'cos most types won't be
	# nested?
	depth = self.__recursion_depth(cursor)
	
	# Non-recursive - just a plain ol' sequence!
	if depth == 0:
	    ComplexTypeCode._fnorb_marshal(self, cursor)

	    # Complex typecodes are contained in encapsulations which are
	    # marshalled as sequences of octets. The length of the
	    # encapsulation is filled in later (ie. when we know how long it
	    # is ;^).
	    cursor.marshal('L', 0)

	    # Remember the position of the encapsulation length (we do this 
	    # *after* marshalling the dummy length to allow for any padding
	    # that is required to align it on a 4 byte boundary).
	    length_offset = cursor.offset() - 4

	    # The encapsulation byte order.
	    cursor.marshal('b', Util.HOST_BYTE_ORDER)

	    # The guts of the typecode.
	    self._element_type._fnorb_marshal(cursor)
	    cursor.marshal('L', self._max_length)

	    # Fixup the length of the encapsulation.
	    length_cursor = cursor.stream().cursor(length_offset)
	    length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	# Recursive!
	else:
	    # Create a recursive sequence typecode and marshal that instead!
	    tc = RecursiveSequenceTypeCode(self._max_length, depth)
	    tc._fnorb_marshal(cursor)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._element_type = tcf.unmarshal(encapsulation_cursor)
	self._max_length = encapsulation_cursor.unmarshal('L')

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	if (not isinstance(value, types.TupleType)  and
	    not isinstance(value, types.ListType)   and
	    not isinstance(value, types.StringType)):
	    raise CORBA.BAD_PARAM()

	if self._max_length > 0 and len(value) > self._max_length:
	    raise CORBA.BAD_PARAM() # System exception.

	if self._element_type.kind() == tk_octet:
	    cursor.marshal('O', value)

	else:
	    cursor.marshal('L', len(value))
	    for element in value:
		self._element_type._fnorb_marshal_value(cursor, element)

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	if self._element_type.kind() == tk_octet:
	    value = cursor.unmarshal('O')

	else:
	    # Get the length of the sequence.
	    length = int(cursor.unmarshal('L'))

	    # Pre-allocate a list of the appropriate size.
	    value = [None] * length
	    for i in range(length):
		value[i] = self._element_type._fnorb_unmarshal_value(cursor)

	if self._max_length > 0 and len(value) > self._max_length:
	    raise CORBA.BAD_PARAM() # System exception.

	return value

    #########################################################################
    # Internal interface.
    #########################################################################

    def __recursion_depth(self, cursor):
 	""" Return the recursion depth for recursive sequences.

	Returns 0 (zero) for non-recursive types.

	Recursive types can only be introduced via sequences of structures
	or unions.

	"""
	# Get the typecode 'kind' of the element type.
	kind = self._element_type.kind()

	if kind == tk_struct or kind == tk_union:
	    # Get the interface repository id of the element type.
	    ifr_id = self._element_type.id()

	    # Look for the recursive type on the container stack.
	    depth = 1
	    for (container, offset) in cursor.stack().items():
		if container.id() == ifr_id:
		    break

		depth = depth + 1

	    # Else, not recursive!
	    else:
		depth = 0

	else:
	    depth = 0

	return depth


class RecursiveSequenceTypeCode(SequenceTypeCode):

    def __init__(self, max_length, offset):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_sequence)

	# Typecode parameters.
	self._max_length = max_length
	self._offset = offset

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._max_length, self._offset)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind \
	   and self._max_length == other._max_length \
	   and self._offset == other._offset:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def length(self):
	""" Return the length of the TypeCode. """

	return self._max_length

    def offset(self):
	""" Return the offset! """

	return self._offset

    def content_type(self):
 	""" Return the content type of the TypeCode. """

	# fixme: Cache the container?
	container = self._container
	for i in range(self._offset - 1):
	    container = container._container

	return container

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# Find the offset of the recursive type in the octet stream.
	(container, offset) = cursor.stack().items()[self._offset-1]

	# The guts of the typecode.
	cursor.marshal('L', 0xffffffffL)
	cursor.marshal('l', offset - cursor.offset())
	cursor.marshal('L', self._max_length)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream.

	This method is never called as recursive sequences are simply
	unmarshalled as references to the recursive structure or union type.

	"""
	pass

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	if (not isinstance(value, types.TupleType)  and
	    not isinstance(value, types.ListType)   and
	    not isinstance(value, types.StringType)):
	    raise CORBA.BAD_PARAM()

	if self._max_length > 0 and len(value) > self._max_length:
	    raise CORBA.BAD_PARAM() # System exception.

	# Get the recursive type.
	element_type = self.content_type()

	cursor.marshal('L', len(value))
	for element in value:
	    element_type._fnorb_marshal_value(cursor, element)

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	# Get the length of the sequence.
	length = int(cursor.unmarshal('L'))

	if self._max_length > 0 and length > self._max_length:
	    raise CORBA.BAD_PARAM() # System exception.

	# Get the recursive type.
	element_type = self.content_type()

	# Pre-allocate a list of the appropriate size.
	value = [None] * length
	for i in range(length):
	    value[i] = element_type._fnorb_unmarshal_value(cursor)

	return value


class ArrayTypeCode(ComplexTypeCode):

    def __init__(self, length, element_type):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_array)

	# Typecode parameters.
	self._length = length
	self._element_type = element_type

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._element_type, self._length)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind and \
	   self._length == other._length and \
	   self._element_type == other._element_type:
	    result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def length(self):
	""" Return the length of the TypeCode. """

	return self._length

    def content_type(self):
	""" Return the content type of the TypeCode. """

	return self._element_type

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	self._element_type._fnorb_marshal(cursor)
	cursor.marshal('L', self._length)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._element_type = tcf.unmarshal(encapsulation_cursor)
	self._length = encapsulation_cursor.unmarshal('L')

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	if (not isinstance(value, types.TupleType)  and
	    not isinstance(value, types.ListType)   and
	    not isinstance(value, types.StringType)):
	    raise CORBA.BAD_PARAM()

	if len(value) != self._length:
	    raise CORBA.BAD_PARAM() # System exception.

	for element in value:
	    self._element_type._fnorb_marshal_value(cursor, element)

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	# Pre-allocate a list of the appropriate size.
	value = [None] * int(self._length)
	for i in range(self._length):
	    value[i] = self._element_type._fnorb_unmarshal_value(cursor)

	return value


class AliasTypeCode(ComplexTypeCode):

    def __init__(self, ifr_id, name, typecode):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_alias)

	# Typecode parameters.
	self._ifr_id = ifr_id
	self._name = name
	self._typecode = typecode

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._ifr_id, self._name, self._typecode)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind:
	    # Find my *actual* typecode.
	    self_typecode = self._typecode
	    while self_typecode.kind() == CORBA.tk_alias:
		self_typecode = self_typecode._typecode

	    # Find the other *actual* typecode.
	    other_typecode = other._typecode
	    while other_typecode.kind() == CORBA.tk_alias:
		other_typecode = other_typecode._typecode

	    # Compare them!
	    result = cmp(self_typecode, other_typecode)

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def id(self):
	""" Return the TypeCode's repository id. """

	return self._ifr_id

    def name(self):
	""" Return the TypeCode's repository name. """

	return self._name

    def content_type(self):
	""" Return the content type of the TypeCode. """

	return self._typecode

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	cursor.marshal('s', self._ifr_id)
	cursor.marshal('s', self._name)
	self._typecode._fnorb_marshal(cursor)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._ifr_id = encapsulation_cursor.unmarshal('s')
	self._name = encapsulation_cursor.unmarshal('s')
	self._typecode = tcf.unmarshal(encapsulation_cursor)

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream. """

	self._typecode._fnorb_marshal_value(cursor, value)

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	return self._typecode._fnorb_unmarshal_value(cursor)


class ExceptionTypeCode(ComplexTypeCode):

    def __init__(self, ifr_id, name, members):
	""" Constructor. """

	# Base class constructor.
	ComplexTypeCode.__init__(self, tk_except)

	# Typecode parameters.
	self._ifr_id = ifr_id
	self._name = name
	self._members = members

	return

    def __getinitargs__(self):
	""" Return the constructor arguments for unpickling. """

	return (self._ifr_id, self._name, self._members)

    def __cmp__(self, other):
	""" Compare TypeCodes. """

	if self._kind == other._kind \
	   and len(self._members) == len(other._members):
	    for i in range(len(self._members)):
		if self._members[i].type != other._members[i].type:
		    result = 1
		    break
	    else:
		result = 0

	else:
	    result = 1

	return result

    #########################################################################
    # CORBA TypeCode interface.
    #########################################################################

    def id(self):
	""" Return the TypeCode's repository id. """

	return self._ifr_id

    def name(self):
	""" Return the TypeCode's repository name. """

	return self._name

    def member_count(self):
	""" Return the number of members in the TypeCode. """

	return len(self._members)

    def member_name(self, index):
	""" Return the name of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].name

    def member_type(self, index):
	""" Return the TypeCode of the index'th member!. """

	if index < 0 or index > len(self._members) - 1:
	    raise Bounds()

	return self._members[index].type

	return type

    #########################################################################
    # Fnorb-specific interface.
    #########################################################################

    def _fnorb_marshal(self, cursor):
	""" Marshal the typecode onto an octet stream. """

	ComplexTypeCode._fnorb_marshal(self, cursor)

	# Complex typecodes are contained in encapsulations which are
	# marshalled as sequences of octets. The length of the encapsulation
	# is filled in later (ie. when we know how long it is ;^).
	cursor.marshal('L', 0)

	# Remember the position of the encapsulation length (we do this *after*
	# marshalling the dummy length to allow for any padding that is
	# required to align it on a 4 byte boundary).
	length_offset = cursor.offset() - 4

	# The encapsulation byte order.
	cursor.marshal('b', Util.HOST_BYTE_ORDER)

	# The guts of the typecode.
	cursor.marshal('s', self._ifr_id)
	cursor.marshal('s', self._name)
	cursor.marshal('L', len(self._members))
	# Each member is a 'StructMember' structure which is defined as
	# follows:-
	#
	#    struct StructMember {
	#        Identifier name;
	#        TypeCode type;
	#        IDLType type_def;
	#    };
	for member in self._members:
	    cursor.marshal('s', member.name)
	    member.type._fnorb_marshal(cursor)

	# Fixup the length of the encapsulation.
	length_cursor = cursor.stream().cursor(length_offset)
	length_cursor.marshal('L', cursor.offset() - length_offset - 4)

	return

    def _fnorb_unmarshal(self, cursor):
	""" Unmarshal the typecode from an octet stream. """

	ComplexTypeCode._fnorb_unmarshal(self, cursor)

	# Create a nil object reference for creating 'StructMember' instances.
	nil = CORBA.ORB_init().nil()

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()

	# Complex typecodes are contained in encapsulations.
	encapsulation_cursor = cursor.encapsulation_cursor()

	# The guts of the typecode.
	self._ifr_id = encapsulation_cursor.unmarshal('s')
	self._name = encapsulation_cursor.unmarshal('s')
	# Each member is a 'StructMember' structure which is defined as
	# follows:-
	#
	#    struct StructMember {
	#        Identifier name;
	#        TypeCode type;
	#        IDLType type_def;
	#    };
	self._members = []
	for i in range(encapsulation_cursor.unmarshal('L')):
	    member_name = encapsulation_cursor.unmarshal('s')
	    member_type = tcf.unmarshal(encapsulation_cursor)
	    member = CORBA.StructMember(member_name, member_type, nil)
	    self._members.append(member)

	# Skip over the encapsulation.
	cursor.unmarshal('O')

	return

    def _fnorb_marshal_value(self, cursor, value):
	""" Marshal a VALUE of this type onto an octet stream.

	Like 'struct' typecodes, input values can be Python dictionaries, or
	any Python object with a __dict__ attribute (ie. a module, a class, or
	an instance).

	"""

	if not isinstance(value, Fnorb.orb.CORBA.UserException):
	    raise CORBA.BAD_PARAM()

	if type(value) == types.DictionaryType:
	    dict = value

	elif hasattr(value, '__dict__'):
	    dict = value.__dict__

	else:
	    raise CORBA.BAD_PARAM() # System exception.

	# The dictionary must contain an item for *every* member of the
	# exception.
	try:
	    # Marshal each member of the exception.
	    for member in self._members:
		# If the member name is a python keyword then the Python
		# is be prefixed with an underscore.
		py_member_name = Util.python_name(member.name)
		member.type._fnorb_marshal_value(cursor, dict[py_member_name])

	except KeyError:
	    raise CORBA.BAD_PARAM() # System exception.

	return

    def _fnorb_unmarshal_value(self, cursor):
	""" Unmarshal a VALUE of this type from an octet stream. """

	# Unmarshal the contents of the exception.
	dict = {}
	for member in self._members:
	    # If the member name is a python keyword then the Python attribute
	    # must be prefixed with an underscore.
	    py_member_name = Util.python_name(member.name)
	    dict[py_member_name] = member.type._fnorb_unmarshal_value(cursor)

	# Get a reference to the Type Manager.
	tm = TypeManager.TypeManager_init()

	# Find the Python class that implements the structure.
	klass = tm.get_python_object(self._ifr_id)

	# If the class was not found then create a new one with the same name
	# as the exception (this is useful for the DII).
	if klass is None:
	    # Class attributes.
	    klass_attributes = {'_FNORB_ID': self._ifr_id}

	    # Base classes.
	    bases = (CORBA.UserException,)

	    # Create the class object.
	    klass = new.classobj(self._name, bases, klass_attributes)

	    # Add the type to the Type Manager.
	    tm.add_type(self._ifr_id, self._fnorb_to_constant(), klass)

	return new.instance(klass, dict)

#############################################################################
# TypeCode constants.
#############################################################################

TC_null       = NullTypeCode()
TC_void       = VoidTypeCode()
TC_short      = ShortTypeCode()
TC_long       = LongTypeCode()
TC_ushort     = UShortTypeCode()
TC_ulong      = ULongTypeCode()
TC_float      = FloatTypeCode()
TC_double     = DoubleTypeCode()
TC_boolean    = BooleanTypeCode()
TC_char       = CharTypeCode()
TC_octet      = OctetTypeCode()
TC_any        = AnyTypeCode()
TC_TypeCode   = TypeCodeTypeCode()
TC_Principal  = PrincipalTypeCode()
TC_string     = StringTypeCode()
TC_Object     = InterfaceTypeCode()
TC_longlong   = LongLongTypeCode()
TC_ulonglong  = ULongLongTypeCode()
TC_longdouble = LongDoubleTypeCode()
TC_wchar      = WcharTypeCode()
TC_wstring    = WstringTypeCode()

#############################################################################
# TypeCode factory.
#############################################################################

def TypeCodeFactory_init():
    """ Return the TypeCode factory. 

    This is a factory function for the TypeCodeFactory class (the TypeCode
    factory is a singleton (ie. there can only be one instance per process)).

    """
    try:
	factory = TypeCodeFactory()

    except TypeCodeFactory, factory:
	pass

    return factory


class TypeCodeFactory:
    """ Factory for TypeCode instances. 

    The factory is a singleton (ie. there can only be one instance per
    process).

    """
    __instance = None

    # Mapping from TypeCode 'kinds' to their corresponding Python classes.
    TYPECODE_CLASS_MAP = {
	tk_null       : NullTypeCode,
	tk_void       : VoidTypeCode,
	tk_short      : ShortTypeCode,
	tk_long       : LongTypeCode,
	tk_ushort     : UShortTypeCode,
	tk_ulong      : ULongTypeCode,
	tk_float      : FloatTypeCode,
	tk_double     : DoubleTypeCode,
	tk_boolean    : BooleanTypeCode,
	tk_char       : CharTypeCode,
	tk_octet      : OctetTypeCode,
	tk_any        : AnyTypeCode,
	tk_TypeCode   : TypeCodeTypeCode,
	tk_Principal  : PrincipalTypeCode,
	tk_objref     : InterfaceTypeCode,
	tk_struct     : StructTypeCode,
	tk_union      : UnionTypeCode,
	tk_enum       : EnumTypeCode,
	tk_string     : StringTypeCode,
	tk_sequence   : SequenceTypeCode,
	tk_array      : ArrayTypeCode,
	tk_alias      : AliasTypeCode,
	tk_except     : ExceptionTypeCode,
	tk_longlong   : LongLongTypeCode,
	tk_ulonglong  : ULongLongTypeCode,
	tk_longdouble : LongDoubleTypeCode,
	tk_wchar      : WcharTypeCode,
	tk_wstring    : WstringTypeCode}

    def __init__(self):
	""" Constructor. """

	# The factory is a singleton (ie. there can only be one instance per
	# process).
	if TypeCodeFactory.__instance is not None:
	    raise TypeCodeFactory.__instance

	TypeCodeFactory.__instance = self

	return

    def unmarshal(self, cursor):
	""" Unmarshal a TypeCode from an octet stream.

	'cursor'    is a cursor positioned to unmarshal the typecode 'kind'.

	"""
	# Get the 'kind' of the typecode.
	kind = cursor.unmarshal('L')

	# The 'kind' for repeated/recursive typecodes is '0xffffffff'.
	if kind == 0xffffffffL:
	    # Mark the offset after the '0xffffffff' was unmarshalled. This is
	    # the starting point for the indirection.
	    mark = cursor.offset()

	    # Unmarshal the indirection (always a negative value).
	    indirection = cursor.unmarshal('l')

 	    # Find the repeated/recursive typecode in the stack.
	    for (typecode, offset) in cursor.stack().items():
		if offset == mark + indirection:
		    break
	    else:
		raise 'Invalid indirection for recursive typecode.'
		
 	    return typecode

	# Remember the position of the 'kind' in the octet stream.
	offset = cursor.offset() - 4

	# Set the cursor back 4 bytes to point to the typecode 'kind' again.
	# This means that we end up unmarshalling the typecode 'kind' twice,
	# but it also means that instances of each concrete Typecode class can
	# be created both manually and via the typecode factory.
	cursor.set_offset(offset)

	try:
	    # Find the appropriate TypeCode class for the kind.
	    klass = TypeCodeFactory.TYPECODE_CLASS_MAP[TCKind[int(kind)]]

	    # Create a new instance of the TypeCode.
	    typecode = new.instance(klass, {})

	    # Unmarshal it from the octet stream.
	    typecode._fnorb_unmarshal(cursor)

	except KeyError:
	    raise CORBA.BAD_TYPECODE() # System exception.

	return typecode

    def constant_to_typecode(self, constant):
	""" Convert a typecode constant into a typecode! """

	# Convert the typecode constant from an ASCII string into an octet
	# stream.
	octets = cdr.ASCII_to_octet(constant)

	# Create an encapsulation and get a cursor for it.
	encapsulation = OctetStream.Encapsulation(octets)
	cursor = encapsulation.cursor()

	# Unmarshal the typecode from the encapsulation.
	return self.unmarshal(cursor)

#############################################################################
# Python language mapping specific definitions.
#############################################################################

# Cache for typecodes.
__TYPECODE_CACHE = {} # {InterfaceRepositoryID : TypeCode}

# Mutex to make access to the cach thread-safe.
__TYPECODE_CACHE_LK = fnorb_thread.allocate_lock()

def typecode(ifr_id):
    """ Get the typecode for the specified interface repository ID. """

    # fixme: Does the locking slow the cache down too much?
    __TYPECODE_CACHE_LK.acquire()

    # Try the cache first.
    if __TYPECODE_CACHE.has_key(ifr_id):
	tc = __TYPECODE_CACHE[ifr_id]
	__TYPECODE_CACHE_LK.release()

    else:
	# Release here to allow for recursive typecodes.
	__TYPECODE_CACHE_LK.release()

	# Get a reference to the Type Manager.
	tm = TypeManager.TypeManager_init()

	# Lookup the typecode constant for the given interface repository ID.
	typecode_constant = tm.get_typecode_constant(ifr_id)

	# Get a reference to the typecode factory.
	tcf = TypeCodeFactory_init()
    
	# Convert the typecode constant into a typecode instance.
	tc = tcf.constant_to_typecode(typecode_constant)

	# Add the typecode to the cache.
	__TYPECODE_CACHE_LK.acquire()
	__TYPECODE_CACHE[ifr_id] = tc
	__TYPECODE_CACHE_LK.release()

    return tc

def id(py_object):
    """ Get the interface repository ID for the specified Python object.
    
    Returns 'None' if the object is not found.

    """
    # Lookup the interface repository ID for the given Python object.
    return TypeManager.TypeManager_init().get_ifr_id(py_object)

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