#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 accs[100];
  CORBA::ULong accs_index = 0;
  CosRelationships::Role_ptr roles[100];
  CORBA::ULong roles_index = 0;
  CosRelationships::Relationship_ptr rel_ships[100];
  CORBA::ULong relships_index = 0;
  Person_ptr persons[100];
  CORBA::ULong persons_index = 0;

  
  //sleep (1);
  cout << "Binding to AccountFactory (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 << "Checking role_type ()  ..." << flush;
  CORBA::InterfaceDef_ptr interface = owner_factory->role_type ();
  if (!CORBA::is_nil (interface))
    cout << "ok.\n";
  else
    cout << "error.\n";

  cout << "Checking relationship_type ()  ..." << flush;
  CORBA::InterfaceDef_ptr interface2 = ownership_factory->relationship_type ();
  if (!CORBA::is_nil (interface2))
    cout << "ok.\n";
  else
    cout << "error.\n";

  /*
  CORBA::InterfaceDef::FullInterfaceDescription_var full_of_role
      = interface2 ->describe_interface ();
  cout << "name: " << full_of_role->name << "\n";
  cout << "id: " << full_of_role->id << "\n";
  cout << "defined_in: " << full_of_role->defined_in
       << "\n";
       */



  //sleep (1);
  accs_index = 0;
  accs[accs_index] = bank->create ();
  accs[accs_index]->set (0);
  accs[accs_index]->deposit (100);
  accs_index++;
  accs[accs_index] = bank->create ();
  accs[1]->set (0);
  accs[1]->deposit (200);
  accs_index++;
 
  persons[persons_index] = pfactory->create_with_name (5466, 1976, 3, 21, 
						       "Karel", "Gardas");
  persons_index++;
  persons[persons_index] = pfactory->create_with_name (9787, 1975, 9, 12,
						       "Olga", "Psenicova");
  persons_index++;
  
  cout << "Checking create_role ()  ..." << flush;
  CORBA::Boolean right_owner_role = TRUE;
  try {
    roles[roles_index] = owner_factory->create_role 
      (Person::_duplicate (persons[0]));
  }  
  catch (CosRelationships::RoleFactory::RelatedObjectTypeError_var &ex1)
    {
      cout << "RelatedObjectTypeError!\n";
      right_owner_role = FALSE;
    }

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

  cout << "Checking related_object ()  ..." << flush;
  Person_ptr tmp_person;
  tmp_person = Person::_narrow (roles[0]->related_object ());
  if (!CORBA::is_nil (tmp_person))
    cout << "ok.\n";
  else {
    cout << "error!\n";
    exit (1);
  }

  cout << "Checking RelatedObjectTypeError exception  ..." << flush;
  CORBA::Boolean exception = FALSE;

  try {
    roles[roles_index] = ownedby_factory->create_role 
      (Person::_duplicate (persons[0]));
  }  catch (CosRelationships::RoleFactory::RelatedObjectTypeError_var &ex1)
    {
      exception = TRUE;
    }

  if (exception)
    cout << "ok.\n";
  else {
    cout << "error!\n";
    exit (1);
  }

  cout << "Checking NilRelatedObject exception  ..." << flush;
  exception = FALSE;
  /*
  cout << "roles_index: " << roles_index << "\n";
  if (CORBA::is_nil (ownedby_factory))
    cout << "ownedby_factory is NIL!\n";
  else
    cout << "ownedby_factory is object.\n";
    */
  try {
    roles[roles_index] = ownedby_factory->create_role (Account::_nil ());
  }  catch (CosRelationships::RoleFactory::NilRelatedObject_var &ex1)
    {
      exception = TRUE;
    }

  if (exception)
    cout << "ok.\n";
  else {
    cout << "error!\n";
    exit (1);
  }

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

  if (right_ownedby_role) {
    roles_index++;
  }

  cout << "Checking create () (of relationship)  ..." << flush;
  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]);
 
  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 << "ok.\n";
    relships_index++;
  }

  exception = FALSE;
  cout << "Checking UnknownRoleName exception  ..." << flush;
  nr.length (2);
  nr[0].name = CORBA::string_dup ("owner-haha");
  nr[0].aRole = CosRelationships::Role::_duplicate (roles[0]);
  nr[1].name = CORBA::string_dup ("owned_thing");
  nr[1].aRole = CosRelationships::Role::_duplicate (roles[1]);
 
  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 << "\n";
    }
    */
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
    exception = TRUE;
  }

  if (exception) {
    cout << "ok.\n";
  }
  else 
    cout << "error!\n";


  exception = FALSE;
  cout << "Checking DuplicateRoleName exception  ..." << flush;
  nr.length (2);
  nr[0].name = CORBA::string_dup ("owner");
  nr[0].aRole = CosRelationships::Role::_duplicate (roles[0]);
  nr[1].name = CORBA::string_dup ("owner");
  nr[1].aRole = CosRelationships::Role::_duplicate (roles[1]);
 
  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 << "\n";
    }
    */
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
    exception = TRUE;
  } 
  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 (exception) 
    cout << "ok.\n";
  else
    cout << "error!\n";


  exception = FALSE;
  cout << "Checking DegreeError exception  ..." << flush;
  nr.length (3);
  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]);
  nr[2].name = CORBA::string_dup ("owner");
  nr[2].aRole = CosRelationships::Role::_duplicate (roles[0]);

 
  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 ();
    exception = TRUE;
  } 
  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 (exception) 
    cout << "ok.\n";
  else
    cout << "error!\n";


  exception = FALSE;
  cout << "Checking RoleTypeError exception  ..." << flush;
  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[0]);  // owner role
 
  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";
  }
  catch (CosRelationships::RelationshipFactory::RoleTypeError_var &ex) {
    /*
    cout << "RoleTypeError 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 << "\n";
    }
    */
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
    exception = TRUE;
  }

  if (exception)
    cout << "ok.\n";
  else
    cout << "error!\n";


  exception = FALSE;
  cout << "Checking MaxCardinalityExceeded exception  ..." << flush;
  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]);
 
  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";
  }
  catch (CosRelationships::RelationshipFactory::MaxCardinalityExceeded_var &ex) {
    /*
    cout << "MaxCardinalityExceeded 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 << "\n";
    }
    */
    rel_ships[relships_index] = CosRelationships::Relationship::_nil ();
    exception = TRUE;
  }


  if (exception)
    cout << "ok.\n";
  else
    cout << "error!\n";


  cout << "Checking get_relationships ()  ..." << flush;
  CosRelationships::RelationshipIterator_var 
    iterator = CosRelationships::RelationshipIterator::_nil ();
  CosRelationships::RelationshipHandles* rel_handles;
  rel_handles = NULL;
  roles[0]->get_relationships (3, rel_handles, iterator);
  if ((rel_handles != NULL) && (CORBA::is_nil (iterator))) {
    rel_handles = NULL;
    iterator = CosRelationships::RelationshipIterator::_nil ();
    roles[0]->get_relationships (0, rel_handles, iterator);
    if ((rel_handles->length () == 0) && (!CORBA::is_nil (iterator)))
      cout << "ok.\n";
    else
      cout << "error!\n";
  }
  else
    cout << "ERROR!\n";

  cout << "Checking next_n ()  ..." << flush;
  iterator->next_n (10, rel_handles);
  if (rel_handles->length () == 1 && 
      ( (*rel_handles)[0].the_relationship->is_identical (rel_ships[0])))
    cout << "ok.\n";
  else
    cout << "error!\n";
  iterator->destroy ();

  cout << "Checking next_one ()  ..." << flush;
  CosRelationships::RelationshipHandle* rel_handle;
  roles[0]->get_relationships (0, rel_handles, iterator);
  iterator->next_one (rel_handle);
  if (rel_handle->the_relationship->is_identical (rel_ships[0]))
    cout << "ok.\n";
  else
    cout << "error!\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;
    }
  for (CORBA::ULong i=0; i<accs_index; i++)
    if (!CORBA::is_nil (accs[i])) {
      accs[i]->destroy ();
      cout << "." << flush;
    }
  for (CORBA::ULong i=0; i<persons_index; i++)
    if (!CORBA::is_nil (persons[i])) {
      persons[i]->destroy ();
      cout << "." << flush;
    }


  cout << "done.\n";
  return 0;
}


