// Purpose.  Visitor design pattern example
// 
// Discussion.  The Element hierarchy models an aggregate object
// structure.  It would be nice if "operations" could be added to this
// hierarchy without disturbing its implementation ("open for extension,
// closed for modification").  By introducing a single accept(Visitor&)
// member to Element, all "operations" can be modeled as a derived class
// of Visitor, and they can come and go without affecting the Element
// hierarchy.  Double dispatch is now valuable, because we would like to
// "do the right thing" based off the type of TWO objects - an Element
// object and a Visitor object.  Each Visitor derived class defines what
// it means for its "operation" to "visit" each Element derived class.
// 
// o The client sets up an Element aggregate.
// o The client declares a Visitor object for each desired operation.
// o The client steps through the Element objects, calling accept() (the
//   first dispatch) on each, and passing the Visitor derived class instance.
// o accept() in each Element derived class is implemented exactly the same.
// o accept() calls visit() (the second dispatch) on the Visitor argument,
//   passing its identity (and type).
// o The correct derived class of Visitor has now had flow of control
//   vectored to it, and it knows the correct derived class of its Element
//   argument.
// o The CallVisitor knows to only call doThis() on Foo objects, and doThat()
//   on Bar objects.
// o The TotalVisitor is able to "accumulate state" across an entire Element
//   aggregate without resorting to global variables.
// o The client can ask TotalVisitor for its accumulated state.

#include <iostream.h>

class Foo;
class Bar;

class Visitor {
public:
   virtual void visit( Foo* ) = 0;
   virtual void visit( Bar* ) = 0;
};

class CallVisitor : public Visitor {
public:
   void visit( Foo* );
   void visit( Bar* );                
};

class TotalVisitor : public Visitor {
public:
   TotalVisitor() {
      totalFoos_ = 0; totalBars_ = 0; }
   void visit( Foo* ) {
      cout << "TotalV: second dispatch." << endl;
      totalFoos_++; }
   void visit( Bar* ) {
      cout << "TotalV: second dispatch." << endl;
      totalBars_++; }
   void reportResults() {
      cout << totalFoos_ << " Foos and "<< totalBars_ << " Bars" << endl; }
private:
   int  totalFoos_, totalBars_;
};

class Element {
public:
   virtual void accept( Visitor& ) = 0;
};

class Foo : public Element {
public:
   void doThis() { cout << "Foo this" << endl; }
   void accept( Visitor& v ) {
      cout << "Foo: first dispatch.  ";
      v.visit( this ); }
};

class Bar : public Element {
public:
   void doThat() { cout << "Bar that" << endl; }
   void accept( Visitor& v ) {
      cout << "Bar: first dispatch.  ";
      v.visit( this ); }
};

void CallVisitor::visit( Foo* f ) {
   cout << "CallV:  second dispatch.  ";
   f->doThis(); }
void CallVisitor::visit( Bar* b ) {
   cout << "CallV:  second dispatch.  ";
   b->doThat(); }

main()
{
   Foo           aFoo;
   Bar           aBar;
   Element*      aBunch[5] = { &aFoo, &aBar, &aBar, &aFoo, &aFoo };
   CallVisitor   callV;
   TotalVisitor  totalV;

   for (int i=0; i < 5; i++)
      aBunch[i]->accept( callV );
   cout << endl;

   for (int i=0; i < 5; i++)
      aBunch[i]->accept( totalV );
   totalV.reportResults();
}

// Foo: first dispatch.  CallV:  second dispatch.  Foo this
// Bar: first dispatch.  CallV:  second dispatch.  Bar that
// Bar: first dispatch.  CallV:  second dispatch.  Bar that
// Foo: first dispatch.  CallV:  second dispatch.  Foo this
// Foo: first dispatch.  CallV:  second dispatch.  Foo this
// 
// Foo: first dispatch.  TotalV: second dispatch.
// Bar: first dispatch.  TotalV: second dispatch.
// Bar: first dispatch.  TotalV: second dispatch.
// Foo: first dispatch.  TotalV: second dispatch.
// Foo: first dispatch.  TotalV: second dispatch.
// 3 Foos and 2 Bars

