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

#include <OB/CORBA.h>
#include <OB/Util.h>
#include <OB/Hashers.h>
#include <OB/Hashtable.h>
#include <OB/HashtableI.h>
#include <OB/Properties.h>
#include <OB/CosTypedEventChannelAdmin_skel.h>
#include <OB/OBTypedEventChannelFactory_skel.h>

#include <TEC_TypedEventChannel_impl.h>

#include <TypedEventChannelFactory_impl.h>

// ----------------------------------------------------------------------
// Template instantiations
// ----------------------------------------------------------------------

#ifndef HAVE_NO_EXPLICIT_TEMPLATES
template class OBHashtable<CORBA_String_var, TEC_TypedEventChannel_impl*,
                           OB_LOCK_STRATEGY_SYNCHRONIZED>;
#else
#ifdef HAVE_PRAGMA_DEFINE
#pragma define(OBHashtable<CORBA_String_var, TEC_TypedEventChannel_impl*,
	                   OB_LOCK_STRATEGY_SYNCHRONIZED>)
#endif
#endif

// ----------------------------------------------------------------------
// TypedEventChannelFactory_impl constructor and destructor
// ----------------------------------------------------------------------

TypedEventChannelFactory_impl::TypedEventChannelFactory_impl(
    CORBA_ORB_ptr orb, CORBA_BOA_ptr boa)
    : orb_(CORBA_ORB::_duplicate(orb)),
      boa_(CORBA_BOA::_duplicate(boa)),
      channels_(new TypedEventChannelMap(63))
{
}

TypedEventChannelFactory_impl::~TypedEventChannelFactory_impl()
{
    //
    // Prevent callbacks to removeChannel() from the event channels'
    // destroy() method.
    //
    TypedEventChannelMap* channels = channels_;
    channels_ = 0;
    
    //
    // Destroy the event channels.
    //
    TypedEventChannelMap::Enumerator keys = channels -> keys();

    for(CORBA_ULong i = 0; i < keys.length(); ++i)
    {
        TEC_TypedEventChannel_impl* c;
        if(channels -> get(keys[i], c))
            c -> destroy();
    }
    
    delete channels;
}

// ----------------------------------------------------------------------
// TypedEventChannelFactory_impl public member implementation
// ----------------------------------------------------------------------

CosTypedEventChannelAdmin_TypedEventChannel_ptr
TypedEventChannelFactory_impl::create_channel(const char* id)
{
    TEC_TypedEventChannel_impl* c =
        new TEC_TypedEventChannel_impl(orb_, this, id);
    try
    {
        orb_ -> connect(c, id);
    }
    catch(const CORBA_INV_IDENT&)
    {
        CORBA_release(c);
        throw OBEventChannelFactory_ChannelAlreadyExists();
    }

    channels_ -> put(CORBA_string_dup(id), c);

    return c -> _this();
}

CosTypedEventChannelAdmin_TypedEventChannel_ptr
TypedEventChannelFactory_impl::get_channel_by_id(const char* id)
{
    TEC_TypedEventChannel_impl* c;

    if(!channels_ -> get(id, c))
        throw OBEventChannelFactory_ChannelNotAvailable();
    return c -> _this();
}

OBEventChannelFactory_ChannelIdSeq*
TypedEventChannelFactory_impl::get_channels()
{
    OBEventChannelFactory_ChannelIdSeq_var channelIds =
        new OBEventChannelFactory_ChannelIdSeq;

    TypedEventChannelMap::Enumerator keys = channels_ -> keys();

    for(CORBA_ULong i = 0; i < keys.length(); ++i)
        channelIds -> append(keys[i]);

    return channelIds._retn();
}
    
void
TypedEventChannelFactory_impl::shutdown()
{
    JTCSynchronized sync(*this);

    if(!CORBA_is_nil(boa_))
    {
        boa_ -> deactivate_impl(CORBA_ImplementationDef::_nil());
        boa_ = CORBA_BOA::_nil();
    }
}
    
void
TypedEventChannelFactory_impl::removeChannel(const char* id)
{
    if(channels_)
    {
        TEC_TypedEventChannel_impl* c;
	bool rc = channels_ -> get(id, c);
	assert(rc);

        channels_ -> remove(id);
        CORBA_release(c);
    }
}
