// Purpose.  Iterator design pattern

// Take traversal-of-a-collection functionality out of the collection and
// promote it to "full object status".  This simplifies the collection, allows
// many traversals to be active simultaneously, and decouples collection algo-
// rithms from collection data structures.

// "Every 'container-like' class must have an iterator." [Lakos]  It may seem
// like a violation of encapsulation for a Stack class to allow its users to
// access its contents directly, but John Lakos' argument is that the designer
// of a class inevitably leaves something out.  Later, when users need addi-
// tional functionality, if an iterator was originally provided, they can add
// functionality with "open for extension, closed for modification".  Without
// an iterator, their only recourse is to invasively customize production
// code.  Below, the orginal Stack class did not include an equality operator,
// but it did include an iterator.  As a result, the equality operator could
// be readily retrofitted.

// 1. Design an "iterator" class for the "container" class
// 2. Add a createIterator() member to the container class
// 3. Clients ask the container object to create an iterator object
// 4. Clients use the first(), isDone(), next(), and currentItem() protocol

#include <iostream>
using namespace std;

class Stack {
   int items[10];
   int sp;
public:
   friend class StackIter;
   Stack()             { sp = -1; }
   void push( int in ) { items[++sp] = in; }
   int  pop()          { return items[sp--]; }
   bool isEmpty()      { return (sp == -1); }
   StackIter* createIterator() const;      // 2. Add a createIterator() member
};

class StackIter {                          // 1. Design an "iterator" class
   const Stack* stk;
   int index;
public:
   StackIter( const Stack* s ) { stk = s; }
   void first()                { index = 0; }
   void next()                 { index++; }
   bool isDone()               { return index == stk->sp+1; }
   int  currentItem()          { return stk->items[index]; }
};

StackIter* Stack::createIterator() const { return new StackIter( this ); }

bool operator==( const Stack& l, const Stack& r ) {
   // 3. Clients ask the container object to create an iterator object
   StackIter* itl = l.createIterator();
   StackIter* itr = r.createIterator();
   // 4. Clients use the first(), isDone(), next(), and currentItem() protocol
   for (itl->first(), itr->first(); ! itl->isDone(); itl->next(), itr->next())
      if (itl->currentItem() != itr->currentItem()) break;
   bool ans = itl->isDone() && itr->isDone();
   delete itl;   delete itr;
   return ans;
}

void main( void ) {
   Stack  s1;
   for (int i=1; i < 5; i++) s1.push(i);
   Stack  s2( s1 ), s3( s1 ), s4( s1 ), s5( s1 );
   s3.pop();       s5.pop();
   s4.push( 2 );   s5.push( 9 );
   cout << "1 == 2 is "<< (s1 == s2) << endl;
   cout << "1 == 3 is "<< (s1 == s3) << endl;
   cout << "1 == 4 is "<< (s1 == s4) << endl;
   cout << "1 == 5 is "<< (s1 == s5) << endl;
}

// 1 == 2 is 1
// 1 == 3 is 0
// 1 == 4 is 0
// 1 == 5 is 0




// Purpose.  Iterator using operators instead of methods
//
// Discussion.  John Lakos suggests the GOF and STL iterator interfaces are:
// error-prone (possibility of misspelling method names), clumsy, and require
// too much typing.  This design uses nothing but "intuitive" operators.
// Notice also that no createIterator() was specified.  The user creates these
// iterators as local variables, and no clean-up is necessary.

#include <iostream>
using namespace std;

class Stack {
   int items[10];
   int sp;
public:
   friend class StackIter;
   Stack()             { sp = -1; }
   void push( int in ) { items[++sp] = in; }
   int  pop()          { return items[sp--]; }
   bool isEmpty()      { return (sp == -1); }
};

class StackIter {
   const Stack& stk;
   int index;
public:
   StackIter( const Stack& s ) : stk( s ) { index = 0; }
   void operator++() { index++; }
   bool operator()() { return index != stk.sp+1; }
   int  operator*()  { return stk.items[index]; }
};

bool operator==( const Stack& l, const Stack& r ) {
   StackIter itl( l ), itr( r );
   for ( ; itl(); ++itl, ++itr)
      if (*itl != *itr) break;
   return ! itl() && ! itr();
}

void main( void ) {
   Stack  s1;   int  i;
   for (i=1; i < 5; i++) s1.push(i);
   Stack  s2( s1 ), s3( s1 ), s4( s1 ), s5( s1 );
   s3.pop();       s5.pop();
   s4.push( 2 );   s5.push( 9 );
   cout << "1 == 2 is "<< (s1 == s2) << endl;
   cout << "1 == 3 is "<< (s1 == s3) << endl;
   cout << "1 == 4 is "<< (s1 == s4) << endl;
   cout << "1 == 5 is "<< (s1 == s5) << endl;
}

// 1 == 2 is 1
// 1 == 3 is 0
// 1 == 4 is 0
// 1 == 5 is 0




// Purpose.  Iterator using the Java interface
//
// Discussion.  Java's standard collection classes have a much leaner inter-
// face.  Their next() methods combine the next() and currentItem() methods.

#include <iostream>
using namespace std;

class Stack {
   int items[10];
   int sp;
public:
   friend class StackIter;
   Stack()             { sp = -1; }
   void push( int in ) { items[++sp] = in; }
   int  pop()          { return items[sp--]; }
   bool isEmpty()      { return (sp == -1); }
   StackIter* iterator() const;
};

class StackIter {
   const Stack* stk;
   int index;
public:
   StackIter( const Stack* s ) { stk = s;  index = 0; }
   int  next()                 { return stk->items[index++]; }
   bool hasNext()              { return index != stk->sp+1; }
};

StackIter* Stack::iterator() const { return new StackIter( this ); }

bool operator==( const Stack& l, const Stack& r ) {
   StackIter* itl = l.iterator();
   StackIter* itr = r.iterator();
   while (itl->hasNext())
      if (itl->next() != itr->next()) {
         delete itl;   delete itr;
         return false;
      }
   bool ans = (! itl->hasNext()) && ( ! itr->hasNext());
   delete itl;   delete itr;
   return ans;
}

void main( void ) {
   Stack  s1;   int  i;
   for (i=1; i < 5; i++) s1.push(i);
   Stack  s2( s1 ), s3( s1 ), s4( s1 ), s5( s1 );
   s3.pop();       s5.pop();
   s4.push( 2 );   s5.push( 9 );
   cout << "1 == 2 is "<< (s1 == s2) << endl;
   cout << "1 == 3 is "<< (s1 == s3) << endl;
   cout << "1 == 4 is "<< (s1 == s4) << endl;
   cout << "1 == 5 is "<< (s1 == s5) << endl;
}

// 1 == 2 is 1
// 1 == 3 is 0
// 1 == 4 is 0
// 1 == 5 is 0




// Purpose.  Simple implementation of an Iterator (uses parallel dynamic array)
//
// Discussion.  Instead of having to write an involved stack-like solution to
// handle step-wise recursive descent, use a little extra memory to maintain a
// sequential representation of the original hierarchical data.  The replicated
// data are not Node objects, they are lightweight pointers.  The array is
// initialized using a recursive method similar to traverse(Node*).

#include <iostream>
#include <ctime>
using namespace std;

class BST {
   friend class Iterator;
   struct Node {
      Node( int );
      int value;
      Node* left;
      Node* rite;
   };
   Node* root;
   int   size;
   void add( Node**, int );
   void traverse( Node* );
public:
   BST() { root = 0;  size = 0; }
   void add( int );
   void traverse();
   Iterator* createIterator() const;
};

class Iterator {
   const BST* tree;
   BST::Node** array;
   int index;
   void populateArray( BST::Node* current ) {
      if (current->left) populateArray( current->left );
      array[index++] = current;
      if (current->rite) populateArray( current->rite );
   }
public:
   Iterator( const BST* s ) {
      tree = s;
      array = 0;  index = 0;
   }
   ~Iterator() { delete [] array; }
   void first() {
      delete [] array;
      array = new BST::Node*[tree->size];
      index = 0;
      populateArray( tree->root );
      index = 0;
   }
   void next()              { index++; }
   bool isDone()            { return index == tree->size; }
   BST::Node* currentItem() { return array[index]; }
};

void main( void ) {
   srand( time( 0 ) );
   BST  tree;
   for (int i=0; i < 20; i++) tree.add( rand() % 20 + 1 );
   cout << "traverse: ";
   tree.traverse();
   cout << "\niterator: ";
   Iterator* it = tree.createIterator();
   for (it->first(); ! it->isDone(); it->next())
      cout << it->currentItem()->value << ' ';
   cout << "\niterator: ";
   for (it->first(); ! it->isDone(); it->next())
      cout << it->currentItem()->value << ' ';
   cout << '\n';
}

// traverse: 1 2 3 7 8 9 9 10 11 11 13 14 14 14 15 17 18 19 19 20
// iterator: 1 2 3 7 8 9 9 10 11 11 13 14 14 14 15 17 18 19 19 20
// iterator: 1 2 3 7 8 9 9 10 11 11 13 14 14 14 15 17 18 19 19 20


BST::Node::Node( int v ) { value = v;  left = rite = 0; }

void BST::add( Node** n, int v ) {
   if ( ! *n)                 { *n = new Node( v );  size++; }
   else if (v <= (*n)->value) add( &((*n)->left), v );
   else                       add( &((*n)->rite), v );
}

void BST::add( int v ) { add( &root, v ); }
void BST::traverse() { traverse( root ); }

void BST::traverse( Node* n ) {
   if (n->left) traverse( n->left );
   cout << n->value << ' ';
   if (n->rite) traverse( n->rite );
}

Iterator* BST::createIterator() const { return new Iterator( this ); }




// Purpose.  Fairly reusable iterator for step-wise recursive descent
//
// Discussion.  The Composite/Component/Leaf code is one of the previous
// Composite demos.  Methods added were: Component::outputValue() and
// Composite::createIterator().

#include <iostream>
#include <vector>
using namespace std;

class Component { public:
   virtual void traverse() = 0;
   virtual void outputValue() { }
};

class Leaf : public Component {
   int value;
public:
   Leaf( int val ) { value = val; }
   /*virtual*/ void traverse() { cout << value << ' '; }
   /*virtual*/ void outputValue() { traverse(); }
};

class Composite : public Component {
   vector<Component*> children;
public:
   friend class Iterator;
   void add( Component* ele ) { children.push_back( ele ); }
   /*virtual*/ void traverse() {
      for (int i=0; i < children.size(); i++)
         children[i]->traverse();
   }
   Iterator* createIterator();
};

class Memento {
public:
   struct MgrIdx {
      MgrIdx( Composite* m=0, int i=0 ) { mgr = m;  idx = i; }
      Composite* mgr;
      int        idx;
   };
   void initialize( Composite* root ) {
      vec.resize( 0 );
      vec.push_back( MgrIdx( root, 0 ) );
   }
   bool isEmpty()         { return vec.size() == 0; }
   void push( MgrIdx ds ) { vec.push_back( ds ); }
   MgrIdx top()           { return vec.back(); }
   MgrIdx pop() {
      MgrIdx ds = vec.back();
      vec.pop_back();
      return ds;
   }
private:
   vector<MgrIdx> vec;
};

// Dependencies on actual class playing the role of "Composite":
//    Composite class name, children attribute name
class Iterator {
   Composite* root;
   Memento    memento;
   bool       done;
public:
   Iterator( Composite* rooot ) { root = rooot; }
   void first() {
      memento.initialize( root );
      done = false;
   }
   void next() {
      Memento::MgrIdx ds = memento.pop();
      ds.idx++;
      // if (and while) you are at end-of-composite, go up
      while (ds.idx == ds.mgr->children.size()) {
         if (memento.isEmpty()) { done = true;  return; }
         ds = memento.pop();
         ds.idx++;
      }
      memento.push( ds );
      Composite* compo;
      if (compo = dynamic_cast<Composite*>(ds.mgr->children[ds.idx]))
         memento.push( Memento::MgrIdx( compo, 0 ) );
   }
   Component* currentItem() {
      Memento::MgrIdx ds = memento.top();
      return ds.mgr->children[ds.idx];
   }
   bool isDone() { return done; }
};

Iterator* Composite::createIterator() { return new Iterator( this ); }

void main( void ) {
   Composite containers[4];
   for (int i=0; i < 4; i++)
      for (int j=0; j < 3; j++)
         containers[i].add( new Leaf( i * 3 + j ) );
   for (i=1; i < 4; i++) containers[0].add( &(containers[i]) );
   cout << "traverse: ";
   containers[0].traverse();

   Iterator* it = containers[0].createIterator();
   cout << "\niterator: ";
   for (it->first(); ! it->isDone(); it->next())
      it->currentItem()->outputValue();
   cout << '\n';
   cout << "iterator: ";
   for (it->first(); ! it->isDone(); it->next())
      it->currentItem()->outputValue();
   cout << '\n';
   delete it;
}

// traverse: 0 1 2 3 4 5 6 7 8 9 10 11
// iterator: 0 1 2 3 4 5 6 7 8 9 10 11
// iterator: 0 1 2 3 4 5 6 7 8 9 10 11