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

#include <OB/Basic.h>
#include <OB/Except.h>
#include <OB/Template.h>
#include <OB/Declarations.h>
#include <OB/IOP.h>
#include <OB/Object.h>
#include <OB/OCI.h>

#include <OCI_impl.h>

OCI_Current_impl* OCI_Current_impl::instance_ = 0;

class OBOCICurrentImplDestroyer
{
public:

    ~OBOCICurrentImplDestroyer()
    {
	CORBA_release(OCI_Current_impl::instance_);
	OCI_Current_impl::instance_ = 0;
    }
};

static OBOCICurrentImplDestroyer destroyer;

// ----------------------------------------------------------------------
// OCI_ConFactoryRegistry_impl public member implementation
// ----------------------------------------------------------------------

void
OCI_ConFactoryRegistry_impl::add_factory(OCI_ConFactory_ptr factory)
{
    factories_.insert(OCI_ConFactory::_duplicate(factory));
}

OCI_ConFactory_ptr
OCI_ConFactoryRegistry_impl::get_factory(const OCI_IOR& ior)
{
    CORBA_PolicyList dummyPolicies;
    return get_factory_with_policies(ior, dummyPolicies);
}

OCI_ConFactory_ptr
OCI_ConFactoryRegistry_impl::get_factory_with_policies(
                          const OCI_IOR& ior,
                          const CORBA_PolicyList& policies)
{
    //
    // Need to search each profile tag, then factories to force
    // order correctness.
    //
    for(CORBA_ULong j = 0 ; j < factories_.length() ; j++)
        if(factories_[j] -> consider_with_policies(ior, policies))
            return OCI_ConFactory::_duplicate(factories_[j]);
    
    return OCI_ConFactory::_nil();
}

OCI_ConFactorySeq*
OCI_ConFactoryRegistry_impl::get_factories()
{
    return new OCI_ConFactorySeq(factories_);
}

CORBA_Boolean
OCI_ConFactoryRegistry_impl::equivalent(const OCI_IOR& ior1,
					const OCI_IOR& ior2)
{
    for(CORBA_ULong i = 0 ; i < factories_.length() ; i++)
	if(!factories_[i] -> equivalent(ior1, ior2))
	    return CORBA_FALSE;
    
    return CORBA_TRUE;
}

CORBA_ULong
OCI_ConFactoryRegistry_impl::hash(const OCI_IOR& ior, CORBA_ULong maximum)
{
    CORBA_ULong hash = 0;
    
    for(CORBA_ULong i = 0 ; i < factories_.length() ; i++)
	hash ^= factories_[i] -> hash(ior, maximum);
    
    return hash % (maximum + 1);
}

// ----------------------------------------------------------------------
// OCI_AccRegistry_impl public member implementation
// ----------------------------------------------------------------------

void
OCI_AccRegistry_impl::add_acceptor(OCI_Acceptor_ptr acceptor)
{
    acceptors_.length(acceptors_.length() + 1);
    acceptors_[acceptors_.length() - 1] =
	OCI_Acceptor::_duplicate(acceptor);
}

OCI_AcceptorSeq*
OCI_AccRegistry_impl::get_acceptors()
{
    return new OCI_AcceptorSeq(acceptors_);
}

void
OCI_AccRegistry_impl::add_profiles(const OCI_ObjectKey& object_key,
				   OCI_IOR& ior)
{
    for(CORBA_ULong i = 0 ; i < acceptors_.length() ; i++)
	acceptors_[i] -> add_profile(object_key, ior);
}

OCI_ObjectKey*
OCI_AccRegistry_impl::is_local(const OCI_IOR& ior)
{
    for(CORBA_ULong i = 0 ; i < acceptors_.length() ; i++)
    {
	OCI_ObjectKey_var key = acceptors_[i] -> is_local(ior);
	if(key -> length() > 0)
	    return key._retn();
    }
    
    return new OCI_ObjectKey();
}

// ----------------------------------------------------------------------
// OCI_Current_impl constructor and destructor
// ----------------------------------------------------------------------

OCI_Current_impl::OCI_Current_impl()
{
#ifdef HAVE_JTC
    //
    // Initialize the transport TSS key
    //
    key_ = JTCTSS::allocate();

    //
    // The transport is initially nil
    //
    JTCTSS::set(key_, OCI_TransportInfo::_nil());
#endif
}

OCI_Current_impl::~OCI_Current_impl()
{
#ifdef HAVE_JTC
    //
    // Release the transport TSS key
    //
    JTCTSS::release(key_);
#endif
}

// ----------------------------------------------------------------------
// OCI_Current_impl public member implementation
// ----------------------------------------------------------------------

OCI_TransportInfo_ptr
OCI_Current_impl::get_oci_transport_info()
{
    //
    // Retrieve the transport info
    //
    OCI_TransportInfo_var info;
#ifdef HAVE_JTC
    info = OCI_TransportInfo::_duplicate(
	(OCI_TransportInfo_ptr)JTCTSS::get(key_));
#else
    info = info_;
#endif

    return info._retn();
}

OCI_AcceptorInfo_ptr
OCI_Current_impl::get_oci_acceptor_info()
{
    OCI_TransportInfo_var info = get_oci_transport_info();
    if(!CORBA_is_nil(info))
        return info -> acceptor_info();
    else
        return OCI_AcceptorInfo::_nil();
}
    
OCI_Current_impl*
OCI_Current_impl::_OB_impl()
{
    if(!instance_)
	instance_ = new OCI_Current_impl;

    return instance_;
}

OCI_Current_ptr
OCI_Current_impl::_OB_instance()
{
    return OCI_Current::_duplicate(_OB_impl());
}

OCI_TransportInfo_ptr
OCI_Current_impl::_OB_setOCITransportInfo(OCI_TransportInfo_ptr info)
{
    //
    // Retrieve the old transport info
    //
    OCI_TransportInfo_var save;
#ifdef HAVE_JTC
    save = OCI_TransportInfo::_duplicate(
	(OCI_TransportInfo_ptr)JTCTSS::get(key_));
#else
    save = info_;
#endif

    //
    // Set the new transport info
    //
#ifdef HAVE_JTC
    CORBA_release((OCI_TransportInfo_ptr)JTCTSS::get(key_));
    JTCTSS::set(key_, OCI_TransportInfo::_duplicate(info));
#else
    info_ = OCI_TransportInfo::_duplicate(info);
#endif

    //
    // Return the old transport info
    //
    return save._retn();
}
