// Purpose.  State                      #include <iostream.h>
//
// Discussion.  The boss's behavior is  class Boss {
// "morphing" radically as a function   public:
// of his mood.  Operations have large     friend class Disposition;
// "case" constructs that depend on        Boss();
// this "state" attribute.  Like large     void decide();
// procedures, large conditional stmts     void direct();
// are undesirable.  They're monolith-  private:
// ic, and tend to make maintenance        Disposition*  moods_[2];
// very difficult.  The State pattern      int           current_;
// models individual states with de-    };
// rived classes of an inheritance
// hierarchy, and front-ends this       class Disposition {
// hierarchy with an "interface"        public:
// object that knows its "current"         virtual void decide( Boss* ) = 0;
// state.  This partitions and local-      virtual void direct( Boss* ) = 0;
// izes all state-specific responsi-    protected:
// bilities; allowing for a cleaner        void toggle( Boss* b ) {
// implementation of dynamic behavior         b->current_ = ! b->current_; }
// that must change as internal state   };
// changes.
                                        class DilbertZone :
class Boss {                                  public Disposition { public:
public:                                    void decide( Boss* b ) {
   Boss() {                                   cout << "Eenie, meenie, mynie,";
      mood_ = DilbertZone;                    cout << " moe.\n";  toggle(b); }
   }                                       void direct( Boss* b ) {
   void decide() {                            cout << "My whim - you're";
      if (mood_ == DilbertZone) {             cout << " nightmare.\n";
         cout << "Eenie, meenie,";            toggle(b); }
         cout << " mynie, moe.\n";      };
      }                                 class Sunny :
      else if (mood_ == Sunny) {              public Disposition { public:
         cout << "You need it - you";      void decide( Boss* b ) {
         cout << " got it.\n";                cout << "You need it - you got";
      }                                       cout << " it.\n";  toggle(b); }
      toggle();                            void direct( Boss* b ) {
   }                                          cout << "Follow me.\n";
   void direct() {                            toggle(b); }
      if (mood_ == DilbertZone) {       };
         cout << "My whim - you're";
         cout << " nightmare.\n";       Boss::Boss() {
      }                                    moods_[0] = new DilbertZone;
      else if (mood_ == Sunny)             moods_[1] = new Sunny;
         cout << "Follow me.\n";           current_ = 0; }
      toggle();                         void Boss::decide() {
   }                                       moods_[current_]->decide( this ); }
private:                                void Boss::direct() {
   enum Disposition { Sunny,               moods_[current_]->direct( this ); }
                      DilbertZone};
   Disposition  mood_;                  void main( void )
   void toggle() { mood_ = ! mood_; }   {
};                                         Boss ph;
                                           for (int i=0; i < 2; i++) {
void main( void )                             ph.decide();
{                                             ph.decide();
   Boss ph;                                   ph.direct(); }
   for (int i=0; i < 2; i++)            }
   {                                    // Eenie, meenie, mynie, moe.
      ph.decide();                      // You need it - you got it.
      ph.decide();                      // My whim - you're nightmare.
      ph.direct();                      // You need it - you got it.
   }                                    // Eenie, meenie, mynie, moe.
}                                       // Follow me.




// Purpose.  State design pattern - an FSM with two states and
// two events (distributed transition logic - logic in the
// derived state classes)

#include <iostream>                     \ Event    on      off
using namespace std;               State \      -------  -------
                                    ON          nothing    OFF
class Machine {                     OFF           ON     nothing
   class State* current;
public:
   Machine();
   void setCurrent( State* s ) { current = s; }
   void on();
   void off();
};

class State {
public:
   virtual void on( Machine* m )  { cout << "   already ON\n"; }
   virtual void off( Machine* m ) { cout << "   already OFF\n"; }
};

void Machine::on()  { current->on(  this ); }
void Machine::off() { current->off( this ); }

class ON : public State {
public:
   ON()  { cout << "   ON-ctor ";  };
   ~ON() { cout << "   dtor-ON\n"; };
   void off( Machine* m );
};

class OFF : public State {
public:
   OFF()  { cout << "   OFF-ctor ";  };
   ~OFF() { cout << "   dtor-OFF\n"; };
   void on( Machine* m ) {
      cout << "   going from OFF to ON";
      m->setCurrent( new ON() );
      delete this;
   }
};

void ON::off( Machine* m ) {
   cout << "   going from ON to OFF";
   m->setCurrent( new OFF() );
   delete this;
}

Machine::Machine() { current = new OFF();  cout << '\n'; }

void main( void ) {
   void (Machine::*ptrs[])() = { Machine::off, Machine::on };
   Machine fsm;
   int num;
   while (1) {
      cout << "Enter 0/1: ";
      cin >> num;
      (fsm.*ptrs[num])();
}  }

//    OFF-ctor
// Enter 0/1: 0
//    already OFF
// Enter 0/1: 1
//    going from OFF to ON   ON-ctor    dtor-OFF
// Enter 0/1: 1
//    already ON
// Enter 0/1: 0
//    going from ON to OFF   OFF-ctor    dtor-ON
// Enter 0/1: 1
//    going from OFF to ON   ON-ctor    dtor-OFF
// Enter 0/1: 0
//    going from ON to OFF   OFF-ctor    dtor-ON
// Enter 0/1: 0
//    already OFF
// Enter 0/1:




// Purpose.  State design pattern - an FSM with two states and two events
// (distributed transition logic - logic in the derived state classes)

// State\Event     Suck up money      Drive through
//
// RedLight          you're a            you're  
//                    victim,             dead,
//                 maybe change       change to RED
//                   to GREEN
//
// GreenLight        you're an         you're free
//                     idiot           but you're
//                                  still a victim,
//                                   change to RED

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

class FSM {
   class State* current;
public:
   FSM();
   void setCurrent( State* s ) { current = s; }
   void suckUpMoney( int );
   void carDrivesThrough();
};

class State {
   int total;
protected:
   int getTotal() { return total; }
public:
   State() { total = 0; }
   virtual void suckUpMoney( int in, FSM* fsm ) {
      total += in;
      cout << "total is " << total << '\n';
   }
   virtual void carDrivesThrough( FSM* fsm ) = 0;
};

class GreenLight : public State {
public:
   GreenLight() { cout << "GREEN light\n"; }
   void suckUpMoney( int in, FSM* fsm ) {
      cout << "      You're an idiot, ";
      State::suckUpMoney( in, fsm );
   }
   void carDrivesThrough( FSM* fsm );
};

class RedLight : public State {
public:
   RedLight() { cout << "RED light\n"; }
   void suckUpMoney( int in, FSM* fsm ) {
      cout << "      ";
      State::suckUpMoney( in, fsm );
      if (getTotal() >= 50) {
         fsm->setCurrent( new GreenLight );
         delete this;
   }  }
   void carDrivesThrough( FSM* fsm ) {
      cout << "Sirens!!  Heat-seeking missile!!  Confiscate net worth!!\n";
      fsm->setCurrent( new RedLight );
      delete this;
}  };

FSM::FSM() {
   current = new RedLight();
}
void FSM::suckUpMoney( int in ) {
   current->suckUpMoney( in, this );
}
void FSM::carDrivesThrough() {
   current->carDrivesThrough( this );
}
void GreenLight::carDrivesThrough( FSM* fsm ) {
   cout << "Good-bye sucker!!\n";
   fsm->setCurrent( new RedLight );
   delete this;
}

int getCoin() {
   static int choices[3] = { 5, 10, 25 };
   return choices[rand() % 3];
}

void main( void ) {
   srand( time(0) );
   FSM fsm;
   int ans;
   while (true) {
      cout << "   Shell out (1), Drive thru (2), Exit (0): ";
      cin >> ans;
      if      (ans == 1) fsm.suckUpMoney( getCoin() );
      else if (ans == 2) fsm.carDrivesThrough();
      else break;
}  }



// Purpose.  State demo (centralized transition logic - logic in the FSM)
//
// Discussion.  Who defines the state transitions?  The State pattern does not
// specify which participant defines the criteria for state transitions.  The
// logic can be implemented entirely in the Context (FSM).  It is generally
// more flexible and appropriate, however, to let the State subclasses them-
// selves specify their successor state and when to make the transition.  This
// requires adding an interface to the Context that lets State objects set the
// Context's current state explicitly.  A disadvantage of decentralization is
// that State subclasses will be coupled to other sibling subclasses. [GOF308]

#include <iostream.h>

class FSMstate { public:
   virtual void on()  { cout << "undefined combo" << endl; }
   virtual void off() { cout << "undefined combo" << endl; }
   virtual void ack() { cout << "undefined combo" << endl; } };

class FSM {
public:
   FSM();
   void on()   { states[current]->on();  current = next[current][0]; }
   void off()  { states[current]->off(); current = next[current][1]; }
   void ack()  { states[current]->ack(); current = next[current][2]; }
private:
   FSMstate*  states[3];
   int        current;
   int        next[3][3];
};

class A : public FSMstate { public:
   void on()  { cout << "A, on ==> A" << endl; }
   void off() { cout << "A, off ==> B" << endl; }
   void ack() { cout << "A, ack ==> C" << endl; }
};
class B : public FSMstate { public:
   void off() { cout << "B, off ==> A" << endl; }
   void ack() { cout << "B, ack ==> C" << endl; }
};
class C : public FSMstate { public:
   void ack() { cout << "C, ack ==> B" << endl; }
};

FSM::FSM() {
   states[0] = new A; states[1] = new B; states[2] = new C;
   current = 1;
   next[0][0] = 0; next[0][1] = 1; next[0][2] = 2;
   next[1][0] = 1; next[1][1] = 0; next[1][2] = 2;
   next[2][0] = 2; next[2][1] = 2; next[2][2] = 1; }

enum     Message { On, Off, Ack };
Message  messageArray[10] = { On,Off,Off,Ack,Ack,Ack,Ack,On,Off,Off };

void main( void ) {
   FSM  fsm;
   for (int i = 0; i < 10; i++) {
      if (messageArray[i] == On)        fsm.on();
      else if (messageArray[i] == Off)  fsm.off();
      else if (messageArray[i] == Ack)  fsm.ack(); }
}

// undefined combo           // B, ack ==> C
// B, off ==> A              // C, ack ==> B
// A, off ==> B              // undefined combo
// B, ack ==> C              // B, off ==> A
// C, ack ==> B              // A, off ==> B