/*
  CoreLinux++ 
  Copyright (C) 2000 CoreLinux Consortium
  
   The CoreLinux++ Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CoreLinux++ Library Library is distributed in the hope that it will 
   be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  
*/   

/** \example examp8.cpp
   This example is to show use of the Facade pattern, our 
   Facade (ObjectModel) is the application interface to the following:
   
   Dictionary(D) - maintains a collection of names for objects in the
   system. Names can be added and deleted from the Dictionary but there
   can be no collisions. The following methods are used:
   
         addName(string);
         changeName( string, string );
         removeName( string );
         getIdentifierForName( string );
         getNameForIdentifier( Identifier );
      
   Factory(F) - creates and destroys objects. If the object being asked for
   create is already in existence, it returns that instance.
   
         createObject( Identifier );
         destroyObject( Identifier );
   
   Modeler(M) - manages links between parents and children
   
         addParent( Identifier, Identifier );
         removeParent( Identifier, Identifier );
          getParents( Identifier );
   
   With the above, ObjectModel is all the user needs to create and maintain
   a hierarchy of objects.
   
   createObject("name");                  // Uses D  F, and M
   
   destroyObject("name");                 // Uses D, F, and M
   
   changeName("oldname","newname");       // Uses D
   
   addParent("childname","parentname");   // Uses D, F, and M
   
   removeParent("childname","parentname");// Uses D, F, and M
   
   display("name");                       // Uses D, F, and M
   
   Objects that are created have a parent ("Root") automatically assigned
   to them. This parent stays with them regardless of other relationships.
   
   For your own experimentation, you can change the semantics around but
   keep in mind they can get a little hairy, for example:
   
   1. Is it a cylical or acylical?
   2. Is it multi-inheritence or single?
   3. What is visibility?
   
*/                   


#include <Common.hpp>
#include <ObjectModel.hpp>

using namespace corelinux;


#include <iostream>
#include <exception>

//
// In module function prototypes
//

int   main( void );
void  displayMenu( void );
Int   getCommand( void );
void  doWork( ObjectModelRef );

//
// Functions that work with Engine types
//

void  handleAssertion( AssertionCref );
void  handleException( ExceptionCref );   

int main( void )
{

   //
   // Practice gracefull exception management
   //

   cout << endl;

   try
   {
      ObjectModel aModel("The Main Model");
      doWork(aModel);

   }

   catch( AssertionRef aAssert )
   {
      handleAssertion(aAssert);
   }
   catch( ExceptionRef aException )
   {
      handleException(aException);
   }
   catch( std::exception & e )
   {
      cerr  << e.what() << endl;
   }
   catch( ... )
   {
      cerr  << "Unknown exception." << endl;
   }

   return 0;               
}

void  displayMenu( void )
{
   cout  << endl;
   cout  << "\tCreate an object                 1" << endl;
   cout  << "\tDelete an object                 2" << endl;
   cout  << "\tChange object name               3" << endl;
   cout  << "\tAdd a parent to an objet         4" << endl;
   cout  << "\tRemove a parent from an object   5" << endl;
   cout  << "\tDisplay information on a object  6" << endl;
   cout  << "\tDisplay the entire model         7" << endl;
   cout  << "\tQuit the example                 8" << endl;
   cout  << endl;
}

Int   getCommand( void )
{
   displayMenu();

   Int   aOption;

   cout  << "Enter the option number on the right to execute :";
   cin   >> aOption;

   return aOption;
}

void  doWork( ObjectModelRef aModel )
{
   bool  keepWorking(true);

   do
   {
      Int   aCommand( getCommand() );

      switch( aCommand )
      {
         //
         // Create a new object
         //

         case  1:
            {
               string   aNewName;
               cout  << "Enter the name of the object to create : ";
               cin   >> aNewName;
               if( aNewName.empty() == false )
               {
                  aModel.createObject(aNewName);
                  cout << aNewName << " created!" << endl;
               }
               else
               {
                  cerr << "Not a valid name" << endl;
               }

               break;
            }

         //
         // Delete an object
         //

         case  2:
            {
               string   aName;
               cout  << "Enter the name of the object to delete : ";
               cin   >> aName;
               if( aName.empty() == false )
               {
                  aModel.destroyObject(aName);
                  cout  << aName << " deleted!" << endl;
               }
               else
               {
                  cerr << "Not a valid name" << endl;
               }
               break;
            }

         //
         // Change object name
         //

         case  3:
            {
               string   oldName,newName;
               cout  << "Enter the old name of the object : ";
               cin   >> oldName;
               cout  << "Enter the new name for the object : ";
               cin   >> newName;
               if( oldName.empty() == false &&
                   newName.empty() == false )
               {
                  aModel.changeName(oldName,newName);
                  cout << oldName << " changed to " << newName << endl;
               }
               else
               {
                  cerr << "Not a valid name" << endl;
               }
               break;
            }

         //
         // Add a parent to an object
         //

         case  4:
            {
               string   myName,parName;
               cout  << "Enter the object name  : ";
               cin   >> myName;
               cout  << "Enter the new parent object name : ";
               cin   >> parName;
               if( myName.empty() == false &&
                   parName.empty() == false )
               {
                  aModel.addParent(myName,parName);

                  cout << parName << " added as parent to " << 
                     myName << endl;
               }
               else
               {
                  cerr << "Not a valid name" << endl;
               }
               break;
            }

         //
         // Remove a parent from an object
         //

         case  5:
            {
               string   myName,parName;
               cout  << "Enter the object name  : ";
               cin   >> myName;
               cout  << "Enter the parent name to remove  : ";
               cin   >> parName;
               if( myName.empty() == false &&
                   parName.empty() == false )
               {
                  aModel.removeParent(myName,parName);

                  cout << parName << " removed as parent to " << 
                     myName << endl;
               }
               else
               {
                  cerr << "Not a valid name" << endl;
               }
               break;
            }

         //
         // Display object information
         //
         case  6:
            {
               string   aName;
               cout  << "Enter the name of the object to display : ";
               cin   >> aName;
               if( aName.empty() == false )
               {
                  aModel.display(aName,cout);
               }
               else
               {
                  cerr << "Not a valid name" << endl;
               }
               break;
            }

         //
         // Display entire model
         //

         case  7:
            aModel.display(cout);
            break;

         case  8:
            keepWorking=false;
            break;

         default:
            ;  //do nothing
            break;
      }
   } while( keepWorking == true );
}


//
// Peform default (just show it)
//

void  handleAssertion( AssertionCref aAssert )
{
   cerr << aAssert.getFile() << ":" << aAssert.getLine() << ":" << 
      "Assertion: ";

   if( aAssert.getType() == Assertion::NEVERGETHERE )
   {
      cerr << "NEVER_GET_HERE";
   }
   else
   {
      if( aAssert.getType() == Assertion::REQUIRE )
      {
         cerr  << "REQUIRE";
      }
      else if( aAssert.getType() == Assertion::ENSURE )
      {
         cerr  << "ENSURE";
      }
      else if( aAssert.getType() == Assertion::CHECK )
      {
         cerr  << "CHECK";
      }
      else 
      {
         cerr  << "ASSERT";
      }
      cerr << "( " << aAssert.getWhy() << " )";
   }

   cerr << endl;
}

void  handleException( ExceptionCref aExcp )
{
   cerr << aExcp.getFile() << ":" << aExcp.getLine() << ":" <<
      "Exception: " << aExcp.getWhy() << endl;
}

/*
   Common rcs information do not modify
   $Author: prudhomm $
   $Revision: 1.2 $
   $Date: 2000/08/31 22:47:57 $
   $Locker:  $
*/


