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

#ifndef OB_CLIENT_H
#define OB_CLIENT_H

#include <OB/TypeCodeConst_fwd.h>
#include <OB/Client_fwd.h>
#include <OB/OCIClient_fwd.h>
#include <OB/Downcall_fwd.h>
#include <OB/Stream_fwd.h>

#include <OB/AnyDeclaration.h>
#include <OB/TypeCode.h>
#include <OB/OCITypes.h>
#include <OB/Object.h>
#include <OB/Policy.h>
#include <OB/CodeConverters.h>
#include <OB/list.h>

namespace OB
{

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

    int usage_; // The usage counter
    CodeConverters codeConverters_; // The code converters

    //
    // The concurrency model for this Client
    //
public:
    enum ConcModel
    {
	Reactive, 
	Threaded
    };
protected:
    ConcModel concModel_;

    Client(ConcModel, const CodeConverters&);
    virtual ~Client();

public:

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

    //
    // Destroy the client
    //
    virtual void destroy() = 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 the code set converters
    //
    const CodeConverters* codeConverters() const { return &codeConverters_; }

    //
    // Get a new request ID
    //
    virtual CORBA::ULong requestId() = 0;

    //
    // Get all profiles that are usable with this client
    //
    virtual OCI::ProfileInfoSeq* getUsableProfiles(
	const OCI::IOR&, const CORBA::PolicyList&) = 0;
    
    //
    // Get the OCI Connector info
    //
    virtual OCI::ConnectorInfo_ptr connectorInfo() = 0;
    
    //
    // Get the OCI Transport info
    //
    virtual OCI::TransportInfo_ptr transportInfo() = 0;

    //
    // Start a downcall, returning a downcall emitter and an
    // OutputStream for marshalling a request
    //
    virtual DowncallEmitter_ptr startDowncall(Downcall_ptr, OutputStream_out)
	throw() = 0;

    //
    // Checks whether this client is equal to another client
    //
    virtual bool equal(Client_ptr) = 0;

    //
    // Force connection establishment
    //
    virtual void bind(CORBA::Long) = 0;

    //
    // Determines whether this client supports twoway invocations
    //
    virtual bool twoway() = 0;
};

//
// A sequence of clients
// 
typedef ObjSeq< Client, int > ClientSeq;
typedef SeqVar< ClientSeq > ClientSeq_var;

} // End of namespace OB

namespace CORBA
{

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

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

} // End of namespace CORBA

namespace OBCORBA
{

class ORB_impl; // For the friend declaration

} // End of namespace CORBA

namespace OB
{

//
// A client/profile pair
//
struct ClientProfilePair
{
    Client_var client;
    RefCountProfileInfo_var profile;
};

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

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

    //
    // The ORB Instance
    //
    OB::ORBInstance_var orbInstance_;

    //
    // All clients
    //
    OB_STL::list<Client_var> allClients_;

    //
    // All reusable clients
    //
    OB_STL::list<Client_var> reusableClients_;

    //
    // The concurrency model with which new Clients are created
    //
    Client::ConcModel concModel_;

    ClientManager(Client::ConcModel);
    ~ClientManager();
    friend class ::OBCORBA::ORB_impl; // ORB_impl creates ClientManager

public:

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

    //
    // Destroy the client manager, including all clients it contains
    //
    void destroy();

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

    //
    // Get a list of ClientProfilePairs for an IOR and a list of policies
    //
    OB_STL::list<ClientProfilePair_var>*
    getClientProfilePairs(const IOP::IOR&, const CORBA::PolicyList&);

    //
    // Release a client
    //
    void releaseClient(Client_ptr);

    //
    // Compare two IORs for equivalence
    // Calculate a hash value for an IOR
    //
    CORBA::Boolean equivalent(const IOP::IOR&, const IOP::IOR&);
    CORBA::ULong hash(const IOP::IOR&, CORBA::ULong);
};

} // End of namespace OB

namespace CORBA
{

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

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

} // End of namespace CORBA

#endif
