// Purpose.  Chain of Responsibility design pattern demo
//
// Discussion.  Implements a "chain" of 4 processing elements: 2 that can
// handle LandSat images, and 2 for SPOT images.  Each element simulates a
// "busy" condition by making itself unavailable when it "accepts" an
// image, and then not resetting its availability until it has been
// unsuccessfully probed one time.  If an image is not "handled" the first
// time down the chain, it is recycled through the chain until it is
// handled.  The structure of the demo parallels the OMT diagram on p224.

#include <iostream.h>

enum ImageType { LSAT, SPOT };

class Image {
public:
   Image( ImageType type ) : _type(type) { }
   ImageType getType() { return _type; }
private:
   ImageType _type;
};


class ImageHandler {
public:
   // If derived class is not able to handle the request, it passes the
   // request to the next derived class downstream
   virtual void handleImage( Image* image ) { handler->handleImage(image); }
   // Set next downstream handler
   void setHandler( ImageHandler* inhand )  { handler = inhand; }
protected:
   ImageHandler( ImageHandler* inhand = 0 ) : handler(inhand), _avail(1) {
      _id = _counter++; }
   int IsAvailable() { return _avail; }
   int  _id;
   int  _avail;
   static int _counter;
private:
   // The next downstream handler
   ImageHandler* handler;
};

// "State" per instance mechanism
int ImageHandler::_counter = 1;


class LandSatHandler : public ImageHandler {
public:
   LandSatHandler( ImageHandler* inhand = 0 ) : ImageHandler(inhand) { }
   void handleImage( Image* image ) {
      // _avail should only be toggled if the request is of the correct type
      if (image->getType() == LSAT)
         if (_avail) {
            _avail--;
            cout << "LandSatHandler " << _id << " engaged\n" << endl;
            return; }
         else {
            _avail++;
            cout << "LandSatHandler " << _id << " busy" << endl; }
      // Request was not handled - pass the request downstream
      ImageHandler::handleImage( image ); }
};


class SpotHandler : public ImageHandler {
public:
   SpotHandler( ImageHandler* inhand = 0 ) : ImageHandler(inhand) { }
   void handleImage( Image* image ) {
      if (image->getType() == SPOT)
         if (_avail) {
            _avail--;
            cout << "SpotHandler " << _id << " engaged\n" << endl;
            return; }
         else {
            _avail++;
            cout << "SpotHandler " << _id << " busy" << endl; }
      ImageHandler::handleImage( image ); }
};


main()
{
   // Simulate an input stream of images
   Image  lsat(LSAT), spot(SPOT);
   Image* images[10] = { &lsat, &lsat, &lsat, &spot, &spot, &lsat, &lsat,
      &spot, &lsat, &spot };

   // Establish the chain: lsat1 => lsat2 => spot1 => spot2
   ImageHandler*  spot2 = new SpotHandler();
   ImageHandler*  spot1 = new SpotHandler( spot2 );
   ImageHandler*  lsat2 = new LandSatHandler( spot1 );
   ImageHandler*  lsat1 = new LandSatHandler( lsat2 );
   // Loop back to beginning of chain for unhandled requests
   spot2->setHandler( lsat1 );

   for (int i=0; i < 10; i++)
      lsat1->handleImage( images[i] );
}

// LandSatHandler 4 engaged
// 
// LandSatHandler 4 busy
// LandSatHandler 3 engaged
// 
// LandSatHandler 4 engaged
// 
// SpotHandler 2 engaged
// 
// SpotHandler 2 busy
// SpotHandler 1 engaged
// 
// LandSatHandler 4 busy
// LandSatHandler 3 busy
// LandSatHandler 4 engaged
// 
// LandSatHandler 4 busy
// LandSatHandler 3 engaged
// 
// SpotHandler 2 engaged
// 
// LandSatHandler 4 engaged
// 
// SpotHandler 2 busy
// SpotHandler 1 busy
// SpotHandler 2 engaged

