/*
  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 examp20.cpp
   This example is to show use of the Subject/Observer patterns.
   We basically rework ex19 so that the colleagues
   
   @li ListColleague     - Maintains a list of sentences that the user can edit
   @li SelectColleague   - Sets up the select of the sentence to edit
   @li EditColleague     - Provides editing for a sentence
      
   Now become subject AND observers themselves      
      
   @li List     - Maintains a list of sentences that the user can edit
   @li Select   - Sets up the select of the sentence to edit
   @li Edit     - Provides editing for a sentence
      
   and we ditch the Mediator. The above must be both Subject and Observer
   because they generate and listen for events.
      
   When something occurs in a Subject, it captures the state in a Memento
   which is made part of the Event. The Subject then calls the interested
   Observers event interface.
   
   The flow of traffic is:
   
   A) Lister updates the list and calls observers with a memento
      that contains the current list --> B
      
   B) Select is interested in list changes, so it receives an
      event with the current list.
      
   C) The main part of the application invokes Select to do it's thing, which
      is to display the list and allow for a selection. When a valid
      selection is received, it calls the mediator with a memento containing
      the text of the selection ---> D
      
   D) The Edit receives the event and displays the selected string
      with a edit prompt. It calls its observers with a memento that contains
      the original string, and the replacement string ---> E
      
   E) The List receives the event and updates it list and A then C.
   
   
   It behooves me to point out that the advantage of the Mediator implementation
   lies in the fact that the Colleagues have NO knowledge of other colleagues, 
   whereas the Subjects MUST know their observers. This may be limiting in some
   solution spaces. The choice, of course, is YOURS!!! Ain't life grand?
   
   Some improvements to this code would be makeing the Events prototypes
   for submitting to observer interest.
            
*/                   


#include <corelinux/Common.hpp>

#if   !defined(__LISTER_HPP)
#include <Lister.hpp>
#endif

#if   !defined(__EDIT_HPP)
#include <Edit.hpp>
#endif

#if   !defined(__SELECT_HPP)
#include <Select.hpp>
#endif

#if   !defined(__EVENTS_HPP)
#include <Events.hpp>
#endif

#if  !defined(__MEMENTOS_HPP)
#include <Mementos.hpp>
#endif

using namespace corelinux;

#include <iostream>
#include <exception>

//
// In module function prototypes
//

int   main( void );

//
// General Functions 
//

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

//
// Type declarations
//

//
// Global data
//

//
// Main entry point
//


int main( void )
{

   cout << endl;

   //
   // Practice graceful exception management
   //


   try
   {
      //
      // Instantiate Event prototypes
      //

      ListEntries aDummy;
      ListEvent   aListEvent( ListChanged,new ChangedListMemento( aDummy ) );
      ListEvent   aSelectEvent( SelectionMade,new SelectionMemento( "" ));
      ListEvent   aEditEvent( EditedEntry, new EditSelectionMemento("","") );

      //
      // Instantiate SubjectObserver types
      //

      Lister      aList;
      Edit        aEditor;
      Select      aSelection;

      //
      // Make the links
      //

      aList.addObserver
         ( 
            ObserverPtr(&aSelection), 
            (Event<Identifier>*)&aListEvent 
         );

      aEditor.addObserver
         ( 
            ObserverPtr(&aList), 
            (Event<Identifier>*)&aEditEvent 
         );

      aSelection.addObserver
         ( 
            ObserverPtr(&aEditor), 
            (Event<Identifier>*)&aSelectEvent 
         );

      //
      // Perform the work
      //

      aList.initialize();

      while( aSelection.getSelection() == true ) ;

      //
      // Clean somethings up
      //

      aSelection.removeObserver( ObserverPtr( &aEditor ) );
      aEditor.removeObserver( ObserverPtr( &aList ) );
      aList.removeObserver( ObserverPtr( &aSelection ) );

   }

   catch( NullPointerException aException )
   {
      cerr  << "Received NullPointerException!" << endl;
      handleException(aException);
   }
   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;               
}

//
// Some utility functions
//

//
// Error handlers
//

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:49:01 $
   $Locker:  $
*/


