// **********************************************************************
//
// 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/Hashtable.h>
#include <OB/NTService.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 <EventMsg.h>

#include <NTEventService.h>

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

// ----------------------------------------------------------------------
// NTEventService constructor
// ----------------------------------------------------------------------

NTEventService::NTEventService()
    : OBNTService("EventService", "ORBacus Event Service", EVENT_MSG),
      stopped_(false)
{
}

// ----------------------------------------------------------------------
// NTEventService public member implementation
// ----------------------------------------------------------------------

void
NTEventService::start(int argc, char** argv)
{
    try
    {
	//
	// Create ORB and BOA
	//
        CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);

	bool typedService = false;

	//
	// 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;
	}
	
	//
	// 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);
	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::ConcModelThreaded);
        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);
        }

	//
	// 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");
            untypedChannel =
		untypedFactory -> create_channel("DefaultEventChannel");

	    s = orb -> object_to_string(untypedChannel);
	}
	else
	{
	    try
	    {
		CORBA_Object_var ir =
		    orb -> resolve_initial_references("InterfaceRepository");
	    }
	    catch(const CORBA_ORB::InvalidName&)
	    {
		OBMessageViewer::instance() ->
		    error("No `InterfaceRepository' initial reference");
		statusUpdate(SERVICE_STOPPED);
		return;
	    }

            typedFactory = new TypedEventChannelFactory_impl(orb, boa_);
            orb -> connect(typedFactory, "DefaultTypedEventChannelFactory");
            typedChannel =
                typedFactory -> create_channel("DefaultTypedEventChannel");

	    s = orb -> object_to_string(typedChannel);
	}

        //
        // Inform the status manager that the service is running.
        //
	statusUpdate(SERVICE_RUNNING);
        
	//
	// Run implementation
	//
        if(!stopped_)
            boa_ -> impl_is_ready(CORBA_ImplementationDef::_nil());
        boa_ = CORBA_BOA::_nil();

	//
	// Destroy factory.
	//
	if(!typedService)
	    untypedFactory -> shutdown();
	else
	    typedFactory -> shutdown();
    }
    catch(CORBA_SystemException& ex)
    {
	CORBA_String_var err = OBExceptionToString(ex);
	OBMessageViewer::instance() -> error(err);
    }
}

void
NTEventService::stop()
{
    stopped_ = true;
    if(!CORBA_is_nil(boa_))
        boa_ -> deactivate_impl(CORBA_ImplementationDef::_nil());
}
