// **********************************************************************
//
// Copyright (c) 1998
// Object-Oriented Concepts, Inc.
// Billerica, MA, USA
//
// Copyright (c) 1998
// Object-Oriented Concepts GmbH
// Ettlingen, Germany
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_TYPE_CODE_H
#define OB_TYPE_CODE_H

//
// The TypeCode class
//
class CORBA_TypeCode;
typedef CORBA_TypeCode* CORBA_TypeCode_ptr;
typedef CORBA_TypeCode_ptr TypeCodeRef;
void OBDuplicate(CORBA_TypeCode_ptr);
void OBRelease(CORBA_TypeCode_ptr);
typedef OBObjVar< CORBA_TypeCode > CORBA_TypeCode_var;

class CORBA_TypeCode : public OBRefCount
{
    //
    // TypeCode kind
    //
    CORBA_TCKind kind_;

    //
    // CORBA_tk_objref, CORBA_tk_struct, CORBA_tk_union, CORBA_tk_enum,
    // CORBA_tk_alias, CORBA_tk_except
    //
    CORBA_String_var id_;
    CORBA_String_var name_;

    //
    // CORBA_tk_struct, CORBA_tk_union, CORBA_tk_enum, CORBA_tk_except
    //
    OBStrSeq memberNames_;

    //
    // CORBA_tk_struct, CORBA_tk_union, CORBA_tk_except
    //
    OBObjSeq< CORBA_TypeCode > memberTypes_;

    //
    // CORBA_tk_union
    //
    OBVarSeq< CORBA_Any > labels_;

    //
    // CORBA_tk_union
    //
    CORBA_TypeCode_var discriminatorType_;

    //
    // CORBA_tk_string, CORBA_tk_sequence, CORBA_tk_array
    //
    CORBA_ULong length_;

    //
    // CORBA_tk_sequence, CORBA_tk_array, CORBA_tk_alias
    //
    CORBA_TypeCode_var contentType_;

    //
    // CORBA_tk_sequence (for recursive sequence type codes)
    //
    CORBA_ULong offset_;

    //
    // TypeCodes containing a cyclic reference to this type code
    //
    OBObjSeq< CORBA_TypeCode > cyclicTypes_;

    //
    // Hide copy-constructor and asignment operator
    //
    CORBA_TypeCode(const CORBA_TypeCode&);
    void operator=(const CORBA_TypeCode&);

protected:

    //
    // Only these classes may create TypeCodes
    //
    friend class OBTypeCodeSimpleConst;
    friend class OBTypeCodeStringConst;
    friend class OBTypeCodeObjectConst;
    friend class OBTypeCodeSysExConst;
    friend class OBTypeCodeConst;
    friend class CORBA_ORB;

    CORBA_TypeCode();
    virtual ~CORBA_TypeCode();

public:

    //
    // Standard IDL to C++ Mapping
    //
    static inline CORBA_TypeCode_ptr _duplicate(CORBA_TypeCode_ptr p)
    { if(p) p -> _OB_incRef(); return p; }
    static inline CORBA_TypeCode_ptr _nil()
    { return 0; }

    class Bounds { };
    class BadKind { };

    CORBA_Boolean exactly_equal(CORBA_TypeCode_ptr) const;
    CORBA_TCKind kind() const;

    const char* id() const
	throw(BadKind);
    const char* name() const
	throw(BadKind);
    
    CORBA_ULong member_count() const
	throw(BadKind);
    const char* member_name(CORBA_ULong index) const
	throw(BadKind, Bounds);
    
    CORBA_TypeCode_ptr member_type(CORBA_ULong index) const
	throw(BadKind, Bounds);
    
    CORBA_Any* member_label(CORBA_ULong index) const
	throw(BadKind, Bounds);
    CORBA_TypeCode_ptr discriminator_type() const
	throw(BadKind);
    CORBA_Long default_index() const
	throw(BadKind);
    
    CORBA_ULong length() const
	throw(BadKind);
    
    CORBA_TypeCode_ptr content_type() const
	throw(BadKind);
    
    //
    // Additonal ORBacus specific functions
    //
    CORBA_Boolean equal(CORBA_TypeCode_ptr) const; // like equal, but
                                                   // ignores aliases
    CORBA_ULong offset() const
	throw(BadKind);    

    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    bool _OB_isSystemException() const;

    //
    // CDR
    //
    friend void OBMarshal(CORBA_TypeCode_ptr, CORBA_Octet*&);
    friend void OBMarshalRec(CORBA_TypeCode_ptr, CORBA_Octet*&,
			     CORBA_Octet const * const,
			     OBFixSeq< CORBA_Long >&);

    friend void OBMarshalCount(CORBA_TypeCode_ptr, CORBA_ULong&);
    friend void OBMarshalCountRec(CORBA_TypeCode_ptr, CORBA_ULong&,
				  CORBA_ULong);

    friend void OBUnmarshal(CORBA_TypeCode_ptr&, const CORBA_Octet*&, bool);
    friend void OBUnmarshalRec(CORBA_TypeCode_ptr&, const CORBA_Octet*&,
			       bool, CORBA_Octet const * const,
			       OBFixSeq< CORBA_Long >&);

    friend void OBMarshalBuffer(CORBA_TypeCode_ptr, const CORBA_Octet*&,
				CORBA_Octet*&, bool);
    friend void OBMarshalBufferCount(CORBA_TypeCode_ptr, const CORBA_Octet*&,
				     CORBA_ULong&, bool);

    //
    // Fill in recursive type codes
    //
    friend bool OBFillRec(CORBA_TypeCode_ptr&, CORBA_TypeCode_ptr,
			  CORBA_ULong);

    //
    // OBRelease needs access to cyclicTypes_ and contentType_
    //
    friend void OBRelease(CORBA_TypeCode_ptr);
};

inline void
CORBA_release(CORBA_TypeCode_ptr p)
{
    OBRelease(p); // Must call OBRelease due to special
                  // cyclic object dependency handling
}

inline CORBA_Boolean
CORBA_is_nil(CORBA_TypeCode_ptr p)
{
    return p == 0;
}

//
// CDR
//
void OBMarshal(const OBObjSeq< CORBA_TypeCode >&, CORBA_Octet*&);
void OBMarshalCount(const OBObjSeq< CORBA_TypeCode >&, CORBA_ULong&);
void OBUnmarshal(OBObjSeq< CORBA_TypeCode >&, const CORBA_Octet*&, bool);

//
// Classes for _tc_<type> constants
//
class OBTypeCodeSimpleConst
{
    mutable CORBA_TypeCode_var typeCode_;
    const CORBA_TCKind kind_;

    OBTypeCodeSimpleConst(const OBTypeCodeSimpleConst&);
    void operator=(const OBTypeCodeSimpleConst&);

public:
    
    OBTypeCodeSimpleConst(CORBA_TCKind);
    operator CORBA_TypeCode_ptr() const;
    CORBA_TypeCode_ptr operator->() const
    { return operator CORBA_TypeCode_ptr(); }
};

class OBTypeCodeStringConst
{
    mutable CORBA_TypeCode_var typeCode_;

    OBTypeCodeStringConst(const OBTypeCodeStringConst&);
    void operator=(const OBTypeCodeStringConst&);

public:
    
    OBTypeCodeStringConst();
    operator CORBA_TypeCode_ptr() const;
    CORBA_TypeCode_ptr operator->() const
    { return operator CORBA_TypeCode_ptr(); }
    CORBA_TypeCode_ptr bounded(CORBA_ULong) const;
};

class OBTypeCodeObjectConst
{
    mutable CORBA_TypeCode_var typeCode_;

    OBTypeCodeObjectConst(const OBTypeCodeStringConst&);
    void operator=(const OBTypeCodeStringConst&);

public:
    
    OBTypeCodeObjectConst();
    operator CORBA_TypeCode_ptr() const;
    CORBA_TypeCode_ptr operator->() const
    { return operator CORBA_TypeCode_ptr(); }
};

class OBTypeCodeSysExConst
{
    mutable CORBA_TypeCode_var typeCode_;
    const char* name_;

    OBTypeCodeSysExConst(const OBTypeCodeSysExConst&);
    void operator=(const OBTypeCodeSysExConst&);

public:
    
    OBTypeCodeSysExConst(const char* name);
    operator CORBA_TypeCode_ptr() const;
    CORBA_TypeCode_ptr operator->() const
    { return operator CORBA_TypeCode_ptr(); }
};

class OBTypeCodeConst
{
    mutable CORBA_TypeCode_var typeCode_;
    char const * const str_;

    OBTypeCodeConst(const OBTypeCodeConst&);
    void operator=(const OBTypeCodeConst&);

public:

    OBTypeCodeConst(const char* s)
	: typeCode_(CORBA_TypeCode::_nil()), str_(s) { }
    operator CORBA_TypeCode_ptr() const;
    CORBA_TypeCode_ptr operator->() const
    { return operator CORBA_TypeCode_ptr(); }
};

//
// TypeCode constants
//
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_null;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_void;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_short;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_long;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_ushort;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_ulong;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_float;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_double;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_boolean;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_char;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_octet;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_any;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_TypeCode;
OB_IMPORT extern const OBTypeCodeSimpleConst CORBA__tc_Principal;

OB_IMPORT extern const OBTypeCodeStringConst CORBA__tc_string;

OB_IMPORT extern const OBTypeCodeObjectConst CORBA__tc_Object;

OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_UNKNOWN;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_BAD_PARAM;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_NO_MEMORY;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_IMP_LIMIT;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_COMM_FAILURE;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_INV_OBJREF;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_NO_PERMISSION;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_INTERNAL;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_MARSHAL;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_INITIALIZE;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_NO_IMPLEMENT;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_BAD_TYPECODE;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_BAD_OPERATION;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_NO_RESOURCES;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_NO_RESPONSE;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_PERSIST_STORE;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_BAD_INV_ORDER;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_TRANSIENT;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_FREE_MEM;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_INV_IDENT;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_INV_FLAG;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_INTF_REPOS;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_BAD_CONTEXT;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_OBJ_ADAPTER;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_DATA_CONVERSION;
OB_IMPORT extern const OBTypeCodeSysExConst CORBA__tc_OBJECT_NOT_EXIST;

//
// Get original type, i.e. remove aliases
//
CORBA_TypeCode_ptr OBGetOrigType(CORBA_TypeCode_ptr);

#endif
