/*===========================================================================*/
/*                                                                           */
/*                    Isaac Newton Group of Telescopes                       */
/*                   Roque de los Muchachos Observatory                      */
/*                               La Palma                                    */
/*                                                                           */
/*                        (c) Copyright PPARC 2007                           */
/*                                                                           */
/*===========================================================================*/
/*
COMPONENT:
   $Id: udas_corba_client.cc,v 1.8 2011/04/28 08:36:27 rab Exp $

TYPE:
   C++ source-code.

PURPOSE:
   CORBA C++ client library for the udas camera server.

PERSONNEL:
   Richard Bassom, Computer Software Group, ING.  rab@ing.iac.es


HISTORY:
   $Log: udas_corba_client.cc,v $
   Revision 1.8  2011/04/28 08:36:27  rab
   Modifed to prevent compiler warning of no return value in getOrb function.

   Revision 1.7  2009/09/01 14:26:52  rab
   Modifed to include stdio.h.

   Revision 1.6  2009/06/24 15:37:43  rab
   Fixed includes.

   Revision 1.5  2009/01/13 08:48:38  whtsm
   Added method to get an object reference from a stringified name service IOR.

   Revision 1.4  2007/12/07 13:56:36  rab
   Added method for a named host for the name service.

   Revision 1.3  2007/11/23 11:41:43  whtsm
   Modified for objects in root context.

   Revision 1.2  2007/07/25 13:48:24  rab
   Modified to throw exception rather than exit.

   Revision 1.1  2007/06/11 09:35:31  rab
   Udas CORBA client library functions.



--- End of module header information ----------------------------------------*/
#ifndef __lint
   const char udas_corba_client_cc[] = "@(#)$Id: udas_corba_client.cc,v 1.8 2011/04/28 08:36:27 rab Exp $";
#endif

/*- Feature test switches ---------------------------------------------------*/

/*- System headers ----------------------------------------------------------*/
#include <iostream>
#include <stdlib.h>
using namespace std;
#include <stdio.h>
#include <syslog.h>
#include <strings.h>
/* Header-files standardized by ANSI C: */

/*- Local headers -----------------------------------------------------------*/
#include <udas_camera_corba.hh>
/*- Local macros ------------------------------------------------------------*/

/*- Local typedefs, structures and unions -----------------------------------*/

/*- External data -----------------------------------------------------------*/
/*- Local data --------------------------------------------------------------*/


//////////////////////////////////////////////////////////////////////
// Get the CORBA orb from a named host
CORBA::ORB_var getOrb(int& argc,
                      char** argv,
                      const char* orb_identifier,
                      char * hostname)
{

   char     initRefOption[128]    = "InitRef";
   char     initRefParameter[128];
   CORBA::ORB_var orb;
   
   sprintf(initRefParameter, "NameService=corbaname::%s:35777", hostname);

   try {
// Initialise the ORB.
      const char*options[][2] = {
         {initRefOption,     initRefParameter},
         {0,0}
      };
      orb = CORBA::ORB_init(argc, argv, orb_identifier, options);
   }
   catch(CORBA::COMM_FAILURE& ex) {
      syslog(LOG_DEBUG, "Caught system exception COMM_FAILURE -- unable to contact the object.");   
      cerr << "Caught system exception COMM_FAILURE -- unable to contact the "
            << "object." << endl;
   }
   catch(CORBA::SystemException& se) {
      syslog(LOG_DEBUG, "Caught CORBA::SystemException.");
      cerr << "Caught CORBA::SystemException." << endl;
      cerr << "  mesg: " << se._name() << endl;
   }
   catch(CORBA::Exception&) {
      syslog(LOG_DEBUG, "Caught CORBA::Exception.");
      cerr << "Caught CORBA::Exception." << endl;
   }
   catch(omniORB::fatalException& fe) {
      syslog(LOG_DEBUG, "Caught omniORB::fatalException:");
      syslog(LOG_DEBUG, "  file: %s", fe.file());
      syslog(LOG_DEBUG, "  line: %d", fe.line());
      syslog(LOG_DEBUG, "  mesg: %s", fe.errmsg());
      cerr << "Caught omniORB::fatalException:" << endl;
      cerr << "  file: " << fe.file() << endl;
      cerr << "  line: " << fe.line() << endl;
      cerr << "  mesg: " << fe.errmsg() << endl;
   }
   catch(...) {
      syslog(LOG_DEBUG, "Caught unknown exception.");
      cerr << "Caught unknown exception." << endl;
   }

   return orb;
}

// Get the ORB from the relevant machine
CORBA::ORB_var getOrb(int& argc,
                      char** argv,
                      const char* orb_identifier)
{

// Set the name server initref dependent on the telescope in use
      char* telescope_name = getenv("TELESCOPE");
      char  hostname[128]  = "localhost";
      
      if (strcmp(telescope_name, "WHT") == 0)
         strcpy(hostname, "whtcns.ing.iac.es");

      else if (strcmp(telescope_name, "INT") == 0)
         strcpy(hostname, "intcns.ing.iac.es");
         
      return getOrb(argc, argv, orb_identifier, hostname);
      
}



//////////////////////////////////////////////////////////////////////
// Get the CORBA object reference

CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb,
                                     char * context_name, char * object_name)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var obj;
    obj = orb->resolve_initial_references("NameService");
//    cout << "NameService ref: " << orb->object_to_string(obj) << endl;

    // Narrow the reference returned.
    rootContext = CosNaming::NamingContext::_narrow(obj);
    if( CORBA::is_nil(rootContext) ) {
      cerr << "Failed to narrow the root naming context." << endl;
      return CORBA::Object::_nil();
    }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    // This should not happen!
    cerr << "Service required is invalid [does not exist]." << endl;
    return CORBA::Object::_nil();
  }


  // Create a name object, containing the name test/context:
  CosNaming::Name name;

  // If the context string is empty, then assume the root context
  if (strlen(context_name) == 0)
  {
     name.length(1);
     name[0].id   = (const char*) object_name;
     name[0].kind = (const char*) "";
  }
  else
  {
     name.length(2);

     name[0].id   = (const char*) context_name;       // string copied
     name[0].kind = (const char*) "";                 // string copied
     name[1].id   = (const char*) object_name;
     name[1].kind = (const char*) "";
  }
  // Note on kind: The kind field is used to indicate the type
  // of the object. This is to avoid conventions such as that used
  // by files (name.type -- e.g. test.ps = postscript etc.)


  try {
    // Resolve the name to an object reference.
    return rootContext->resolve(name);
  }
  catch(CosNaming::NamingContext::NotFound& ex) {
    // This exception is thrown if any of the components of the
    // path [contexts or the object] aren't found:
    cerr << "Context not found." << endl;
    cerr << "Unable to find the object: " << object_name << endl;
    throw ex;
    // exit (EXIT_FAILURE);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE -- unable to contact the "
         << "naming service." << endl;
    throw ex;
    // exit (EXIT_FAILURE);
  }
  catch(CORBA::SystemException& ex) {
    cerr << "Caught a CORBA::SystemException while using the naming service."
	 << endl;
//    throw CORBA::SystemExceptionex;
    // exit (EXIT_FAILURE);
  }

  return CORBA::Object::_nil();
}


//////////////////////////////////////////////////////////////////////
// Get the CORBA object reference from a named IOR

CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb,
                                     char * nameServiceIor,
                                     char * context_name, char * object_name)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var obj;

    obj = orb->string_to_object(nameServiceIor);

    // Narrow the reference returned.
    rootContext = CosNaming::NamingContext::_narrow(obj);
    if( CORBA::is_nil(rootContext) ) {
      cerr << "Failed to narrow the root naming context." << endl;
      return CORBA::Object::_nil();
    }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    // This should not happen!
    cerr << "Service required is invalid [does not exist]." << endl;
    return CORBA::Object::_nil();
  }


  // Create a name object, containing the name test/context:
  CosNaming::Name name;

  // If the context string is empty, then assume the root context
  if (strlen(context_name) == 0)
  {
     name.length(1);
     name[0].id   = (const char*) object_name;
     name[0].kind = (const char*) "";
  }
  else
  {
     name.length(2);

     name[0].id   = (const char*) context_name;       // string copied
     name[0].kind = (const char*) "";                 // string copied
     name[1].id   = (const char*) object_name;
     name[1].kind = (const char*) "";
  }
  // Note on kind: The kind field is used to indicate the type
  // of the object. This is to avoid conventions such as that used
  // by files (name.type -- e.g. test.ps = postscript etc.)


  try {
    // Resolve the name to an object reference.
    return rootContext->resolve(name);
  }
  catch(CosNaming::NamingContext::NotFound& ex) {
    // This exception is thrown if any of the components of the
    // path [contexts or the object] aren't found:
    cerr << "Context not found." << endl;
    cerr << "Unable to find the object: " << object_name << endl;
    throw ex;
    // exit (EXIT_FAILURE);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE -- unable to contact the "
         << "naming service." << endl;
    throw ex;
    // exit (EXIT_FAILURE);
  }
  catch(CORBA::SystemException& ex) {
    cerr << "Caught a CORBA::SystemException while using the naming service."
	 << endl;
//    throw ex;
    // exit (EXIT_FAILURE);
  }

  return CORBA::Object::_nil();
}

