// **********************************************************************
//
// Copyright (c) 2002
// IONA Technologies, Inc.
// Waltham, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_TYPE_CODE_H
#define OB_TYPE_CODE_H

#include <OB/Any.h>
#include <OB/TypeCodeConst.h>
#include <OB/TCKind.h>

namespace OB
{

//
// For friend declarations
//
class TypeCodeConst;
class TypeCodeFactory;

} // End of namespace OB

namespace CORBA
{

//
// Declare ValueModifier and Visibility
//
typedef CORBA::Short ValueModifier;
typedef CORBA::Short Visibility;

//
// The TypeCode class
//
class TypeCode : public JTCMutex, public OB::SimpleRefCount
{
public:
    //
    // Union label class
    //
    class Label
    {
	bool isDefault_; // Is the default union label?
	void* value_; // If not the default, value_ contains the label.
	TCKind kind_;

	void* copyValue(TCKind, const void*);
	void replace(TCKind, void*);

    public:
	Label();
	~Label();

	Label& operator=(const Label&);
	Label& operator=(const Any&);

        void value(TCKind, void*);
	void setDefault();

	bool isDefault() const { return isDefault_; }
	const void* value() const { return value_; }
    };

private:
    //
    // TypeCode kind
    //
    TCKind kind_;

    //
    // tk_objref, tk_struct, tk_union, tk_enum, tk_alias, tk_value,
    // tk_value_box, tk_native, tk_abstract_interface, tk_except
    //
    String_var id_;
    String_var name_;

    //
    // tk_struct, tk_union, tk_enum, tk_value, tk_except
    //
    OB::StrSeq< int > memberNames_;

    //
    // tk_struct, tk_union, tk_value, tk_except
    //
    OB::ObjSeq< TypeCode, int > memberTypes_;

    //
    // tk_union
    //
    OB::VarSeq< Label, int > labels_;

    //
    // tk_union
    //
    TypeCode_var discriminatorType_;

    //
    // tk_string, tk_wstring, tk_sequence, tk_array
    //
    ULong length_;

    //
    // tk_sequence, tk_array, tk_value_box, tk_alias
    //
    TypeCode_var contentType_;

    //
    // tk_fixed
    //
    UShort fixedDigits_;
    Short fixedScale_;

    //
    // tk_value
    //
    OB::FixSeq< Short, int > memberVisibility_;
    ValueModifier typeModifier_;
    TypeCode_var concreteBaseType_;

    //
    // If recId_ is set, this is a placeholder recursive TypeCode that
    // was generated with create_recursive_tc(). If the placeholder
    // recursive TypeCode is already embedded, recType_ points to the
    // recursive TypeCode this placeholder delegates to.
    //
    String_var recId_;
    TypeCode_var recType_;

    //
    // Helper functions for equivalent()
    //
    bool equivalentRecHelper(TypeCode_ptr, OB::FixSeq< TypeCode_ptr, int >&,
                             OB::FixSeq< TypeCode_ptr, int >&) const;
    bool equivalentRec(TypeCode_ptr, OB::FixSeq< TypeCode_ptr, int >&,
                       OB::FixSeq< TypeCode_ptr, int >&) const;

    //
    // Helper function for get_compact_typecode()
    //
    TypeCode_ptr getCompactTypeCodeRec(OB::FixSeq< TypeCode_ptr, int >&,
				       OB::FixSeq< TypeCode_ptr, int >&) const;

    //
    // Helper functions for releasing recursive TypeCodes
    //
    ULong tryRefCount_;
    bool releaseVisit_;
    bool tryReleaseVisit_;
    bool reachableVisit_;
    void resetTryRelease();
    void tryRelease();
    bool checkTryRelease(TypeCode_ptr);
    bool isReachable(TypeCode_ptr);

    bool gc_; // Garbage collect this TypeCode?

    //
    // Hide copy-constructor and assignment operator
    //
    TypeCode(const TypeCode&);
    void operator=(const TypeCode&);

protected:

    //
    // Only these classes may create TypeCodes
    //
    friend class ::OB::TypeCodeConst;
    friend class ::OB::TypeCodeFactory;

    //
    // CDR
    //
    friend class ::OB::InputStreamImpl;
    friend class ::OB::OutputStreamImpl;

    TypeCode(bool = false);
    virtual ~TypeCode();

public:

    //
    // Standard IDL to C++ Mapping
    //
    static inline TypeCode_ptr _duplicate(TypeCode_ptr p)
    { 
	if(p)
	{
	    //
	    // Must call _OB_duplicateWithGC() due to special cyclic object
	    // dependency handling
	    //
	    p -> _OB_duplicateWithGC();
	}

	return p;
    }

    static inline TypeCode_ptr _nil()
    { return 0; }

    struct Bounds : public UserException
    {
	//
	// Standard IDL to C++ Mapping
	//
	Bounds() { }
	Bounds(const Bounds& ex) : UserException(ex) { }
	Bounds& operator=(const Bounds&) { return *this; }
	
	static Bounds* _downcast(Exception* p)
	{ return dynamic_cast<Bounds*>(p); }
	static const Bounds* _downcast(const Exception* p)
	{ return dynamic_cast<const Bounds*>(p); }
	virtual void _raise() const { throw *this; }
        virtual const char* _name() const { return "Bounds"; }
        virtual const char* _rep_id() const
        { return "IDL:omg.org/CORBA/TypeCode/Bounds:1.0"; }

	//
	// Additional ORBacus specific functions
	//
	virtual char* _to_string() const
	{ return _OB_defaultToString("CORBA::TypeCode::Bounds"); }
	
	//
	// ORBacus internal functions
	// Application programs must not use these functions directly
	//
	virtual Exception* _OB_clone() const { return new Bounds(*this); }
        virtual void _OB_insertInAny(Any&);
	static void _OB_unmarshal(Bounds&, OB::InputStreamImpl*);
    };

    class TypeCodeConstForBounds : public JTCMutex
    {
	TypeCodeConstForBounds(const TypeCodeConstForBounds&);
	void operator=(const TypeCodeConstForBounds&);
	
	CORBA::TypeCode_var typeCode_;
	
    public:
	
	TypeCodeConstForBounds() { }

	operator CORBA::TypeCode_ptr();
	CORBA::TypeCode_ptr operator->()
	{ return operator CORBA::TypeCode_ptr(); }
    };
    static OB_IMPORT TypeCodeConstForBounds _tc_Bounds;

    struct BadKind : public UserException
    {
	//
	// Standard IDL to C++ Mapping
	//
	BadKind() { }
	BadKind(const BadKind& ex) : UserException(ex) { }
	BadKind& operator=(const BadKind&) { return *this; }
	
	static BadKind* _downcast(Exception* p)
	{ return dynamic_cast<BadKind*>(p); }
	static const BadKind* _downcast(const Exception* p)
	{ return dynamic_cast<const BadKind*>(p); }
	virtual void _raise() const { throw *this; }
        virtual const char* _name() const { return "BadKind"; }
        virtual const char* _rep_id() const
        { return "IDL:omg.org/CORBA/TypeCode/BadKind:1.0"; }
	
	//
	// Additional ORBacus specific functions
	//
	virtual char* _to_string() const
        { return _OB_defaultToString("CORBA::TypeCode::BadKind"); }

	//
	// ORBacus internal functions
	// Application programs must not use these functions directly
	//
	virtual Exception* _OB_clone() const { return new BadKind(*this); }
        virtual void _OB_insertInAny(Any&);
	static void _OB_unmarshal(BadKind&, OB::InputStreamImpl*);
    };

    class TypeCodeConstForBadKind : public JTCMutex
    {
	TypeCodeConstForBadKind(const TypeCodeConstForBadKind&);
	void operator=(const TypeCodeConstForBadKind&);
	
	CORBA::TypeCode_var typeCode_;
	
    public:
	
	TypeCodeConstForBadKind() { }

	operator CORBA::TypeCode_ptr();
	CORBA::TypeCode_ptr operator->()
	{ return operator CORBA::TypeCode_ptr(); }
    };
    static OB_IMPORT TypeCodeConstForBadKind _tc_BadKind;

    Boolean equal(TypeCode_ptr) const;
    Boolean equivalent(TypeCode_ptr) const;
    TypeCode_ptr get_compact_typecode() const;
    TCKind kind() const;

    const char* id() const;
    const char* name() const;
    
    ULong member_count() const;
    const char* member_name(ULong index) const;
    
    TypeCode_ptr member_type(ULong index) const;
    
    Any* member_label(ULong index) const;
    TypeCode_ptr discriminator_type() const;
    Long default_index() const;

    ULong length() const;

    TypeCode_ptr content_type() const;

    UShort fixed_digits() const;
    Short fixed_scale() const;

    Visibility member_visibility(ULong) const;
    ValueModifier type_modifier() const;
    TypeCode_ptr concrete_base_type() const;

    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    bool _OB_isSystemException() const;
    bool _OB_isRecursive() const { return recId_.in() ? true : false; }
    void _OB_duplicateWithGC();
    void _OB_releaseWithGC();

    //
    // Enable/Disable garbage collection
    //
    void _OB_disableGC();
    void _OB_enableGC();
    
    TypeCode_ptr _OB_contentType_nodup() const;
    TypeCode_ptr _OB_memberType_nodup(ULong index) const;
    TypeCode_ptr _OB_discriminatorType_nodup() const;
    TypeCode_ptr _OB_concreteBaseType_nodup() const;

    //
    // Embed recursive placeholder TypeCodes
    //
    static void _OB_embedRecTC(TypeCode_ptr);
    static void _OB_embedRecTC(TypeCode_ptr, TypeCode_ptr);
};

inline Boolean
is_nil(TypeCode_ptr p)
{
    return p == 0;
}

inline void
release(TypeCode_ptr p)
{
    if(!is_nil(p))
    {
        //
	// Must call _OB_releaseWithGC() due to special cyclic object
	// dependency handling
	//
	p -> _OB_releaseWithGC();
    }
}

} // End of namespace CORBA

//
// Insertion and extraction for TypeCode::Bounds
//
void operator<<=(CORBA::Any&, CORBA::TypeCode::Bounds*);
void operator<<=(CORBA::Any&, const CORBA::TypeCode::Bounds&);
CORBA::Boolean operator>>=(const CORBA::Any&, CORBA::TypeCode::Bounds*&);

inline void
operator<<=(CORBA::Any_var& any, CORBA::TypeCode::Bounds* val)
{
    any.inout() <<= val;
}

inline void
operator<<=(CORBA::Any_var& any, const CORBA::TypeCode::Bounds& val)
{
    any.inout() <<= val;
}

inline CORBA::Boolean
operator>>=(const CORBA::Any_var& any, CORBA::TypeCode::Bounds*& val)
{
    return any.in() >>= val;
}

//
// Insertion and extraction for TypeCode::BadKind
//
void operator<<=(CORBA::Any&, CORBA::TypeCode::BadKind*);
void operator<<=(CORBA::Any&, const CORBA::TypeCode::BadKind&);
CORBA::Boolean operator>>=(const CORBA::Any&, CORBA::TypeCode::BadKind*&);

inline void
operator<<=(CORBA::Any_var& any, CORBA::TypeCode::BadKind* val)
{
    any.inout() <<= val;
}

inline void
operator<<=(CORBA::Any_var& any, const CORBA::TypeCode::BadKind& val)
{
    any.inout() <<= val;
}

inline CORBA::Boolean
operator>>=(const CORBA::Any_var& any, CORBA::TypeCode::BadKind*& val)
{
    return any.in() >>= val;
}

namespace OB
{

//
// Classes for _tc_<type> constants
//
class TypeCodePrimitiveConst
{
    TypeCodePrimitiveConst(const TypeCodePrimitiveConst&);
    void operator=(const TypeCodePrimitiveConst&);

    CORBA::TypeCode_var typeCode_;
    CORBA::TCKind kind_;

public:
    
    TypeCodePrimitiveConst(CORBA::TCKind);

    operator CORBA::TypeCode_ptr()
    { return typeCode_; /* No _duplicate() here! */ }

    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }
};

class TypeCodeStringConst : public JTCMutex
{
    TypeCodeStringConst(const TypeCodeStringConst&);
    void operator=(const TypeCodeStringConst&);

    CORBA::TypeCode_var typeCode_;
    bool wide_;

public:
    
    TypeCodeStringConst(bool wide) : wide_(wide) { }

    operator CORBA::TypeCode_ptr();
    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }

    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    CORBA::TypeCode_ptr _OB_bounded(CORBA::ULong);
};

class TypeCodeFixedConst : public JTCMutex
{
    TypeCodeFixedConst(const TypeCodeFixedConst&);
    void operator=(const TypeCodeFixedConst&);

    CORBA::TypeCode_var typeCode_;

public:
    
    TypeCodeFixedConst() { }

    operator CORBA::TypeCode_ptr();
    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }

    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    CORBA::TypeCode_ptr _OB_fixed(CORBA::UShort, CORBA::UShort);
};

class TypeCodeObjectConst : public JTCMutex
{
    TypeCodeObjectConst(const TypeCodeObjectConst&);
    void operator=(const TypeCodeObjectConst&);

    CORBA::TypeCode_var typeCode_;

public:
    
    TypeCodeObjectConst() { }

    operator CORBA::TypeCode_ptr();
    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }
};

class TypeCodeAbstractBaseConst : public JTCMutex
{
    TypeCodeAbstractBaseConst(const TypeCodeAbstractBaseConst&);
    void operator=(const TypeCodeAbstractBaseConst&);

    CORBA::TypeCode_var typeCode_;

public:
    
    TypeCodeAbstractBaseConst() { }

    operator CORBA::TypeCode_ptr();
    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }
};

class TypeCodeValueBaseConst : public JTCMutex
{
    TypeCodeValueBaseConst(const TypeCodeValueBaseConst&);
    void operator=(const TypeCodeValueBaseConst&);

    CORBA::TypeCode_var typeCode_;

public:
    
    TypeCodeValueBaseConst() { }

    operator CORBA::TypeCode_ptr();
    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }
};

class TypeCodeSysExConst : public JTCMutex
{
    TypeCodeSysExConst(const TypeCodeSysExConst&);
    void operator=(const TypeCodeSysExConst&);

    CORBA::TypeCode_var typeCode_;
    const char* name_;

public:
    
    TypeCodeSysExConst(const char* name) : name_(name) { }

    operator CORBA::TypeCode_ptr();
    CORBA::TypeCode_ptr operator->()
    { return operator CORBA::TypeCode_ptr(); }
};

//
// Get original type, i.e., remove aliases
//
CORBA::TypeCode_ptr GetOrigType(CORBA::TypeCode_ptr);
CORBA::TypeCode_ptr GetOrigType_nodup(CORBA::TypeCode_ptr);

} // End of namespace OB

namespace CORBA
{

//
// TypeCode constants
//
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_null;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_void;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_short;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_long;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_longlong;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_ushort;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_ulong;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_ulonglong;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_float;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_double;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_longdouble;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_boolean;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_char;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_wchar;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_octet;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_any;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_TypeCode;
OB_IMPORT extern OB::TypeCodePrimitiveConst _tc_Principal;

OB_IMPORT extern OB::TypeCodeStringConst _tc_string;
OB_IMPORT extern OB::TypeCodeStringConst _tc_wstring;

OB_IMPORT extern OB::TypeCodeFixedConst _tc_fixed;

OB_IMPORT extern OB::TypeCodeObjectConst _tc_Object;

OB_IMPORT extern OB::TypeCodeAbstractBaseConst _tc_AbstractBase;

OB_IMPORT extern OB::TypeCodeValueBaseConst _tc_ValueBase;

OB_IMPORT extern OB::TypeCodeSysExConst _tc_UNKNOWN;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_BAD_PARAM;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_NO_MEMORY;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_IMP_LIMIT;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_COMM_FAILURE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INV_OBJREF;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_NO_PERMISSION;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INTERNAL;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_MARSHAL;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INITIALIZE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_NO_IMPLEMENT;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_BAD_TYPECODE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_BAD_OPERATION;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_NO_RESOURCES;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_NO_RESPONSE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_PERSIST_STORE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_BAD_INV_ORDER;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_TRANSIENT;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_FREE_MEM;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INV_IDENT;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INV_FLAG;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INTF_REPOS;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_BAD_CONTEXT;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_OBJ_ADAPTER;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_DATA_CONVERSION;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_OBJECT_NOT_EXIST;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_TRANSACTION_REQUIRED;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_TRANSACTION_ROLLEDBACK;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INVALID_TRANSACTION;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_INV_POLICY;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_CODESET_INCOMPATIBLE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_REBIND;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_TIMEOUT;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_TRANSACTION_UNAVAILABLE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_TRANSACTION_MODE;
OB_IMPORT extern OB::TypeCodeSysExConst _tc_BAD_QOS;

} // End of namespace CORBA

#endif
