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

#include <OB/CORBA.h>
#include <OB/Util.h>
#include <OB/Properties.h>

#include <OB/CosEventChannelAdmin_skel.h>

#include <ProxyConsumer_impl.h>
#include <ProxyState.h>
#include <EC_ProxyPushConsumer_impl.h>
#include <EC_SupplierAdmin_impl.h>
#include <EC_EventChannel_impl.h>
#include <Event_impl.h>
#include <EventUtil.h>

// ----------------------------------------------------------------------
// EC_ProxyPushConsumer_impl constructor/destructor
// ----------------------------------------------------------------------

EC_ProxyPushConsumer_impl::EC_ProxyPushConsumer_impl(
    CORBA_ORB_ptr orb,
    EC_EventChannel_impl* channel,
    EC_SupplierAdmin_impl* admin,
    CORBA_ULong id)
    : orb_(CORBA_ORB::_duplicate(orb)),
      channel_(channel),
      admin_(admin),
      state_(Disconnected),
      id_(id)
{
#ifdef OB_TRACE
    if(OBMessageViewer::instance() -> getTraceLevel() >= 2)
    {
        CORBA_String_var desc = EventUtil::getConnectionAddrDescription(orb_);
        CORBA_String_var msg = CORBA_string_dup("Create ProxyPushConsumer(");
        msg += id_;
        msg += ") from ";
        msg += desc;
        OBMessageViewer::instance() -> trace(2, msg);
    }
#endif
}

EC_ProxyPushConsumer_impl::~EC_ProxyPushConsumer_impl()
{
#ifdef OB_TRACE
    if(OBMessageViewer::instance() -> getTraceLevel() >= 2)
    {
        CORBA_String_var msg = CORBA_string_dup("Destroy ProxyPushConsumer(");
        msg += id_;
        msg += ')';
        OBMessageViewer::instance() -> trace(2, msg);
    }
#endif

}

// ----------------------------------------------------------------------
// EC_ProxyPushConsumer_impl public member implementation
// ----------------------------------------------------------------------

void
EC_ProxyPushConsumer_impl::connect_push_supplier(
    CosEventComm_PushSupplier_ptr supplier)
{
    JTCSynchronized sync(*this);

    if(state_ == Destroyed)
        throw CORBA_OBJECT_NOT_EXIST();

    if(state_ == Connected)
	throw CosEventChannelAdmin_AlreadyConnected();

    //
    // The supplier is permitted to be nil
    //
    if(!CORBA_is_nil(supplier))
        supplier_ = CosEventComm_PushSupplier::_duplicate(supplier);

    state_ = Connected;
}

void
EC_ProxyPushConsumer_impl::disconnect_push_consumer()
{
    //
    // We first must check the state. This is to account for the case
    // that disconnect_push_consumer is called concurrently.
    //
    ProxyState saveState;
    {
	JTCSynchronized sync(*this);
	if(state_ == Destroyed)
	    return;
	saveState = state_;
	state_ = Destroyed;
    }

    admin_ -> removeProxy(this);

    //
    // Since we don't necessarily have a supplier, we need to verify
    // before invoking a method.
    //
    if(saveState == Connected && !CORBA_is_nil(supplier_))
    {
        try
        {
            supplier_ -> disconnect_push_supplier();
        }
        catch(CORBA_SystemException&)
        {
        }
    }

    //
    // Disconnect the servant from the ORB.
    //
    orb_ -> disconnect(this);
}

void
EC_ProxyPushConsumer_impl::push(const CORBA_Any& any)
{
    {
	JTCSynchronized sync(*this);
	if(state_ == Destroyed)
	    return;
    }
    Event_impl* event = new Event_impl(any, id_);
    channel_ -> receive(event);
}

void
EC_ProxyPushConsumer_impl::disconnect()
{
    JTCSynchronized sync(*this);
    if(state_ == Destroyed)
        return;
    
    state_ = Destroyed;
    
    //
    // Disconnect the servant from the ORB.
    //
    orb_ -> disconnect(this);
}

void
EC_ProxyPushConsumer_impl::release()
{
    CORBA_release(this);
}
