/*
  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 examp12.cpp
   This example is to show use of the Proxy pattern.
   
   Our focus is on the use of restrictive access to accessors
   and mutators.
   
   Contributors
                                                                              
   AbstractBankAccount - which has the usual interface for fund management.
   
   BankAccount - Concrete implementation of above
   
   AccountProxy - Non-restrictive proxy which derives from subject
   
   RestrictedAccountProxy - subclass of AccountProxy which restricts access to
   deposits and displays only.

   Notes:
      
   By deriving the base AccountProxy from AbstractBankAccount, the proxy
   can be used as the latter (as in our example). But this is not required,
   if you want your application to expose the proxy types then you wouldn't
   need to derive from the domain types. This may prove more flexible in a
   complex class model.
   
*/                   


#include <Common.hpp>
#include <BankAccount.hpp>
#include <AccountProxy.hpp>
#include <RestrictedAccountProxy.hpp>

using namespace corelinux;
using namespace std;

#include <iostream>
#include <exception>

//
// Otherstuff
//


//
// In module function prototypes
//

int   main( void );

void  doWork( void );
void  addFunds( AbstractBankAccountPtr );
void  removeFunds( AbstractBankAccountPtr );
void  showBalance( AbstractBankAccountPtr );

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

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

int main( void )
{

   //
   // Practice gracefull exception management
   //

   cout << endl;

   try
   {
      doWork();
   }

   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  << "\tDeposit Funds     1" << endl;
   cout  << "\tWithdraw Funds    2" << endl;
   cout  << "\tDisplay Balance   3" << endl;
   cout  << "\tToggle Access     4" << endl;
   cout  << "\tQuit              5" << endl;
   cout  << endl;
}

Int   getCommand( void )
{
   displayMenu();

   Int   aOption;

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

   return aOption;
}

const Amount   startingBalance(20.0);

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

   //
   // Open an account with 20.00 dollars, assume full
   // access and manage funds
   //

   BankAccount             anAccount(startingBalance);
   AccountProxy            aProxy(&anAccount);
   RestrictedAccountProxy  aRProxy(&anAccount);
   AbstractBankAccountPtr  currentAccount(&aProxy);

   cout << "Account started with a fist full of dollars." << endl;
   do
   {
      Int   aCommand( getCommand() );

      if( aCommand > 5 || aCommand < 0 )
      {
         cerr << "You can't enter non-numeric options!" << endl;
         aCommand = 5;
      }
      else
      {
         ;  // do nothing
      }

      switch( aCommand )
      {
         //
         // Deposit funds
         //

         case  1:
            {
               addFunds( currentAccount );
               break;
            }

         //
         // Withdraw funds
         //

         case  2:
            {
               removeFunds( currentAccount );
               break;
            }

         //
         // Display balance
         //

         case  3:
            {
               showBalance( currentAccount );
               break;
            }

         //
         // Change access
         //

         case  4:
            {
               if( currentAccount == &aProxy )
               {
                  cout  << "Account now restricted." << endl;
                  currentAccount = &aRProxy;
               }
               else
               {
                  cout  << "Account restrictions disabled." << endl;
                  currentAccount = &aProxy;
               }
               break;
            }

         //
         // Exit routine
         //

         case  5:
            keepWorking=false;
            break;

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

}

//
// Deposit funds from the account
//

void  addFunds( AbstractBankAccountPtr aAccount )
{
   Amount   total(0.0);
   cout  << "Enter the amount of funds to deposit : ";
   cin   >> total;
   try
   {
      aAccount->depositFunds( total );
   }
   catch( InsufficientFundsExceptionRef aExcp )
   {
      cerr << aExcp.getWhy() << endl;
   }

   return;
}

//
// Withdraw funds from the account
//

void  removeFunds( AbstractBankAccountPtr aAccount )
{
   Amount   total(0.0);
   cout  << "Enter the amount of funds to withdraw : ";
   cin   >> total;
   try
   {
      aAccount->withdrawFunds( total );
   }
   catch( InsufficientFundsExceptionRef aExcp )
   {
      cerr << aExcp.getWhy() << endl;
   }

   return;
}

//
// Show the balance and please excuse the lack of
// locale sensitivity
//

void  showBalance( AbstractBankAccountPtr aAccount )
{
   cout  << "The total account balance : $ " << 
      aAccount->getBalance() << endl;

   return;
}

//
// 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:50:31 $
   $Locker:  $
*/


