/*
  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 examp6.cpp
   This example is to show use of the Composite types and pattern.
   
   In our scenario we have non-typed composites (other than the
   fact they are Equipment) and concrete equipment types (HardDrive,
   PowerSupply).
   
   We could have created concrete composites (Bus, Case, etc.) and
   added semantics to them. For example, is it semantically correct
   for a Case to have a hard-drive, or a Bus to have a power-supply?
   We leave that to the curious.
   
   We use the TransparentComponent to reduce the amount of type
   checking. This has its drawbacks as can be seen in the 
   recursion function "dumpComposites".
*/                   


#include <Common.hpp>
#include <TransparentComponent.hpp>
#include <EquipmentComposite.hpp>
#include <PowerSupply.hpp>
#include <HardDrive.hpp>

using namespace corelinux;

#include <iostream>
#include <exception>


//
// In module function prototypes
//

int   main( void );

//
// Routine to walk tree
//

void  dumpComposites( EquipmentRef );

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

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

int main( void )
{

   //
   // Practice gracefull exception management
   //

   cout << endl;

   try
   {
      //
      // Build up a part-whole hierarchy with
      // some composites
      //

      EquipmentComposite   aSystem("System");
      EquipmentComposite   aCase("Case");
      EquipmentComposite   aBus("Bus");

      //
      // And leafs
      //

      PowerSupply          aPowerSupply("200 Watt Supply");
      HardDrive            aHardDrive("40 Gigabyte Drive");

      //
      // Build up the hierarchy
      //

      aSystem.addComponent( &aCase );
      aCase.addComponent( &aPowerSupply );
      aCase.addComponent( &aBus );
      aBus.addComponent( &aHardDrive );

      dumpComposites(aSystem);

      //
      // Our composits rid themselves during
      // auto destruction.
      //


   }
   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;               
}

//
// A depth recursive routine which checks for 
// exceptions based on leaf/composite
//

void  dumpComposites( EquipmentRef aRef )
{
   Iterator<EquipmentPtr> *aIterator( NULLPTR );

   try
   {
      aIterator = aRef.createIterator();

      cout  << endl;
      cout  << "Composite : " << aRef.getName() << " has" ;

      //
      // If we have anything but the nul iterator, dig
      // deeper.
      //

      if( aIterator->isValid() )
      {
         cout << " components " << " with a total power requirement of " << 
            aRef.getPower() << " watts." << endl;

         do
         {
            dumpComposites( *aIterator->getElement() );
            aIterator->setNext();

         } while( aIterator->isValid() );
      }
      else
      {
         cout  << " no components." << endl;
      }

      //
      // Because of the implementation, this step
      // is optional as the composit maintains the
      // list of iterators that it "loans" out. BUT
      // this is memory friendly in larger scale
      // scenarios
      //

      aRef.destroyIterator( aIterator );
   }

   //
   // This shows how the transparent type implementation needs to
   // watch for using leaves in a composit scenario.
   //

   catch( InvalidCompositeExceptionRef icExcp )
   {
      cerr << "Attempt to access a leaf as composite exception" << endl;
      cerr << aRef.getName() << " is a Leaf not a composite!" << endl;
      cout << aRef.getName() << " requires " << aRef.getPower() << " watts." << endl;
   }

}


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


