// Purpose.  Memento design pattern

// 1. Assign the roles of "caretaker" and "originator"
// 2. Create a "memento" class and declare the originator a friend
// 3. Caretaker knows when to "check point" the originator
// 4. Originator creates a memento and copies its state to the memento
// 5. Caretaker holds on to (but cannot peek in to) the memento
// 6. Caretaker knows when to "roll back" the originator
// 7. Originator reinstates itself using the saved state in the memento

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

class Memento {                   // 2. Create a "memento" class and
   friend class Stack;            //    declare the originator a friend
   int *items, num;
   Memento( int* arr, int n ) {
      items = new int[num = n];
      for (int i=0; i < num; i++) items[i] = arr[i]; }
public:
   ~Memento() { delete items; }
};

class Stack {                     // 1. Stack is the "originator"
   int  items[10], sp;
public:
   Stack()                 { sp = -1; }
   void     push( int in ) { items[++sp] = in; }
   int      pop()          { return items[sp--]; }
   bool     isEmpty()      { return sp == -1; }
   // 4. Originator creates a memento and copies its state to the memento
   Memento* checkPoint() {
      return new Memento( items, sp+1 );
   }
   // 7. Originator reinstates itself using the saved state in the memento
   void rollBack( Memento* m ) {
      sp = m->num-1;
      for (int i=0; i < m->num; i++) items[i] = m->items[i];
   }
   friend ostream& operator<< ( ostream& os,  const Stack& s ) {
      string buf( "[ " );
      for (int i=0; i < s.sp+1; i++) { buf += s.items[i]+48;  buf += ' '; }
      buf += ']';
      return os << buf;                   // stack is [ 0 1 2 3 4 ]
}  };                                     // stack is [ 0 1 2 3 4 5 6 7 8 9 ]
                                          // popping stack: 9 8 7 6 5 4 3 2 1 0
// 1. main() is the "caretaker"           // stack is [ ]
void main( void ) {                       // second is [ 0 1 2 3 4 5 6 7 8 9 ]    
   Stack s;                               // first is [ 0 1 2 3 4 ]
   for (int i=0; i < 5; i++) s.push( i ); // popping stack: 4 3 2 1 0
   cout << "stack is " << s << endl;     
   Memento* first = s.checkPoint();       // 3. Caretaker knows when to save
   for (i=5; i < 10; i++) s.push( i );    // 5. Caretaker holds on to memento
   cout << "stack is " << s << endl;     
   Memento* second = s.checkPoint();      // 3. Caretaker knows when to save
   cout << "popping stack: ";             // 5. Caretaker holds on to memento
   while ( ! s.isEmpty()) cout << s.pop() << ' ';  cout << endl;
   cout << "stack is " << s << endl;
   s.rollBack( second );                  // 6. Caretaker knows when to undo
   cout << "second is " << s << endl;
   s.rollBack( first );                   // 6. Caretaker knows when to undo
   cout << "first is " << s << endl;
   cout << "popping stack: ";
   while ( ! s.isEmpty()) cout << s.pop() << ' ';  cout << endl;
   delete first;  delete second;
}



// Purpose.  Memento design pattern
//
// Discussion.  A memento is an object that stores a snapshot of the
// internal state of another object.  It can be leveraged to support
// multi-level undo of the Command pattern.  In this example, before a
// command is run against the Number object, Number's current state is
// saved in Command's static memento history list, and the command itself
// is saved in the static command history list.  Undo() simply "pops" the
// memento history list and reinstates Number's state from the memento.
// Redo() "pops" the command history list.  Note that Number's encapsula-
// tion is preserved, and Memento is wide open to Number.

#include <iostream.h>
class Number;

class Memento {
public:
   Memento( int val ) { _state = val; }
private:
   friend class Number;  // not essential, but p287 suggests this
   int  _state;
};

class Number {
public:
   Number( int value )                    { _value = value; }
   void dubble()                          { _value = 2 * _value; }
   void half()                            { _value = _value / 2; }
   int getValue()                         { return _value; }
   Memento* createMemento()               { return new Memento( _value ); }
   void  reinstateMemento( Memento* mem ) { _value = mem->_state ; }
private:
   int _value;
};

class Command {
public:
   typedef void (Number::* Action)();
   Command( Number* receiver, Action action ) {
      _receiver = receiver;
      _action = action; }
   virtual void execute() {
      _mementoList[_numCommands] = _receiver->createMemento();
      _commandList[_numCommands] = this;
      if (_numCommands > _highWater) _highWater = _numCommands;
      _numCommands++;
      (_receiver->*_action)(); }
   static void undo() {
      if (_numCommands == 0) {
         cout << "*** Attempt to run off the end!! ***" << endl;
         return; }
      _commandList[_numCommands-1]->_receiver->
         reinstateMemento( _mementoList[_numCommands-1] );
      _numCommands--; }
   void static redo() {
      if (_numCommands > _highWater) {
         cout << "*** Attempt to run off the end!! ***" << endl;
         return; }
      (_commandList[_numCommands]->_receiver->
         *(_commandList[_numCommands]->_action))();
      _numCommands++; }
protected:
    Number*         _receiver;
   Action          _action;
   static Command* _commandList[20];
   static Memento* _mementoList[20];
   static int      _numCommands;
   static int      _highWater;
};

Command* Command::_commandList[];
Memento* Command::_mementoList[];
int      Command::_numCommands = 0;
int      Command::_highWater   = 0;

void main() {
   int i;
   cout << "Integer: ";
   cin >> i;
   Number*   object = new Number(i);

   Command*  commands[3];
   commands[1] = new Command( object, &Number::dubble );
   commands[2] = new Command( object, &Number::half );

   cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: ";
   cin >> i;

   while (i)
   {
      if (i == 3)
         Command::undo();
      else if (i == 4)
         Command::redo();
      else
         commands[i]->execute();
      cout << "   " << object->getValue() << endl;
      cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: ";
      cin >> i;
   }
}

// Integer: 11
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2
//    5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 1
//    10
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2
//    5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
//    10
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
//    5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
//    11
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
// *** Attempt to run off the end!! ***
//    11
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
//    5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
//    10
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
//    5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
// *** Attempt to run off the end!! ***
//    5