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

#ifndef OB_OBJECT_H
#define OB_OBJECT_H

//
// The OBClient class
//
class OBClient;
typedef OBClient* OBClient_ptr;
typedef OBClient_ptr OBClientRef;
void OBDuplicate(OBClient_ptr);
void OBRelease(OBClient_ptr);
typedef OBObjVar< OBClient > OBClient_var;
typedef OBObjSeq< OBClient > OBClientSeq;
typedef OBSeqVar< OBObjSeq< OBClient > > OBClientSeq_var;

class OBClient : public OBRefCount
{
    //
    // Hide copy-constructor and asignment operator
    //
    OBClient(const OBClient&);
    void operator=(const OBClient&);

    //
    // If set to true, this client can be reused
    //
    bool reuseClient_;

    //
    // The usage counter
    //
    int usage_;

protected:

    OBClient() : reuseClient_(true), usage_(0) { }
    virtual ~OBClient() { }

public:

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

    //
    // Increment usage (not mutex protected)
    //
    void incUsage() { assert(usage_ >= 0); usage_++; }

    //
    // Decrement usage (not mutex protected)
    //
    // Returns true if after the decrement the usage counter is larger
    // than 0, and false otherwise.
    //
    bool decUsage() { assert(usage_ > 0); usage_--; return usage_ > 0; }

    //
    // Get connection reuse properties
    //
    bool reuseClient() { return reuseClient_; }

    //
    // Set connection reuse properties
    //
    void reuseClient(bool reuse) { reuseClient_ = reuse; }

    //
    // Destroy the client
    //
    virtual void destroy() = 0;

    //
    // Get the OCI Connector
    //
    virtual OCI_Connector_ptr connector() = 0;
    
    //
    // Get the OCI Transport
    //
    virtual OCI_Transport_ptr transport() = 0;
    
    //
    // Calculate offset
    //
    virtual CORBA_ULong offset(CORBA_Object_ptr, const char*) = 0;

    //
    // Send request and receive response
    // With explicit timeout (throws exception on timeout)
    // With optional retry on communication failure
    //
    virtual CORBA_ULong request(CORBA_Object_ptr, const char*, OBBuffer&,
				bool&, bool&, bool&, CORBA_Long, bool) = 0;

    //
    // Send request oneway
    // With implicit zero timeout (does not throw exception on timeout)
    // With optional retry on communication failure
    //
    virtual void oneway(CORBA_Object_ptr, const char*, OBBuffer&, bool) = 0;

    //
    // Send request deferred
    // With implicit zero timeout (does not throw exception on timeout)
    // With optional retry on communication failure
    //
    virtual void deferred(CORBA_Object_ptr, const char*, OBBuffer&,
			  CORBA_ULong&, bool) = 0;

    //
    // Get repsonse
    // With explicit timeout (throws exception on timeout)
    //
    virtual CORBA_ULong response(CORBA_ULong, OBBuffer&, bool&, bool&, bool&,
				 CORBA_Long) = 0;
    
    //
    // Poll response
    // With implicit zero timeout (returns zero on timeout)
    //
    virtual CORBA_ULong poll(CORBA_ULong, OBBuffer&, bool&, bool&, bool&) = 0;
};

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

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

//
// The Dispatch Status
//
enum OBDispatchStatus
{
    OBDispatchStatusOK,
    OBDispatchStatusExcept,
    OBDispatchStatusNoObject,
    OBDispatchStatusNoOperation
};

//
// The SetOverrideType
//
enum CORBA_SetOverrideType
{
    CORBA_SET_OVERRIDE,
    CORBA_ADD_OVERRIDE
};

//
// The Object class
//
class CORBA_Object;
typedef CORBA_Object* CORBA_Object_ptr;
typedef CORBA_Object_ptr CORBA_ObjectRef;
typedef OBObjVar< CORBA_Object > CORBA_Object_var;

class CORBA_Object : public OBRefCount
{
    //
    // Hide copy-constructor and asignment operator
    //
    CORBA_Object(const CORBA_Object&);
    void operator=(const CORBA_Object&);

protected:

    //
    // The IOR
    //
    IOP_IOR _ob_ior_;

    //
    // Key cache
    //
    OBFixSeq<CORBA_Octet> _ob_key_;

    //
    // The client
    //
    OBClient_var _ob_clt_;

    //
    // The timeout (in msec)
    //
    CORBA_Long _ob_tout_;

    //
    // Retry flag
    //
    bool _ob_retry_;

    //
    // The set of policies
    //
    CORBA_PolicyList _ob_policies_;

    CORBA_Object();
    friend class CORBA_ORB; // The ORB may create CORBA_Objects

public:

    virtual ~CORBA_Object();

    //
    // Standard IDL to C++ Mapping
    //
    friend void CORBA_release(CORBA_Object_ptr);
    friend CORBA_Boolean CORBA_is_nil(CORBA_Object_ptr);
    static inline CORBA_Object_ptr _duplicate(CORBA_Object_ptr p)
    { if(p) p -> _OB_incRef(); return p; }
    static inline CORBA_Object_ptr _nil()
    { return 0; }

    virtual CORBA_ImplementationDef_ptr _get_implementation();
    virtual CORBA_InterfaceDef_ptr _get_interface();

    virtual CORBA_Boolean _is_a(const char*);
    virtual CORBA_Boolean _non_existent();
    CORBA_Boolean _is_equivalent(CORBA_Object_ptr);
    CORBA_ULong _hash(CORBA_ULong);

    CORBA_Status _create_request(CORBA_Context_ptr, const char*,
				 CORBA_NVList_ptr, CORBA_NamedValue_ptr,
				 CORBA_Request_ptr&, CORBA_Flags);
    
    CORBA_Status _create_request(CORBA_Context_ptr, const char*,
				 CORBA_NVList_ptr, CORBA_NamedValue_ptr,
				 CORBA_ExceptionList_ptr,
				 CORBA_ContextList_ptr,
				 CORBA_Request_ptr&, CORBA_Flags);

    CORBA_Request_ptr _request(const char* operation);

    //
    // Policies
    // From draft messaging specifiction
    //
    CORBA_Policy_ptr _get_policy(CORBA_PolicyType);
    CORBA_Policy_ptr _get_effective_policy_override(CORBA_PolicyType);
    CORBA_Object_ptr _set_policy_overrides(const CORBA_PolicyList&,
                                           CORBA_SetOverrideType);
    CORBA_PolicyList* _get_policy_overrides(const CORBA_PolicyTypeSeq&);
    CORBA_Boolean _validate_policies(const CORBA_PolicyList&);

    //
    // Additonal ORBacus specific functions
    //
    CORBA_Boolean _is_local();
    virtual CORBA_Boolean _is_dynamic();
    CORBA_Long _timeout();
    void _timeout(CORBA_Long);
    bool _retry();
    void _retry(bool);
    OCI_TransportInfo_ptr _get_oci_transport_info();
    OCI_ConnectorInfo_ptr _get_oci_connector_info();

    //
    // ORBacus internal functions
    // Application programs must not use these functions directly
    //
    const IOP_IOR& _OB_ior() const
    {
	return _ob_ior_;
    }

    void _OB_ior(const IOP_IOR& ior)
    {
	_ob_key_.length(0); // Invalidate key cache
	_ob_ior_ = ior;
    }

    const OBFixSeq<CORBA_Octet>& _OB_key()
    {
	return _ob_key_;
    }

    void _OB_key(const OBFixSeq<CORBA_Octet>& key)
    {
	_ob_key_ = key;
    }

    OBClient_ptr _OB_client();
    void _OB_client(OBClient_ptr);

    const CORBA_PolicyList& _OB_policies();
    void _OB_policies(const CORBA_PolicyList&);
    CORBA_Policy_ptr _OB_getPolicy(CORBA_PolicyType policyType);
    
    virtual const char* _OB_typeId() const;
    virtual void* _OB_narrowHelp(const char*) const;
    virtual OBDispatchStatus _OB_dispatch(const char*, OBBuffer&, bool,
					  CORBA_ULong, CORBA_ULong);
    CORBA_Boolean _OB_remoteIsA(const char*);
    void _OB_copyFrom(CORBA_Object_ptr);
    void _OB_forward(const CORBA_Octet*&, bool);
    void _OB_forward(const IOP_IOR&);

    //
    // CDR
    //
    friend void OBMarshal(CORBA_Object_ptr, CORBA_Octet*&);
    friend void OBMarshalCount(CORBA_Object_ptr, CORBA_ULong&);
    friend void OBUnmarshal(CORBA_Object_ptr&, const CORBA_Octet*&, bool);
};

//
// release and is_nil
//
inline void
CORBA_release(CORBA_Object_ptr p)
{
    if(p)
	p -> _OB_decRef();
}

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

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

#endif
