// client.cpp 
//              This is the client. It uses the COSS naming service
//              to obtain the object reference.
//
// Usage: client
//
//
//        On startup, the client looks up the object reference from the
//        COS naming service.
//
//        The name which the object is bound to is as follows:
//              root     [context]
//               |
//              test     [context] kind [my_context]
//               |
//          FrontOffice  [object]  kind [Object]
//

#include "front.h"
#include <iostream.h>

void bookSeat(CORBA::Object_ptr);
CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr);

int main ( int argc, char * argv[]) {
  // ORB initialization
  CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "omniORB2" );
  CORBA::BOA_var boa = orb->BOA_init (argc, argv, "omniORB2_BOA");

  try {
    CORBA::Object_var obj = getObjectReference(orb);
    bookSeat(obj);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
       << "object." << endl;
  }
  catch(omniORB::fatalException& ex) {
    cerr << "Caught omniORB2 fatalException. This indicates a bug is caught "
       << "within omniORB2.\nPlease send a bug report.\n"
       << "The exception was thrown in file: " << ex.file() << "\n"
       << "                            line: " << ex.line() << "\n"
       << "The error message is: " << ex.errmsg() << endl;
  }
  catch(...) {
    cerr << "Caught a system exception." << endl;
  }

  return 0;
}


void bookSeat(CORBA::Object_ptr obj) {
  FrontOffice_var foVar = FrontOffice::_narrow(obj);
  
  if (CORBA::is_nil(foVar)) {
    cerr << "Cannot invoke on a nil object reference.\n" << endl;
    return;
  }

  CORBA::String_var itsName = foVar->name();
  cout << "Name is " << itsName << endl;
  cout << "Number of seats is " << foVar->numberOfSeats()<< endl;
  cout << "Type row and seat to book: " << flush;

  CORBA::Char row;
  CORBA::ULong seat;
  cin >> row >> seat;

  Place p = {row, seat};
  cout << "Price of seat " << row << seat << " is "
     << foVar->getPrice(p) << "." << endl;
  
  if (foVar->bookSingleSeat(p, "4531 345 2222 3333"))
    cout << "Seat " << row << seat << " booked ok." << endl;
  else
    cout << "Seat " << row << seat << " cannot be booked." << endl;
}


// This function comes directly from the Echo example that comes with OmniORB
static 
CORBA::Object_ptr
getObjectReference(CORBA::ORB_ptr orb)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext)) 
      {
        cerr << "Failed to narrow naming context." << endl;
        return CORBA::Object::_nil();
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    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;
  name.length(2);

  name[0].id   = (const char*) "test";       // string copied
  name[0].kind = (const char*) "my_context"; // string copied
  name[1].id   = (const char*) "FrontOffice";
  name[1].kind = (const char*) "Object";
  // 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.)

  
  CORBA::Object_ptr obj;
  try {
    // Resolve the name to an object reference, and assign the reference 
    // returned to a CORBA::Object:
    obj = 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;
      return CORBA::Object::_nil();
    }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return CORBA::Object::_nil();
  }
  catch(omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return CORBA::Object::_nil();
  }
  return obj;
}
