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

#include <OB/CORBA.h>
#include <OB/Util.h>
#include <OB/CosTypedEventChannelAdmin.h>
#include <OB/CosEventComm_skel.h>
#include <OB/Reactor.h>

#include <TimerUpdate_skel.h>

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

#include <stdlib.h>

class TimerUpdate_impl : public virtual TypedTimerUpdate_skel
{
    bool slow_;

public:
    
    TimerUpdate_impl(bool s)
        : slow_(s)
    {
    }
    
    virtual void time_update(const char* str)
    {
        cout << str << endl;
        
        if(slow_)
        {
#ifdef WIN32
            Sleep(2000);
#else
            sleep(2);
#endif        
        }
    }

    virtual void push(const CORBA_Any& data) { }
    virtual void disconnect_push_consumer() { }
};

static void
usage(const char* progName)
{
    cerr << "Usage:\n";
    cerr << progName << " [options]\n"
	"\n"
	"Options:\n"
	"-h, --help             Show this message.\n"
	"-s, --slow             Run in `slow' mode.\n"
        "-t sec, --time sec     Run for [sec] seconds, -1 forever.\n"
	"-n, --no-register      Don't register with the event service.\n"
	;
}

int
main(int argc, char** argv)
{
    try
    {
        //
        // Create ORB.
        //
        CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
	
	//
	// Create BOA.
	//
	CORBA_BOA_var boa = orb -> BOA_init(argc, argv);

#if defined(HAVE_JTC)
        orb -> conc_model(CORBA_ORB::ConcModelThreaded);
        boa -> conc_model(CORBA_BOA::ConcModelThreadPerClient);
#else
        orb -> conc_model(CORBA_ORB::ConcModelBlocking);
        boa -> conc_model(CORBA_BOA::ConcModelReactive);
#endif
    
	//
	// Parse command line arguments.
	//
        bool slow = false;
        CORBA_Long timeout = 5;
        bool reg = true;
        for(int i = 1 ; i < argc && *argv[i] == '-' ; i++)
        {
            if(strcmp(argv[i], "--help") == 0 ||
               strcmp(argv[i], "-h") == 0)
            {
                usage(argv[0]);
                return 0;
            }
            else if(strcmp(argv[i], "-s") == 0 ||
                    strcmp(argv[i], "--slow") == 0)
            {
                slow = true;
            }
            else if(strcmp(argv[i], "-n") == 0 ||
                    strcmp(argv[i], "--no-register") == 0)
            {
                reg = false;
            }
            else if(strcmp(argv[i], "-t") == 0 ||
                    strcmp(argv[i], "--timeout") == 0)
            {
                if(i + 1 >= argc)
                {
                    cerr << argv[0] << ": argument expected for " << argv[i]
                         << endl;
                    exit(1);
                }
                timeout = atoi(argv[i+1]);
                ++i;
            }
            else
            {
                cerr << argv[0] << ": unknown option `"
                     << argv[i] << "'\n" << endl;
                usage(argv[0]);
                return 1;
            }
        }

        //
        // Get event channel.
        //
        CORBA_Object_var obj;

        try
        {
            obj = orb -> resolve_initial_references("TypedEventService");
        }
        catch(const CORBA_ORB::InvalidName&)
        {
            cerr << argv[0] << ": can't resolve `TypedEventService'" << endl;
            return 1;
        }

        if(CORBA_is_nil(obj))
        {
            cerr << argv[0] << ": `TypedEventService' is a nil object "
		 << "reference" << endl;
            return 1;
        }

        CosTypedEventChannelAdmin_TypedEventChannel_var e =
            CosTypedEventChannelAdmin_TypedEventChannel::_narrow(obj);

        if(CORBA_is_nil(e))
        {
            cerr << argv[0]
                 << ": `TypedEventService' is not an TypedEventChannel "
                 << "object reference"
                 << endl;
            return 1;
        }

        //
        // Get ProxyPushSupplier
        //
        CosTypedEventChannelAdmin_TypedConsumerAdmin_var consumerAdmin =
            e -> for_consumers();
        CosEventChannelAdmin_ProxyPushSupplier_var supplier;
	try
	{
	    supplier = consumerAdmin ->
		obtain_typed_push_supplier("IDL:event/TimerUpdate:1.0");
	}
	catch(const CosTypedEventChannelAdmin_NoSuchImplementation&)
	{
	    cerr << "NoSuchImplementation" << endl;
	    return 1;
	}

        //
        // Connect implementation to ProxyPushSupplier.
        //
        TimerUpdate_impl* consumer = new TimerUpdate_impl(slow);

        //
        // Connect the consumer to the ORB with the same name each
        // time.
        //
        orb -> connect(consumer, "DefaultConsumer");

        boa -> init_servers();

        if(reg)
            supplier -> connect_push_consumer(consumer);

        //
        // Run implementation.
        //
        if(timeout < 0)
            boa -> impl_is_ready(CORBA_ImplementationDef::_nil());
        {
#ifdef WIN32
            Sleep(timeout * 1000);
#else
            sleep(timeout);
#endif
        }

        //
        // Disconnect the push supplier here to stop the event service
        // from pushing further events.
        //
	supplier -> disconnect_push_supplier();
    }
    catch(CORBA_SystemException& ex)
    {
        OBPrintException(ex);
        return 1;
    }
    
    return 0;
}
