/*
 * Basic log service example.
 */

#include "BasicLogExample.h"
#include "ace/Auto_Ptr.h"

#define LOG_EVENTS 4

BasicLogExample::BasicLogExample (CORBA::ORB_ptr orb)
  : orbVar_ (CORBA::ORB::_duplicate (orb)),
    basicLogFactoryVar_ (0)
{
  if (CORBA::is_nil (orbVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("ERROR: ORB not initialised\n")));
    }
}

int
BasicLogExample::init (void)
{
  // Resolve to the basic log factory.
  ACE_DEBUG ((LM_INFO, ACE_TEXT ("Resolving to basic log factory\n")));
  try
    {
      CORBA::Object_var objVar =
        orbVar_->resolve_initial_references (ACE_TEXT ("BasicLogFactory"));

      basicLogFactoryVar_ =
        DsLogAdmin::BasicLogFactory::_narrow (objVar.in ());
      if (CORBA::is_nil (basicLogFactoryVar_.in ()))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Narrowed to a null basic log factory\n")),
                            -1);
        }

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

DsLogAdmin::BasicLog_ptr
BasicLogExample::createLog (void)
{
  DsLogAdmin::LogFullActionType logFullAction = DsLogAdmin::wrap;
  CORBA::ULongLong max_size = 0; // 0 means "infinite"
  DsLogAdmin::LogId logId = 0;

  DsLogAdmin::BasicLog_var basicLogVar =
    basicLogFactoryVar_->create (logFullAction, max_size, logId);

  ACE_DEBUG ((LM_INFO, ACE_TEXT ("Created log with ID: %i\n"), logId));
  return basicLogVar._retn ();
}

void
BasicLogExample::writeLog (DsLogAdmin::BasicLog_ptr log)
{
  DsLogAdmin::Anys data (LOG_EVENTS);
  data.length (LOG_EVENTS);

  double d = 42.424242;
  int n = 123456789;
  char a = 'a';
  CORBA::String_var s = CORBA::string_dup (ACE_TEXT ("Hello world"));

  data[0] <<= s;
  data[1] <<= d;
  data[2] <<= n;
  data[3] <<= a;

  try
    {
      log->write_records (data);
    }
  catch (const DsLogAdmin::LogFull &)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("ERROR: Log is full\n")));
      throw;
    }
  catch (const DsLogAdmin::LogLocked &)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("ERROR: Log is locked\n")));
      throw;
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to write to log\n"));
      throw;
    }
}

void
BasicLogExample::queryLog (DsLogAdmin::BasicLog_ptr log)
{
  const char *grammar = ACE_TEXT ("EXTENDED_TCL");
  const char *constraint = ACE_TEXT ("$.info == 'Hello world'");

  try
    {
      ACE_DEBUG ((LM_INFO, ACE_TEXT ("Querying using constraint: %s\n"), constraint));
      DsLogAdmin::Iterator_var iterVar;
      DsLogAdmin::RecordList_var recordsVar =
        log->query (grammar, constraint, iterVar.out ());

      if (recordsVar->length () == 1)
        {
          ACE_DEBUG ((LM_INFO, ACE_TEXT ("As expected:\n")));
        }
      else
        {
          ACE_DEBUG ((LM_INFO, ACE_TEXT ("Expected 1:\n")));
        }

      ACE_DEBUG ((LM_INFO, ACE_TEXT ("-------------------------\n")));

      for (CORBA::ULong i = 0; i < recordsVar->length (); i++)
        {
          ACE_DEBUG ((LM_INFO,
                      ACE_TEXT ("The ID of the LogRecord matching the constraint <%s> is: %i\n"),
                      constraint, (CORBA::ULong)(recordsVar[i].id)));
          ACE_DEBUG ((LM_INFO, ACE_TEXT ("-------------------------\n")));
        }
    }
  catch (const DsLogAdmin::InvalidGrammar &ig)
    {
      ig._tao_print_exception (ACE_TEXT ("ERROR: Failed to query log: invalid grammar\n"));
      throw;
    }
  catch (const DsLogAdmin::InvalidConstraint &ic)
    {
      ic._tao_print_exception (ACE_TEXT ("ERROR: Failed to query log: invalid constraint\n"));
      throw;
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to query log\n"));
      throw;
    }
}

int
main (int argc, char **argv)
{
  try
    {
      ACE_DEBUG ((LM_INFO, ACE_TEXT ("Initialising ORB\n")));
      CORBA::ORB_var orbVar = CORBA::ORB_init (argc, argv);

      ACE_DEBUG ((LM_INFO, ACE_TEXT ("Running example\n")));
      BasicLogExample *pExample = 0;
      ACE_NEW_THROW_EX (pExample,
                        BasicLogExample (orbVar.in ()),
                        CORBA::NO_MEMORY ());
      ACE_Auto_Ptr<BasicLogExample> holder (pExample);
      if (pExample->init ())
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Couldn't init servant\n")),
                            -1);
        }

      DsLogAdmin::BasicLog_var logVar = pExample->createLog ();
      pExample->writeLog (logVar.in ());
      pExample->queryLog (logVar.in ());

      ACE_DEBUG ((LM_INFO, ACE_TEXT ("Destroying log\n")));
      logVar->destroy ();

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

  return 0;
}
