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

#ifndef OB_DIRECT_STUB_IMPL_H
#define OB_DIRECT_STUB_IMPL_H

#include <OB/DirectStubImpl_fwd.h>
#include <OB/POAInterface_fwd.h>
#include <OB/POAServantBase_fwd.h>
#include <OB/Object_fwd.h>
#include <OB/ORBInstance_fwd.h>
#include <OB/Stream_fwd.h>

#include <OB/NativeTypes.h>
#include <OB/StubImpl.h>
#include <OB/POACommon.h>

namespace OBPortableServer
{

class POA_impl;

} // End namespace PortableServer

namespace OB
{

//
// The DirectStubImpl class
//
class DirectStubImpl : virtual public StubImplBase
{
    //
    // Hide copy-constructor and assignment operator
    //
    DirectStubImpl(const DirectStubImpl&);
    void operator=(const DirectStubImpl&);

    //
    // The POA
    //
    OBPortableServer::POA_impl* poa_;

    //
    // The object ID
    //
    PortableServer::ObjectId oid_;

    //
    // This flag is true if the servant has been deactivated
    //
    bool deactivated_;
    JTCMutex deactivatedMutex_;

protected:

    //
    // The servant
    //
    PortableServer::ServantBase* _ob_servant_;

    //
    // These operations are needed for OBV, in order to copy arguments
    // even in the local case.
    //
    OutputStream_ptr _OB_createOutputStream();
    InputStream_ptr _OB_createInputStream(OutputStream_ptr);
    
#ifdef HAVE_VCPLUSPLUS_BUGS

public:

    DirectStubImpl() { }

protected:

    void _ob_initialize(PortableServer::POA_ptr,
                        const PortableServer::ObjectId&,
                        PortableServer::ServantBase*);
#endif

public:

    DirectStubImpl(PortableServer::POA_ptr,
                   const PortableServer::ObjectId&,
		   PortableServer::ServantBase*);

    virtual ~DirectStubImpl();

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

    virtual CORBA::InterfaceDef_ptr _get_interface();
    virtual CORBA::Boolean _is_a(const char*);
    virtual CORBA::Boolean _non_existent();
    virtual CORBA::Boolean _locate_request();

    virtual OCI::ConnectorInfo_ptr _get_oci_connector_info();
    virtual OCI::TransportInfo_ptr _get_oci_transport_info();

    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    void _OB_deactivate();
    PortableServer::ServantBase* _OB_setupServant();
    void _OB_preinvoke(const char*);
    void _OB_postinvoke();
    OB::ORBInstance_ptr _OB_ORBInstance();
};

//
// Helper class for setting/clearing down the POA for local
// invocations.
//
class InvocationHandler
{
    DirectStubImpl* directStubImpl_;
    PortableServer::ServantBase_var dummy_;

public:
    
    InvocationHandler(DirectStubImpl* directStubImpl, const char* op)
	: directStubImpl_(directStubImpl)
    {
	//
        // This line has two effects. First, an exception is raised in
        // case the DirectStubImpl has already been
        // deactivated. Second, the reference count of the servant is
        // increased, and the result stored in dummy_, so that the
        // servant cannot be destroyed as long as the
        // InvocationHandler object has not been destructed.
	//
        dummy_ = directStubImpl_ -> _OB_setupServant();

	//
	// Execute preinvoke
	//
	directStubImpl_ -> _OB_preinvoke(op);
    }

    ~InvocationHandler()
    {
	//
	// Execute postinvoke
	//
	directStubImpl_ -> _OB_postinvoke();
    }
};

} // End of namespace OB

namespace CORBA
{

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

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

} // End of namespace CORBA

namespace OBCORBA
{

class ORB_impl; // For the friend declaration

} // End of namespace CORBA

namespace OB
{

//
// The DirectStubImplFactory class
//
class DirectStubImplFactory : public RefCount
{
    //
    // Hide copy-constructor and assignment operator
    //
    DirectStubImplFactory(const DirectStubImplFactory&);
    void operator=(const DirectStubImplFactory&);

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

    //
    // The ORBInstance
    //
    ORBInstance_var orbInstance_;

    DirectStubImplFactory();
    ~DirectStubImplFactory();
    friend class ::OBCORBA::ORB_impl; // ORB_impl creates DirectStubImplFactory

public:

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

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

    //
    // Set the ORBInstance
    //
    void setORBInstance(ORBInstance_ptr);

    //
    // Create a new StubImpl
    //
    DirectStubImpl_ptr createStubImpl(RefCountIOR_ptr,
				      RefCountIOR_ptr,
				      RefCountPolicyList_ptr)
	throw(LocationForward, CORBA::SystemException);
};

} // End of namespace OB

namespace CORBA
{

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

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

} // End of namespace CORBA

#endif
