// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_ORB_H
#define OB_ORB_H


//
// The ORB class
//
class CORBA_ORB;
typedef CORBA_ORB* CORBA_ORB_ptr;
typedef CORBA_ORB_ptr CORBA_ORBRef;
void OBDuplicate(CORBA_ORB_ptr);
void OBRelease(CORBA_ORB_ptr);
typedef OBObjVar< CORBA_ORB > CORBA_ORB_var;

class CORBA_ORB : public OBRefCount
{
public: // For some compilers the following structs must be public
    //
    // Helper struct for initial services
    //
    struct InitialService
    {
        CORBA_String_var name;
        CORBA_String_var ref;
        CORBA_Object_var obj;
    };
    typedef OBVarSeq< InitialService > InitialServiceSeq;

private:
    //
    // Hide copy-constructor and asignment operator
    //
    CORBA_ORB(const CORBA_ORB&);
    void operator=(const CORBA_ORB&);

    //
    // The ORB singleton
    //
    static CORBA_ORB_ptr orb_;

#ifdef HAVE_JTC
    //
    // JTC initialization
    //
    JTCInitialize* dummyForJTC_;
#endif

    //
    // The OCI connection factory registry
    //
    OCI_ConFactoryRegistry_var registry_;

    //
    // All clients
    //
    OBClientSeq clients_;
#ifdef HAVE_JTC
    JTCRecursiveMutex clientsMutex_;
#endif

    //
    // List with all initial services
    //
    InitialServiceSeq services_;

    //
    // The default initial reference "template"
    //
    CORBA_String_var defaultInitRef_;

    //
    // Default set of policies
    //
    CORBA_PolicyList policies_;

    //
    // Whether DII operations should raise system exceptions
    //
    static CORBA_Boolean raiseDIIExceptions_;

    //
    // The concurrency model
    //
public:
    enum ConcModel
    {
	//
	// Client uses blocking send/receive
	//
	ConcModelBlocking,
	
	//
	// Client uses the reactor and non-blocking send/receive
	//
	ConcModelReactive

#ifdef HAVE_JTC
	,
	//
	// Client uses separate sender and receiver threads
	//
	ConcModelThreaded
#endif
    };
private:
    static ConcModel concModel_;

    //
    // For send_multiple_requests_deferred
    //
public:
    typedef OBObjSeq<CORBA_Request> RequestSeq;
private:
    RequestSeq deferredRequests_;
    OBFixSeq<CORBA_Boolean> deferredRequestCompletions_;

    CORBA_ORB();
    ~CORBA_ORB();

    //
    // ORB_init may create ORBs
    //
    friend CORBA_ORB_ptr CORBA_ORB_init(int&, char**, const char*,
					const char*);

public:

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

    typedef char* OAid;
    CORBA_BOA_ptr BOA_init(int&, char**, const char* = "");

    char* object_to_string(CORBA_Object_ptr);
    CORBA_Object_ptr string_to_object(const char*);

    CORBA_Status create_list(CORBA_Long, CORBA_NVList_ptr&);
    CORBA_Status create_operation_list(CORBA_OperationDef_ptr,
				       CORBA_NVList_ptr&);
    CORBA_Status create_named_value(CORBA_NamedValue_ptr&);
    CORBA_Status create_exception_list(CORBA_ExceptionList_ptr&);
    CORBA_Status create_context_list(CORBA_ContextList_ptr&);

    CORBA_Status get_default_context(CORBA_Context_ptr&);
    CORBA_Status create_environment(CORBA_Environment_ptr&);

    CORBA_Status send_multiple_requests_oneway(const RequestSeq&);
    CORBA_Status send_multiple_requests_deferred(const RequestSeq&);
    CORBA_Boolean poll_next_response();
    CORBA_Status get_next_response(CORBA_Request_ptr&);

    static CORBA_TypeCode_ptr create_struct_tc(const char*,
					       const char*,
					       const CORBA_StructMemberSeq&);
    
    static CORBA_TypeCode_ptr create_union_tc(const char*,
					      const char*,
					      CORBA_TypeCode_ptr,
					      const CORBA_UnionMemberSeq&);
    
    static CORBA_TypeCode_ptr create_enum_tc(const char*,
					     const char*,
					     const CORBA_EnumMemberSeq&);
    
    static CORBA_TypeCode_ptr create_alias_tc(const char*,
					      const char*,
					      CORBA_TypeCode_ptr);
    
    static CORBA_TypeCode_ptr create_exception_tc(const char*,
						  const char*,
						 const CORBA_StructMemberSeq&);
    
    static CORBA_TypeCode_ptr create_interface_tc(const char*,
						  const char*);
    
    static CORBA_TypeCode_ptr create_string_tc(CORBA_ULong);
    
    static CORBA_TypeCode_ptr create_sequence_tc(CORBA_ULong,
						 CORBA_TypeCode_ptr);
    
    static CORBA_TypeCode_ptr create_recursive_sequence_tc(CORBA_ULong,
							   CORBA_ULong);
    
    static CORBA_TypeCode_ptr create_array_tc(CORBA_ULong,
					      CORBA_TypeCode_ptr);

    typedef char* ObjectId;
    typedef CORBA_String_var ObjectId_var;
    typedef OBStrSeq ObjectIdList;
    typedef OBSeqVar< OBStrSeq > ObjectIdList_var;

    class InvalidName { };

    ObjectIdList* list_initial_services();
    CORBA_Object_ptr resolve_initial_references(const char*);
        
    struct InconsistentTypeCode {};
    CORBA_DynAny_ptr create_dyn_any(const CORBA_Any& value);
    CORBA_DynAny_ptr create_basic_dyn_any(CORBA_TypeCode_ptr type);
    CORBA_DynStruct_ptr create_dyn_struct(CORBA_TypeCode_ptr type);
    CORBA_DynSequence_ptr create_dyn_sequence(CORBA_TypeCode_ptr type);
    CORBA_DynArray_ptr create_dyn_array(CORBA_TypeCode_ptr type);
    CORBA_DynUnion_ptr create_dyn_union(CORBA_TypeCode_ptr type);
    CORBA_DynEnum_ptr create_dyn_enum(CORBA_TypeCode_ptr type);

    //
    // Additional ORBacus specific functions
    //
    OCI_ConFactoryRegistry_ptr get_con_factory_registry(); 
    CORBA_Object_ptr get_inet_object(const char*, CORBA_UShort, const char*,
				     const char* = "");
    static ConcModel conc_model();
    static void conc_model(ConcModel);
    void connect(CORBA_Object_ptr);
    void connect(CORBA_Object_ptr, const char*);
    void disconnect(CORBA_Object_ptr);
    CORBA_Policy_ptr create_policy(CORBA_PolicyType policy_type,
				   CORBA_Any& val);
    void add_initial_reference(const char*, CORBA_Object_ptr);


    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    static CORBA_ORB_ptr _OB_instance();
    static CORBA_ORB_ptr _OB_instance_nodup();

    char* _OB_IORToString(const IOP_IOR&);

    CORBA_Object_ptr _OB_createObject(const IOP_IOR&);
    void _OB_changeObject(CORBA_Object_ptr, const IOP_IOR&);
    void _OB_incClientUsage(OBClient_ptr);
    void _OB_decClientUsage(OBClient_ptr);
    CORBA_Boolean _OB_equivalent(const IOP_IOR&, const IOP_IOR&);
    CORBA_ULong _OB_hash(const IOP_IOR&, CORBA_ULong);

    void _OB_addInitialService(const char*, const char*);
    void _OB_addInitialService(const char*, CORBA_Object_ptr);

    static CORBA_Boolean _OB_raiseDIIExceptions();
};

inline void
CORBA_release(CORBA_ORB_ptr p)
{
    if(p)
	p -> _OB_decRef();
}

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

//
// ORB initialization
//
CORBA_ORB_ptr CORBA_ORB_init(int&, char**, const char* = "",
			     const char* = OB_VERSION);
typedef char* CORBA_ORBid;

#endif
