// This program may be used, executed, copied, modified and distributed
// without royalty for the purpose of developing, using, marketing, or
// distributing.

//
//----------------------------------------------------------------------------
// COMPONENT_NAME:
//
//  ORIGINS: 27
//
//  DISCLAIMER OF WARRANTIES.
//  The following [enclosed] code is sample code created by IBM
//  Corporation. This sample code is not part of any standard or IBM
//  product and is provided to you solely for the purpose of assisting
//  you in the development of your applications.  The code is provided
//  "AS IS". IBM MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT
//  NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//  FOR A PARTICULAR PURPOSE, REGARDING THE FUNCTION OR PERFORMANCE OF
//  THIS CODE.  THIS CODE MAY CONTAIN ERRORS.  IBM shall not be liable
//  for any damages arising out of your use of the sample code, even
//  if it has been advised of the possibility of such damages.
//
//  DISTRIBUTION.
//  This program may be used, executed, copied, modified and distributed
//  without royalty for the purpose of developing, using, marketing, or
//  distributing.
//

#include <stdlib.h>
#include <fstream.h>
#include <iostream.h>
#include <assert.h>

#include <PhoneBookEntry.hh>
#include <PhoneBookEntryKey.hh>
#include <PhoneBookEntryCopy.hh>
#include <CBSeriesGlobal.hh>
#include <IExtendedLifeCycle.hh>
#include <IManagedClient.hh>
#include <IBOIMManagedObjectFriendQOS.hh>


int main(int argc, char *argv[])
{
   cout << "\n\n************* Start of IMS/OTMA Sample Client Applicaiton\n" << endl;

   CORBA::ORB_ptr op = NULL;
   PhoneBookEntry_var pbePtr;
   PhoneBookEntry_var thePhoneBookEntry;
   IManagedClient::IManageable_var moPtr=NULL;


   try
   {
     // **** Call the CB Global Initializer

     cout << ">>>> Calling the Global Initialize Function...." << endl;
     CBSeriesGlobal::Initialize();
     cout << ">>>> Global Initialize Function Completed." << endl << endl;

     // **** End of the Global initialization


     // **** Find the PhoneBookEntry Factory

     cout << ">>>> Finding the PhoneBookEntry Factory....." << endl;
     IExtendedLifeCycle::FactoryFinder_var myFinder;
     CORBA::Object_var it = CBSeriesGlobal::nameService()->resolve_with_string("host/resources/factory-finders/host-scope");
     cout << ">>>> Name Service is located." << endl;

     myFinder = IExtendedLifeCycle::FactoryFinder::_narrow(it);
     assert( myFinder );
     it = myFinder->find_factory_from_string("PhoneBookEntry.object interface");
     assert( it );
     IManagedClient::IHome_var pbeHomeVar = IManagedClient::IHome::_narrow(it);
     assert( (pbeHomeVar) != NULL );
     cout << ">>>> PhoneBookEntry factory is found" << endl << endl;

     // **** End of the search for a Factory


     // **** Create a Key object for findByPrimaryString

     cout << ">>>> Preparing the account key...." << endl << endl;
     PhoneBookEntryKey_var theKey = PhoneBookEntryKey::_create();
     theKey->lastName("Smith");
     ByteString* theKeyString = theKey->toString();

     try
     {
        cout << ">>>>--- Checking if the phone book entry already exists....." << endl;
        moPtr = pbeHomeVar->findByPrimaryKeyString(*theKeyString);
     }
     catch(IManagedClient::INoObjectWKey &e)
        { cout <<  "  Expected ERROR in findByPrimaryKeyString call: " << e.id() << endl; }
     catch(IManagedClient::IInvalidKey &ik)
        { cout <<  "  Expected ERROR in findByPrimaryKeyString call: " << ik.id() << endl; }
     catch(CORBA::INV_OBJREF &io)
        { cout << "*** ERROR: This remove on the Managed Object should have worked" << endl;
          cout << "*** ERROR: Caught Exception: " << io.id() << endl; }
     catch(CORBA::SystemException &se)
        { cout << "*** ERROR: Caught System Exception: " << se.id() << endl; }
     catch(...)
        { cout <<  "  Expected ERROR in findByPrimaryKeyString call: Caught (...) "  << endl; }

     if(moPtr)
        cout << ">>>> The object ALREADY exists in the IMS datastore!!!" << endl << endl;
     else
     {
        cout << ">>>> PhoneBookEntry not found" << endl << endl;
        cout << ">>>>--- Creating PhoneBookEntry using CopyHelper......." << endl;

        // **** Prepare PhoneBookEntryCopy

        cout << ">>>> Prepare the copy helper object...." << endl;
        PhoneBookEntryCopy_var theCopy = PhoneBookEntryCopy::_create();
        theCopy->lastName("Smith");

        theCopy->firstName("Bob");

        theCopy->extNumber("3289");

        theCopy->internalZip("38961");
        ByteString* theCopyString = theCopy->toString();

        cout << "  Copy helper content: " << endl;
        cout << "    Name:         " << theCopy->firstName() << " " << theCopy->lastName() << endl;
        cout << "    Ext Number:   " << theCopy->extNumber() << endl;
        cout << "    Internal Zip: " << theCopy->internalZip() << endl << endl;


        try
        {
           moPtr = pbeHomeVar->createFromCopyString(*theCopyString);
        }
        catch(IManagedClient::IDuplicateKey e)
           { cout << "*** Caught IManagedClient::IDuplicateKey" << endl; }
        catch(IManagedClient::IInvalidCopy e)
           { cout <<  "*** Caught IManagedClient::IInvalidCopy" << endl; }
        catch(IManagedClient::IInvalidKey &ik)
           { cout <<  "*** Caught IManagedClient::IInvalidKey" << endl; }
        catch(CORBA::SystemException &se)
           { cout << "*** ERROR: Caught System Exception: " << se.id() << endl; }
        catch(...)
           { cout <<  "*** Unexpected ERROR in createFromCopyString call: Caught (...) "  << endl; }

        if(!moPtr)
        {
           cout << "*** ERROR: Unable to create a PhoneBookEntry Managed Object" << endl;
           return 1;
        }
        cout << ">>>> PhoneBookEntry MO created successfully." << endl << endl;
        delete theCopyString;
     }

     // **** Narrow the managed object pointer to the PhoneBookEntry interface
     pbePtr = PhoneBookEntry::_narrow( moPtr );

     if(!pbePtr)
     {
        cout << "*** Unable to narrow to a PhoneBookEntry type" << endl;
        return 1;
     }


     // **** Execute methods on the PhoneBookEntry  object

     char* name;
     ::CORBA::ULong  id;
     ::CORBA::Float  bal;


     char *lname, *fname, *ext, *zip;

     cout << ">>>> Displaying the values at the BO level: " << endl;
     pbePtr->showAll(lname, fname, ext, zip);
     cout << "       Name:         " << fname << " " << lname << endl;
     cout << "       Ext Number:   " << ext << endl;
     cout << "       Internal Zip: " << zip << endl << endl;

     cout << endl << ">>>>--- Modifying PhoneBookEntry....." << endl;

     pbePtr->firstName("Barney");
     pbePtr->extNumber("30909");
     pbePtr->internalZip("948-ABC");

     cout << ">>>> Values at the BO level (before checkpointing): " << endl;
     pbePtr->showAll(lname, fname, ext, zip);
     cout << "       Name:         " << fname << " " << lname << endl;
     cout << "       Ext Number:   " << ext << endl;
     cout << "       Internal Zip: " << zip << endl << endl;


     // **** Must do this to commit the change to the IMS datastore.

     IBOIMManagedObjectFriendQOS::IMMixin_var chkPtPtr =
         IBOIMManagedObjectFriendQOS::IMMixin::_narrow(pbePtr);
     if( CORBA::is_nil(chkPtPtr)) {
        cout << "*** Unable to narrow to a mixin" << endl;
        return 1;
      }

     cout << ">>>> Checkpointing to datatore....." << endl;
     chkPtPtr->checkpointToDatastore();


     cout << ">>>> Refreshing from datastore to make sure that data has been updated"
          << endl;

     chkPtPtr->refreshFromDatastore();

     cout << ">>>> Values after checkpointing: " << endl;


     pbePtr->showAll(lname, fname, ext, zip);
     cout << "       Name:         " << fname << " " << lname << endl;
     cout << "       Ext Number:   " << ext << endl;
     cout << "       Internal Zip: " << zip << endl << endl;


     cout << endl << ">>>>--- Making another modification....." << endl;

     pbePtr->firstName("Barton");
     pbePtr->extNumber("30000");
     pbePtr->internalZip("EMS-621");

     cout << ">>>> Values at the BO level (before checkpointing): " << endl;
     pbePtr->showAll(lname, fname, ext, zip);
     cout << "       Name:         " << fname << " " << lname << endl;
     cout << "       Ext Number:   " << ext << endl;
     cout << "       Internal Zip: " << zip << endl << endl;

     cout << ">>>> Undoing the changes by refreshing from datastore....."
          << endl;

     chkPtPtr->refreshFromDatastore();

     cout << ">>>> Values after refreshing: " << endl;


     pbePtr->showAll(lname, fname, ext, zip);
     cout << "       Name:         " << fname << " " << lname << endl;
     cout << "       Ext Number:   " << ext << endl;
     cout << "       Internal Zip: " << zip << endl << endl;


     cout << ">>>>--- Removing the account created by this sample......" << endl;
     pbePtr->remove();    // this object will not be retrievable anymore.
     cout << ">>>> PhoneBookEntry is removed" << endl << endl;



     //**** Clean up

     cout << endl << ">>>> Releasing variables used....." << endl;
     delete theKeyString;
     free(lname);
     free(fname);

     cout << ">>>> Variables have been released" << endl << endl;

   } // **** End of top level try{}

   catch (IManagedClient::IDuplicateKey &dk)
   {
      cout << "*** ERROR: IManagedClient::IDuplicateKey thrown, returning -1" << endl;
      cout << "*** exception id: " << dk.id() << endl;
      return -1;
   }
   catch (CORBA::SystemException &se)
   {
      cout << "*** ERROR: CORBA::SystemException thrown, returning -1" << endl;
      cout << "exception id: " << se.id() << endl;
      return 127;
   }
   catch (...)
   {
      cout << "*** ERROR: Exception thrown, exiting with value of -1" << endl;
      return 127;
   }

    cout << "************* End of IMS/OTMA Sample Client Application" << endl;
    cout << endl << endl;

   return 0;

} // **** end of func()
