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

#ifndef OB_ORB_INSTANCE_H
#define OB_ORB_INSTANCE_H

#include <OB/TypeCodeConst_fwd.h>
#include <OB/ORBInstance_fwd.h>
#include <OB/OBORB_fwd.h>
#include <OB/OBObject_fwd.h>
#include <OB/DirectStubImpl_fwd.h>
#include <OB/Client_fwd.h>
#include <OB/InitialServiceManager_fwd.h>
#include <OB/ValueFactoryManager_fwd.h>
#include <OB/PolicyFactoryManager_fwd.h>
#include <OB/PIManager_fwd.h>
#include <OB/Codec_fwd.h>
#include <OB/OBPOAManager_fwd.h>
#include <OB/MultiRequestSender_fwd.h>
#include <OB/Properties_fwd.h>
#include <OB/Dispatch_fwd.h>
#include <OB/BootManager_fwd.h>
#include <OB/Reactor_fwd.h>
#include <OB/Logger_fwd.h>
#include <OB/CoreTraceLevels_fwd.h>
#include <OB/OCIClient_fwd.h>
#include <OB/OCI_fwd.h>
#include <OB/UnknownException_fwd.h>
#include <OB/URL_fwd.h>

namespace OBCORBA
{

class ORB_impl; // For the friend declaration

} // End of namespace CORBA

namespace OB
{

class GlobalStateMutexDestroyer;
    
//
// The ORBInstance class. This class only holds references to ORB
// internal class instances. It should not have any behaviour other
// than managing the lifecycle of these objects, and setting/cleaning
// up global state objects.
//
class ORBInstance : public RefCount
{
    //
    // Hide copy-constructor and assignment operator
    //
    ORBInstance(const ORBInstance&);
    void operator=(const ORBInstance&);

    bool destroy_; // True if destroy() was called

    //
    // The native codesets
    //
    CORBA::ULong nativeCs_;
    CORBA::ULong nativeWcs_;

    //
    // The default wchar codeset (should be 0 according to specification)
    //
    CORBA::ULong defaultWcs_;

    //
    // The ORB id
    //
    CORBA::String_var orbId_;

    //
    // The Server id
    //
    CORBA::String_var serverId_;

    //
    // The Server instance-id
    //
    CORBA::String_var serverInstance_;

    //
    // ORBInstance members
    //
    // NOTE: For each new member "X_var x_", add the following to
    // the destroy() operation:
    //
    // x_ -> destroy(); // Only if X has an operation destroy()
    // x_ = X::_nil(); // To resolve potential cyclic dependencies
    //
    ObjectFactory_var objectFactory_;
    DirectStubImplFactory_var directStubImplFactory_;
    ClientManager_var clientManager_;
    PolicyFactoryManager_var policyFactoryManager_;
    PIManager_var interceptorManager_;
    InitialServiceManager_var initServiceManager_;
    ValueFactoryManager_var valueFactoryManager_;
    IOP::CodecFactory_var codecFactory_;
    OBPortableServer::POAManagerFactory_var pmFactory_;
    MultiRequestSender_var multiRequestSender_;
    Properties_var properties_;
    DispatchStrategyFactory_var dispatchStrategyFactory_;
    BootManager_var bootManager_;
    Reactor_var reactor_;
    Logger_var logger_;
    CoreTraceLevels_var coreTraceLevels_;
    OCI::ConFactoryRegistry_var conFactoryRegistry_;
    OCI::AccFactoryRegistry_var accFactoryRegistry_;
    UnknownExceptionStrategy_var unknownExceptionStrategy_;
    URLRegistry_var urlRegistry_;
    bool useTypeCodeCache_;
    bool extendedWchar_;

    JTCRecursiveMutex orbSyncMutex_;
    JTCThreadGroupHandle serverWorkerGroup_;
    JTCThreadGroupHandle clientWorkerGroup_;

    //
    // Global state management
    //
    friend class ::OB::GlobalStateMutexDestroyer;
    static JTCMutex* globalStateMutex_;
    static JTCInitialize* globalStateJTC_;
    static int globalStateCounter_;

    //
    // Create and destroy global state
    //
    void createGlobalState();
    void destroyGlobalState();

    ORBInstance(const char*,
		const char*,
		const char*,
		ObjectFactory_ptr,
		DirectStubImplFactory_ptr,
		ClientManager_ptr,
                PolicyFactoryManager_ptr,
                PIManager_ptr,
                InitialServiceManager_ptr,
                ValueFactoryManager_ptr,
                IOP::CodecFactory_ptr,
		OBPortableServer::POAManagerFactory_ptr,
		MultiRequestSender_ptr,
		Properties_ptr,
		DispatchStrategyFactory_ptr,
		BootManager_ptr,
		Reactor_ptr,
		Logger_ptr,
		CoreTraceLevels_ptr,
                OCI::ConFactoryRegistry_ptr,
                OCI::AccFactoryRegistry_ptr,
                UnknownExceptionStrategy_ptr,
                URLRegistry_ptr,
		CORBA::ULong, CORBA::ULong, CORBA::ULong);

    virtual ~ORBInstance();
    friend class ::OBCORBA::ORB_impl; // ORB_impl creates ORBInstance

public:

    static inline ORBInstance_ptr _duplicate(ORBInstance_ptr p)
    { if(p) p -> _OB_incRef(); return p; }
    static inline ORBInstance_ptr _nil()
    { return 0; }

    //
    // Destroy the ORBInstance
    //
    void destroy();

    //
    // Get codeset information
    //
    CORBA::ULong getNativeCs();
    CORBA::ULong getNativeWcs();
    CORBA::ULong getDefaultWcs();

    //
    // Get the ObjectFactory
    //
    ObjectFactory_ptr getObjectFactory();

    //
    // Get the DirectStubImplFactory
    //
    DirectStubImplFactory_ptr getDirectStubImplFactory();

    //
    // Get the ClientManager
    //
    ClientManager_ptr getClientManager();

    //
    // Get the PolicyFactoryManager
    //
    PolicyFactoryManager_ptr getPolicyFactoryManager();
    
    //
    // Get the PIManager
    //
    PIManager_ptr getPIManager();

    //
    // Get the InitialServiceManager
    //
    InitialServiceManager_ptr getInitialServiceManager();

    //
    // Get the ValueFactoryManager
    //
    ValueFactoryManager_ptr getValueFactoryManager();

    //
    // Get the CodecFactory
    //
    IOP::CodecFactory_ptr getCodecFactory();

    //
    // Get the POAManagerFactory
    //
    OBPortableServer::POAManagerFactory_ptr getPOAManagerFactory();

    //
    // Get the MultiRequestSender
    //
    MultiRequestSender_ptr getMultiRequestSender();

    //
    // Get the Properties
    //
    Properties_ptr getProperties();

    //
    // Get the DispatchStrategyFactory
    //
    DispatchStrategyFactory_ptr getDispatchStrategyFactory();

    //
    // Get the BootManager
    //
    BootManager_ptr getBootManager();

    //
    // Get the reactor
    //
    Reactor_ptr getReactor();

    //
    // Get the message viewer
    //
    Logger_ptr getLogger();

    //
    // Get the core trace levels
    //
    CoreTraceLevels_ptr getCoreTraceLevels();

    //
    // Get the ORB synchronization mutex
    //
    JTCRecursiveMutex& getORBSyncMutex();

    //
    // Get the server worker thread group
    //
    JTCThreadGroupHandle getServerWorkerGroup();

    //
    // Get the client worker thread group
    //
    JTCThreadGroupHandle getClientWorkerGroup();

    //
    // Get the OCI connector factory registry
    //
    OCI::ConFactoryRegistry_ptr getConFactoryRegistry();

    //
    // Get the OCI acceptor factory registry
    //
    OCI::AccFactoryRegistry_ptr getAccFactoryRegistry();

    //
    // Get and set the unknown exception strategy
    //
    UnknownExceptionStrategy_ptr getUnknownExceptionStrategy();
    UnknownExceptionStrategy_ptr setUnknownExceptionStrategy(
        UnknownExceptionStrategy_ptr);

    //
    // Get the URL registry
    //
    URLRegistry_ptr getURLRegistry();

    //
    // Get the ORB id (doesn't follow the C++ mapping)
    //
    const char* getOrbId() const;
    
    //
    // Get the Server id (doesn't follow the C++ mapping)
    //
    const char* getServerId() const;

    //
    // Get the Server instance id (doesn't follow the C++ mapping)
    //
    const char* getServerInstance() const;

    //
    // Use the TypeCode cache?
    // 
    bool useTypeCodeCache() const;

    //
    // Support wchar/wstring for IIOP 1.0?
    //
    bool extendedWchar() const;
};

} // End of namespace OB

namespace CORBA
{

inline void
release(OB::ORBInstance_ptr p)
{
    if(p)
	p -> _OB_decRef();
}

inline Boolean
is_nil(OB::ORBInstance_ptr p)
{
    return p == 0;
}

} // End of namespace CORBA

namespace OB
{

//
// Get an ORBInstance, given an ORB_ptr
//
ORBInstance_ptr GetORBInstance(CORBA::ORB_ptr);

} // End of namespace OB

#endif
