/*
 * Event log factory example.
 */

#include "EventLogExample.h"

#define LOG_EVENTS 10

EventLogExample::EventLogExample (CORBA::ORB_ptr orb, ObjectAdapter &adapter)
  : orbVar_ (CORBA::ORB::_duplicate (orb)),
    adapter_ (adapter),
    eventLogFactoryVar_ (0),
    proxyVar_ (0)
{
  if (CORBA::is_nil (orbVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("ERROR: ORB not initialised\n")));
    }
}

int
EventLogExample::init (void)
{
  // Resolve to the event log factory.
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Resolving to event log factory\n")));
  try
    {
      CORBA::Object_var objVar =
        orbVar_->resolve_initial_references (ACE_TEXT ("EventLogFactory"));

      eventLogFactoryVar_ =
        DsEventLogAdmin::EventLogFactory::_narrow (objVar.in ());
      if (CORBA::is_nil (eventLogFactoryVar_.in ()))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Narrowed to a null event log factory\n")),
                            -1);
        }

      return 0;
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to resolve to event log factory\n"));
      return -1;
    }
}

DsEventLogAdmin::EventLog_ptr
EventLogExample::create (void)
{
  try
    {
      DsLogAdmin::LogFullActionType logFullAction = DsLogAdmin::wrap;
      CORBA::ULongLong max_size = 0; // 0 means "infinite"
      DsLogAdmin::LogId logId = 0;

      DsLogAdmin::CapacityAlarmThresholdList *tmp = 0;
      ACE_NEW_THROW_EX (tmp,
                        DsLogAdmin::CapacityAlarmThresholdList ((CORBA::ULong)75),
                        CORBA::NO_MEMORY ());
      DsLogAdmin::CapacityAlarmThresholdList_var thresVar = tmp;

      DsEventLogAdmin::EventLog_var eventLogVar =
        eventLogFactoryVar_->create (logFullAction, max_size, thresVar.in (), logId);

      if (CORBA::is_nil (eventLogVar.in ()))
        {
          ACE_ERROR ((LM_ERROR, ACE_TEXT ("ERROR: Event log is null\n")));
          return 0;
        }

      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Created log with id: %i\n"), logId));
      return eventLogVar._retn ();
    }
  catch (const DsLogAdmin::InvalidLogFullAction &ilfa)
    {
      ilfa._tao_print_exception (ACE_TEXT ("ERROR: Event log creation failed with InvalidLogFullAction\n"));
      throw;
    }
  catch (const DsLogAdmin::InvalidThreshold &it)
    {
      it._tao_print_exception (ACE_TEXT ("ERROR: Event log creation failed with InvalidThreshold\n"));
      throw;
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Event log creation failed\n"));
      throw;
    }

  return 0;
}

void
EventLogExample::connect (DsEventLogAdmin::EventLog_ptr channel)
{
  try
    {
      // Create the supplier reference.
      PortableServer::POA_var poaVar = adapter_.getPOA ();
      CORBA::Object_var objVar = poaVar->servant_to_reference (this);
      CosEventComm::PushSupplier_var supplierVar =
        CosEventComm::PushSupplier::_narrow (objVar.in ());

      // Obtain a proxy.
      CosEventChannelAdmin::SupplierAdmin_var adminVar =
        channel->for_suppliers ();
      proxyVar_ = adminVar->obtain_push_consumer ();

      // Perform the connection.
      proxyVar_->connect_push_supplier (supplierVar.in ());

      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Connected supplier to log channel\n")));
    }
  catch (const CosEventChannelAdmin::AlreadyConnected &ac)
    {
      ac._tao_print_exception (ACE_TEXT ("ERROR: Failed to connect -- proxy is already connected\n"));
      throw;
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to connect\n"));
      throw;
    }
}

void
EventLogExample::generate (void)
{
  CORBA::Any any;
  char message[30];

  for (int i = 0; i < LOG_EVENTS; ++i)
    {
      ACE_OS::sprintf (message, ACE_TEXT ("Event Log message # %d"), i);

      any <<= CORBA::String_var (CORBA::string_dup (message));

      try
        {
          proxyVar_->push (any);
        }
      catch (const CORBA::Exception &ex)
        {
          ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to push message\n"));
          throw;
        }
    }

  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Generated some log messages\n")));
}

void
EventLogExample::disconnect (void)
{
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Disconnecting supplier from log channel\n")));

  try
    {
      proxyVar_->disconnect_push_consumer ();

      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Disconnected supplier from log channel\n")));
    }
  catch (const CORBA::SystemException &se)
    {
      se._tao_print_exception (ACE_TEXT ("ERROR: Failure while disconnecting\n"));
      throw;
    }
}

void
EventLogExample::disconnect_push_supplier (void)
{
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Disconnect callback invoked\n")));
}

int
main (int argc, char **argv)
{
  try
    {
      // Get the orb reference and start the thread (non-blocking).
      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Initialising ORB\n")));
      CORBA::ORB_var orbVar = CORBA::ORB_init (argc, argv);

      // Create the example.
      ObjectAdapter adapter (orbVar.in ());
      EventLogExample *pExample = 0;
      ACE_NEW_THROW_EX (pExample,
                        EventLogExample (orbVar.in (), adapter),
                        CORBA::NO_MEMORY ());
      PortableServer::ServantBase_var holder (pExample);
      if (pExample->init ())
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Couldn't init servant\n")),
                            -1);
        }
      adapter.createTransient (pExample);

      // Run the example.
      DsEventLogAdmin::EventLog_var logVar =
        pExample->create ();
      pExample->connect (logVar.in ());
      pExample->generate ();
      pExample->disconnect ();

      orbVar->destroy ();
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Test failed\n"));
      return -1;
    }

  return 0;
}
