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

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

#include <OB/OBEventChannelFactory_skel.h>
#include <OB/OBTypedEventChannelFactory_skel.h>

#include <EventChannelFactory_impl.h>
#include <TypedEventChannelFactory_impl.h>
#include <EC_EventChannel_impl.h>
#include <TEC_TypedEventChannel_impl.h>

#include <Config.h> // Make sure that the compiler complains if the
                    // configuration doesn't match

static void
usage(const char* progName)
{
    cerr << "Usage:\n";
    cerr << progName << " [options]\n"
        "\n"
        "Options:\n"
        "-h, --help             "
        "Show this message.\n"
        "-v, --version          "
        "Show Event Service version.\n"
        "-i, --ior              "
        "Print IOR on standard output.\n"
        "-t, --typed-service    "
        "Run typed event service.\n"
        "-u, --untyped-service  "
        "Run untyped event service [default].\n";
}

int
main(int argc, char* argv[])
{
    try
    {
	bool typedService = false;
	int i;

	//
	// Create ORB.
	//
	CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);

	//
	// Check the ooc.even.typed_service property to determine if
	// we're running the typed event service or the untyped.
	//
	const char* value;
	value = OBProperties::instance() ->
	    getProperty("ooc.event.typed_service");
	if(value && strcmp(value, "true") == 0)
	{
	    typedService = true;
	}
	
	//
	// Prescan the arguments to determine if we're running the
	// typed event service or the untyped.
	//
	for(i = 1 ; i < argc; i++)
	{
	    if(strcmp(argv[i], "--typed-service") == 0 ||
	       strcmp(argv[i], "-t") == 0)
	    {
		typedService = true;
	    }
	    else if(strcmp(argv[i], "--untyped-service") == 0 ||
		    strcmp(argv[i], "-u") == 0)
	    {
		typedService = false;
	    }
	}

	//
	// Resolve the service object if available as an initial
	// reference.
	//
	const char* service =
	    (typedService) ? "TypedEventService" : "EventService";
	CORBA_Object_var serviceObject;
	try
	{
	    serviceObject = orb -> resolve_initial_references(service);
	}
	catch(CORBA_ORB::InvalidName&)
	{
	}
	
	//
	// Set the IIOP port based on the port defined in the IIOP
	// profile of the service object (if it exists). Then create
	// the BOA.
	//
	CORBA_BOA::set_iiop_port_from_object(serviceObject);
	CORBA_BOA_var boa = orb -> BOA_init(argc, argv);
	
	//
	// We have to run the BOA in either thread-per-client,
	// thread-pool or thread-per-request concurrency model.
	//
	orb -> conc_model(CORBA_ORB::ConcModelBlocking);
        CORBA_BOA::ConcModel model = boa -> conc_model();
        if(model != CORBA_BOA::ConcModelThreadPerClient &&
           model != CORBA_BOA::ConcModelThreadPool &&
           model != CORBA_BOA::ConcModelThreadPerRequest)
        {
	    boa -> conc_model(CORBA_BOA::ConcModelThreadPerClient);
        }
	
	//
	// Get options.
	//
	bool ior = false;
	
	for(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], "--version") == 0 ||
		    strcmp(argv[i], "-v") == 0)
	    {
		cerr << "Event Service " << OBVersion << endl;
		return 0;
	    }
	    else if(strcmp(argv[i], "--ior") == 0 ||
		    strcmp(argv[i], "-i") == 0)
	    {
		ior = true;
	    }
	    else if(strcmp(argv[i], "--typed-service") == 0 ||
		    strcmp(argv[i], "-t") == 0 ||
		    strcmp(argv[i], "--untyped-service") == 0 ||
		    strcmp(argv[i], "-u") == 0)
	    {
		// ignore
	    }
	    else
	    {
		cerr << argv[0] << ": unknown option `"
		     << argv[i] << "'\n" << endl;
		usage(argv[0]);
		return 1;
	    }
	}
	
	//
	// Create event channel.
	//
	OBEventChannelFactory_EventChannelFactory_var untypedFactory;
	OBTypedEventChannelFactory_TypedEventChannelFactory_var typedFactory;
	CosEventChannelAdmin_EventChannel_var untypedChannel;
	CosTypedEventChannelAdmin_TypedEventChannel_var typedChannel;

	CORBA_String_var s;
	
	if(!typedService)
	{
            untypedFactory = new EventChannelFactory_impl(orb, boa);
            orb -> connect(untypedFactory, "DefaultEventChannelFactory");
            try
            {
                untypedChannel =
                    untypedFactory -> create_channel("DefaultEventChannel");
            }
            catch(OBEventChannelFactory_ChannelAlreadyExists&)
            {
		cerr << argv[0]
		     << ": `DefaultEventChannel' already exists."
		     << endl;
		return 1;
            }

	    s = orb -> object_to_string(untypedChannel);
	}
	else
	{
	    try
	    {
		CORBA_Object_var ir =
		    orb -> resolve_initial_references("InterfaceRepository");
	    }
	    catch(const CORBA_ORB::InvalidName&)
	    {
		cerr << argv[0]
		     << ": no `InterfaceRepository' initial reference."
		     << endl;
		return 1;
	    }

            typedFactory = new TypedEventChannelFactory_impl(orb, boa);
            orb -> connect(typedFactory, "DefaultTypedEventChannelFactory");

            try
            {
                typedChannel =
                    typedFactory -> create_channel("DefaultTypedEventChannel");
            }
            catch(OBEventChannelFactory_ChannelAlreadyExists&)
            {
		cerr << argv[0]
		     << ": `DefaultTypedEventChannel' already exists."
		     << endl;
		return 1;
            }

	    s = orb -> object_to_string(typedChannel);
	}

        //
        // Ensure everything is ready to run when the IOR is
        // displayed.
        //
        boa -> init_servers();
	
	//
	// Print IOR on standard output.
	//
	if(ior)
	    cout << s << endl;
	
	//
	// Run implementation.
	//
	boa -> impl_is_ready(CORBA_ImplementationDef::_nil());

	//
	// Destroy factory.
	//
	if(!typedService)
	    untypedFactory -> shutdown();
	else
	    typedFactory -> shutdown();
    }
    catch(const CORBA_SystemException& ex)
    {
	OBPrintException(ex);
	return 1;
    }
    
    return 0;
}
