// **********************************************************************
//
// 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/CosEventChannelAdmin_skel.h>
#include <OB/OBEventChannelFactory_skel.h>

#include <EC_EventChannel_impl.h>

#include <EventChannelFactory_impl.h>

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

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

// ----------------------------------------------------------------------
// EventChannelFactory_impl constructor and destructor.
// ----------------------------------------------------------------------

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

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

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

// ----------------------------------------------------------------------
// EventChannelFactory_impl public member implementation.
// ----------------------------------------------------------------------

CosEventChannelAdmin_EventChannel_ptr
EventChannelFactory_impl::create_channel(const char* id)
{
    EC_EventChannel_impl* c = new EC_EventChannel_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();
}

CosEventChannelAdmin_EventChannel_ptr
EventChannelFactory_impl::get_channel_by_id(const char* id)
{
    EC_EventChannel_impl* c;

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

    return c -> _this();
}

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

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

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

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

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

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