#include <CORBA.h>
#include <time.h>

#include "Bank.h"
#include <mico/CosRelationships.h>
#include "Person.h"
#include "Ownership.h"
#include "Employment.h"


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

  //sleep (1);
  // client side
  cout << "Runing all tests\n";
  //cout << "Testing arguments..." << flush;
  assert (argc == 2);
  //cout << "correct.\n";

  Account_ptr account;
  CosRelationships::Role_ptr roles[100];
  CORBA::ULong roles_index = 0;
  CosRelationships::Relationship_ptr rel_ships[100];
  CORBA::ULong relships_index = 0;
  Person_ptr person;
  
  cout << "Binding to Bank ..." << flush;
  CORBA::Object_var obj = orb->bind ("IDL:Bank:1.0", argv[1]);
  assert (!CORBA::is_nil (obj));
  Bank_var bank;
  if (bank = Bank::_narrow (obj))
    cout << "done.\n";
  else
    cout << "ERROR!\n";
  
  //sleep (1);
  cout << "Binding to PersonFactory ..." << flush;
  CORBA::Object_var obj3 = orb->bind ("IDL:PersonFactory:1.0", argv[1]);
  assert (!CORBA::is_nil (obj3));
  PersonFactory_var pfactory;
  if (pfactory = PersonFactory::_narrow(obj3))
    cout << "done.\n";
  else
    cout << "ERROR!\n";


  //sleep (1);
  cout << "Binding to OwnerRoleFactory ..." << flush;
  CORBA::ORB::ObjectTag_var 
    tag2 = CORBA::ORB::string_to_tag ("OwnerRole_impl");
  CORBA::Object_var obj10 
    = orb->bind ("IDL:omg.org/CosRelationships/RoleFactory:1.0", 
		 tag2,
		 argv[1]);
  assert (!CORBA::is_nil (obj10));
  CosRelationships::RoleFactory_var owner_factory; 
  if (owner_factory = CosRelationships::RoleFactory::_narrow(obj10))
    cout << "done.\n";
  else
    cout << "ERROR!\n";

  cout << "Binding to OwnedByRoleFactory ..." << flush;
  CORBA::ORB::ObjectTag_var 
    tag3 = CORBA::ORB::string_to_tag ("OwnedByRole_impl");
  CORBA::Object_var obj11 
    = orb->bind ("IDL:omg.org/CosRelationships/RoleFactory:1.0", 
		 tag3,
		 argv[1]);
  assert (!CORBA::is_nil (obj11));
  CosRelationships::RoleFactory_var ownedby_factory; 
  if (ownedby_factory = CosRelationships::RoleFactory::_narrow(obj11))
    cout << "done.\n";
  else
    cout << "ERROR!\n";
  

  cout << "Binding to OwnershipFactory ..." << flush;
  CORBA::ORB::ObjectTag_var 
    tag11 = CORBA::ORB::string_to_tag ("Ownership_impl");
  CORBA::Object_var obj30 
    = orb->bind ("IDL:omg.org/CosRelationships/RelationshipFactory:1.0", 
		 tag11,
		 argv[1]);
  assert (!CORBA::is_nil (obj30));
  CosRelationships::RelationshipFactory_var ownership_factory;
  if (ownership_factory = CosRelationships::RelationshipFactory::_narrow(obj30))
    cout << "done.\n";
  else
    cout << "ERROR!\n";

  cout << "Create Account ..." << flush;
  //sleep (1);
  account = bank->create ();
  account->set (0);
  cout << "done.\n";
  account->deposit (100);
  cout << "Account balance is " << account->balance () << "\n";
 
  cout << "Create Person ..." << flush;
  person = pfactory->create_with_name (5466, 1976, 3, 21, 
						       "Franta", "Voprsalek");
  cout << "done.\n";
  cout << "name of person is " << person->first_name () << " " 
       << person->surname () << "\n";

  cout << "Creating owner role of person ..." << flush;

  CORBA::Boolean right_owner_role = TRUE;
  try {
    roles[roles_index] = owner_factory->create_role (person);
  }  
  catch (CosRelationships::RoleFactory::RelatedObjectTypeError_var &ex1)
    {
      cout << "RelatedObjectTypeError!\n";
      right_owner_role = FALSE;
    }

  if (right_owner_role) {
    cout << "done.\n";
    roles_index++;
  }

  cout << "Creating ownedby role of account ..." << flush;

  CORBA::Boolean right_ownedby_role = TRUE;
  try {
    roles[roles_index] = ownedby_factory->create_role (account);
  }  catch (CosRelationships::RoleFactory::RelatedObjectTypeError_var &ex1)
    {
      cout << "RelatedObjectTypeError!\n";
      right_ownedby_role = FALSE;
    }

  if (right_ownedby_role) {
    cout << "done.\n";
    roles_index++;
  }

  /*
  //sleep (1);
  Account_ptr tmp_acc = Account::_narrow (roles[1]->related_object ());
  cout << "balance of owned object is " << tmp_acc->balance() << "\n";
  */
  /*
  CORBA::release (tmp_acc);
  tmp_acc = Account::_narrow (role3->related_object ());
  cout << "balance of related object client2 is " << tmp_acc->balance() 
       << "\n";
       */

  Person_ptr tmp_person;
  tmp_person = Person::_narrow (roles[0]->related_object ());
  cout << "name of owner is " << tmp_person->first_name () 
       << " " << tmp_person->surname () << "\n";
  CORBA::release (tmp_person);

  Account_ptr tmp_acc = Account::_narrow (roles[1]->related_object ());
  cout << "balance of owned account is " << tmp_acc->balance() << "\n";


  CosRelationships::NamedRoles nr;
  nr.length (2);
  nr[0].name = CORBA::string_dup ("owner");
  nr[0].aRole = CosRelationships::Role::_duplicate (roles[0]);
  nr[1].name = CORBA::string_dup ("owned_thing");
  nr[1].aRole = CosRelationships::Role::_duplicate (roles[1]);

  cout << "Creating ownership between person and account ..." << flush;
 
  try {
    rel_ships[relships_index] = ownership_factory->create (nr);
  } 
  catch (CosRelationships::RelationshipFactory::DegreeError_var &ex) {
    cout << "DegreeError exception!!!\n";
    cout << "Required degree is " << ex->required_degree << "\n";
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
  } 
  catch (CosRelationships::RelationshipFactory::DuplicateRoleName_var &ex) {
    cout << "DuplicateRoleName exception!!!\n";
    cout << "ex->culprits.length () = " << (ex->culprits).length () << "\n";
    for (CORBA::ULong i=0; i<(ex->culprits).length () ; i++) {
      cout << i << ". name: " << (ex->culprits[i]).name.in() << "\n";
    }
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
  } 
  catch (CosRelationships::RelationshipFactory::UnknownRoleName_var &ex) {
    cout << "UnknownRoleName exception!!!\n";
    cout << "ex->culprits.length () = " << (ex->culprits).length () << "\n";
    for (CORBA::ULong i=0; i< (ex->culprits).length (); i++) {
      cout << i << ". name: " << (ex->culprits[i]).name.in() << "\n";
    }
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
    cout << "End of catch statement!\n";
  }

  if (!CORBA::is_nil (rel_ships[relships_index])) {
    cout << "done.\n";
    relships_index++;
  }

  CosRelationships::RelationshipIterator_var 
    iterator = CosRelationships::RelationshipIterator::_nil ();
  CosRelationships::RelationshipHandles* rel_handles;

  cout << "Invoke get_relationships () method on owner ..." << flush;
  roles[0]->get_relationships (0, rel_handles, iterator);
  cout << "done.\n";
  cout << "returned iterator is " << flush;
  if (CORBA::is_nil (iterator))
    cout << "NIL!!!\n";
  else  
    cout << "object.\n";
  cout << "Invoke next_n () method on returned iterator ..." << flush;
  iterator->next_n (10, rel_handles);
  cout << "done.\n";
  /*
  cout << "Returned RelationshipHandles sequence has " 
       << rel_handles->length () << " member(s).\n";
  cout << "number \t\t repoid \t\t\t\t constant_random_id\n";
  cout << "----------------------------------------------------------------"
       << "-----------\n";
  for (CORBA::ULong i=0; i<rel_handles->length (); i++) {
    cout << i+1 << ".\t" << (*rel_handles)[i].the_relationship->_repoid () 
	 << "\t\t\t" << (*rel_handles)[i].the_relationship->constant_random_id ()
	 << "\n";
  }
  */
  cout << "Returned RelationshipHandles sequence has " 
       << rel_handles->length () << " member(s).\n";
  cout << "number. repoid, constant_random_id\n";
  for (CORBA::ULong i=0; i<rel_handles->length (); i++) {
    cout << i+1 << ". " << (*rel_handles)[i].the_relationship->_repoid () 
	 << ", " << (*rel_handles)[i].the_relationship->constant_random_id ()
	 << "\n";
  }
  cout << "\n";
  cout << "Destroing objects" << flush;

  if (!CORBA::is_nil (iterator)) {
    iterator->destroy ();
    cout << "." << flush;
  }
  for (CORBA::ULong i=0; i<relships_index; i++)
    if (!CORBA::is_nil (rel_ships[i])) {
      rel_ships[i]->destroy ();
      cout << "." << flush;
    }
  for (CORBA::ULong i=0; i<roles_index; i++)
    if (!CORBA::is_nil (roles[i])) {
      roles[i]->destroy ();
      cout << "." << flush;
    }
    if (!CORBA::is_nil (account)) {
      account->destroy ();
      cout << "." << flush;
    }
    if (!CORBA::is_nil (person)) {
      person->destroy ();
      cout << "." << flush;
    }
  cout << "done.\n";
  return 0;
}


