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

#include <OB/CORBA.h>
#include <OB/Util.h>
#include <OB/CosEventChannelAdmin.h>
#include <OB/CosEventComm_skel.h>

#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

class PullConsumer_impl : public CosEventComm_PullConsumer_skel
{
    CosEventComm_PullSupplier_var supplier_;

public:

    PullConsumer_impl(CosEventComm_PullSupplier_ptr);
    ~PullConsumer_impl();

    void disconnect_pull_consumer();

    int run();
};

PullConsumer_impl::PullConsumer_impl(CosEventComm_PullSupplier_ptr supplier)
    : supplier_(CosEventComm_PullSupplier::_duplicate(supplier))
{
}

PullConsumer_impl::~PullConsumer_impl()
{
    if(!CORBA_is_nil(supplier_))
        supplier_ -> disconnect_pull_supplier();
}

void
PullConsumer_impl::disconnect_pull_consumer()
{
    supplier_ = CosEventComm_PullSupplier::_nil();
}

int
PullConsumer_impl::run()
{
    //
    // Main loop
    //
    while(true)
    {
	CORBA_Any_var any;
        CORBA_Boolean hasEvent;
	try
	{
	    //
	    // We use try_pull so that the application can be stopped.
	    // The other approach would be to use DII, and send_deferred()
	    // and then poll for the result.
	    //
	    //any = supplier_ -> try_pull(hasEvent);
	    any = supplier_ -> pull(); hasEvent = true;
	}
	catch(CORBA_SystemException& ex)
	{
	    cout << "Error in pull" << endl;
	    OBPrintException(ex);
	    return 1;
	}
        catch(CosEventComm_Disconnected&)
        {
            return 1;
        }

        if(hasEvent)
        {
            char* s;
            if(any >>= s)
                cout << s << endl;
        }
    }

    return 0;
}

int
main(int argc, char* argv[], char*[])
{
    try
    {
        //
        // Create ORB
        //
        CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);

	//
	// Get event channel
	//
	CORBA_Object_var obj;
	
	try
	{
	    obj = orb -> resolve_initial_references("EventService");
	}
	catch(const CORBA_ORB::InvalidName&)
	{
	    cerr << argv[0] << ": can't resolve `EventService'" << endl;
	    return 1;
	}
	
	if(CORBA_is_nil(obj))
	{
	    cerr << argv[0] << ": `EventService' is a nil object reference"
		 << endl;
	    return 1;
	}
	
	CosEventChannelAdmin_EventChannel_var e =
	    CosEventChannelAdmin_EventChannel::_narrow(obj);
	if(CORBA_is_nil(e))
	{
	    cerr << argv[0]
		 << ": `EventService' is not an EventChannel object reference"
		 << endl;
	    return 1;
	}
	
	//
	// Get ProxyPullSupplier
	//
	CosEventChannelAdmin_ConsumerAdmin_var consumerAdmin =
	    e -> for_consumers();
	CosEventChannelAdmin_ProxyPullSupplier_var supplier =
	    consumerAdmin -> obtain_pull_supplier();
	
	//
	// Connect implementation to ProxyPullSupplier
	//
	PullConsumer_impl* consumer = new PullConsumer_impl(supplier);
	CosEventComm_PullConsumer_var dummy = consumer;
	try
	{
	    supplier -> connect_pull_consumer(
		CosEventComm_PullConsumer::_nil());
	}
	catch(const CosEventChannelAdmin_AlreadyConnected&)
	{
	    cout << "AlreadyConnected exception" << endl;
	    return 1;
	}

	if(consumer -> run() == 1)
	    return 1;
    }
    catch(CORBA_SystemException& ex)
    {
        OBPrintException(ex);
        return 1;
    }
 
    return 0;
}
