// Purpose.  Observer                   class Obs;
//
// Discussion.  On the left: Subject    class Subject {
// has hard-wired the number and type   public:
// of "dependent" objects, the compil-     Subject();
// er must have the declaration of the     void attach( Obs* );
// concrete Obs classes to compile         void setVal( int );
// Subject's decl, the Obs classes ex-     int  getVal();
// ercise no reuse of i/f or impl, and     void notify();
// Subject "pushes" updates to the Obs  private:
// objects.  On the right: Subject is      Obs*  obs_[10];
// decoupled from the number, type,        int   num_, val_;
// and declaration of concrete Obs      };
// subclasses; the Obs objects accept
// polymorphism; and Subject broad-     class Obs { public:
// casts that a change has occurred        virtual void update() = 0;
// followed by Obs objects requesting   protected:
// just the info that they want.           Subject*  sub_;
                                           int       div_;
class DivObs { public:                  };
   DivObs( int );                       class DivObs : public Obs { public:
   void update( int );                     DivObs( Subject*, int );
private:                                   void update();
   int  div_;                           };
};                                      class ModObs : public Obs { public:
class ModObs { public:                     ModObs( Subject*, int );
   ModObs( int );                          void update();
   void update( int );                  };
private:
   int  div_;                           Subject::Subject()     { num_ = 0; }
};                                      int  Subject::getVal() { return val_; }
                                        void Subject::attach( Obs* o ) {
class Subject {                            obs_[num_++] = o; }
public:                                 void Subject::setVal( int v ) {
   Subject();                              val_ = v;   notify(); }
   void setVal( int );                  void Subject::notify() {
private:                                   for (int i=0; i < num_; i++)
   int     val_;                              obs_[i]->update(); }
   DivObs  div_;
   ModObs  mod_;                        DivObs::DivObs( Subject* s, int d ) {
};                                         sub_ = s;  div_ = d;
                                           sub_->attach( this ); }
Subject::Subject() : div_(4), mod_(3)   void DivObs::update() {
   { }                                     int v = sub_->getVal();
void Subject::setVal( int v ) {            cout << v << " div " << div_
   val_ = v;                                  << " is " << v / div_ << endl; }
   div_.update( val_ );                 ModObs::ModObs( Subject* s, int d ) {
   mod_.update( val_ ); }                  sub_ = s;  div_ = d;
                                           sub_->attach( this ); }
DivObs::DivObs( int d ) { div_ = d; }   void ModObs::update() {
void DivObs::update( int v ) {             int v = sub_->getVal();
   cout << v << " div " << div_            cout << v << " mod " << div_
      << " is " << v / div_ << endl; }        << " is " << v % div_ << endl; }
ModObs::ModObs( int d ) { div_ = d; }
void ModObs::update( int v ) {          void main( void )
   cout << v << " mod " << div_         {
      << " is " << v % div_ << endl; }     Subject  subj;
                                           DivObs   divObs1( &subj, 4 );
void main( void )                          DivObs   divObs2( &subj, 3 );
{                                          ModObs   modObs3( &subj, 3 );
   Subject  subj;                          subj.setVal( 14 );
   subj.setVal( 14 );                   }
}
                                        // 14 div 4 is 3
// 14 div 4 is 3                        // 14 div 3 is 4
// 14 mod 3 is 2                        // 14 mod 3 is 2




// Purpose.  Observer design pattern

// 1. Model the "independent" functionality with a "subject" abstraction
// 2. Model the "dependent" functionality with "observer" hierarchy
// 3. The Subject is coupled only to the Observer base class
// 4. Observers register themselves with the Subject
// 5. The Subject broadcasts events to all registered Observers
// 6. Observers "pull" the information they need from the Subject
// 7. Client configures the number and type of Observers

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

class Subject {                      // 1. "independent" functionality
   vector<class Observer*> views;    // 3. Coupled only to "interface"
   int value;
public:
   void attach( Observer* obs ) { views.push_back( obs ); }
   void setVal( int val )       { value = val;  notify(); }
   int  getVal()                { return value; }
   void notify();
};

class Observer {                     // 2. "dependent" functionality
   Subject* model;
   int      denom;
public:
   Observer( Subject* mod, int div ) {
      model = mod;  denom = div;
      // 4. Observers register themselves with the Subject
      model->attach( this );
   }
   virtual void update() = 0;
protected:
   Subject* getSubject() { return model; }
   int      getDivisor() { return denom; }
};

void Subject::notify() {             // 5. Publisher broadcasts
   for (int i=0; i < views.size(); i++) views[i]->update();
}

class DivObserver : public Observer { public:
   DivObserver( Subject* mod, int div ) : Observer(mod,div) { }
   void update() {                   // 6. "Pull" information of interest
      int v = getSubject()->getVal(), d = getDivisor();
      cout << v << " div " << d << " is " << v / d << '\n';
}  };

class ModObserver : public Observer { public:
   ModObserver( Subject* mod, int div ) : Observer(mod,div) { }
   void update() {
      int v = getSubject()->getVal(), d = getDivisor();
      cout << v << " mod " << d << " is " << v % d << '\n';
}  };

void main( void ) {
   Subject      subj;
   DivObserver  divObs1( &subj,4 );  // 7. Client configures the number and
   DivObserver  divObs2( &subj,3 );  //    type of Observers
   ModObserver  modObs3( &subj,3 );
   subj.setVal( 14 );
}

// 14 div 4 is 3
// 14 div 3 is 4
// 14 mod 3 is 2




// Purpose.  Observer design pattern, class inheritance vs type inheritance

// SensorSystem is the "subject".  Lighting, Gates, and Surveillance are the
// "views".  The subject is only coupled to the "abstraction" of AlarmListener.

// An object's class defines how the object is implemented.  In contrast, an
// object's type only refers to its interface.  Class inheritance defines an
// object's implementation in terms of another object's implementation.  Type
// inheritance describes when an object can be used in place of another.
// [GoF, pp13-17]

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

class AlarmListener { public: virtual void alarm() = 0; };

class SensorSystem {
   vector<AlarmListener*> listeners;
public:
   void attach( AlarmListener* al ) { listeners.push_back( al ); }
   void soundTheAlarm() {
      for (int i=0; i < listeners.size(); i++)
         listeners[i]->alarm();
}  };

class Lighting : public AlarmListener {
   public: /*virtual*/ void alarm() { cout << "lights up" << '\n'; }
};

class Gates : public AlarmListener {
   public: /*virtual*/ void alarm() { cout << "gates close" << '\n'; }
};

class CheckList {
   virtual void localize() { cout << "   establish a perimeter" << '\n'; }
   virtual void isolate()  { cout << "   isolate the grid"      << '\n'; }
   virtual void identify() { cout << "   identify the source"   << '\n'; }
public:
   void byTheNumbers() {  // Template Method design pattern
      localize();
      isolate();
      identify();
}  };
                     // class inheri.  // type inheritance
class Surveillance : public CheckList, public AlarmListener {
   /*virtual*/ void isolate() { cout << "   train the cameras" << '\n'; }
public:
   /*virtual*/ void alarm() {
      cout << "Surveillance - by the numbers:" << '\n';
      byTheNumbers();
}  };

void main( void ) {
   SensorSystem ss;
   ss.attach( &Gates()        );
   ss.attach( &Lighting()     );
   ss.attach( &Surveillance() );
   ss.soundTheAlarm();
}

// gates close
// lights up
// Surveillance - by the numbers:
//    establish a perimeter
//    train the cameras
//    identify the source




// Purpose.  Observer and Mediator demo
//
// Observer - 1. Sender is coupled to a Receiver interface
//            2. Receivers register with Sender
//            3. Sender broadcasts (in the blind) to all Receivers
//
// Mediator - 4. Sender(s) has handle to Mediator
//            5. Mediator has handle to Receiver(s)
//            6. Sender(s) sends to Mediator
//            7. Mediator sends to Receiver(s)

#include <iostream>
#include <vector>
using namespace std;
void gotoxy( int, int );

class Observer { public: virtual void update( int ) = 0; };

class Mediator {
   vector<Observer*> groups[3];         // 1. Sender is coupled to an interface
public:
   enum Message { ODD, EVEN, THREE };   // 1. Sender is coupled to an interface
   void attach( Observer* o, Message type ) { groups[type].push_back( o ); }
   void disseminate( int num ) {
         if (num % 2 == 1)  // odd      // 3,7. Sender/Mediator broadcasts
            for (int i=0; i < groups[0].size(); i++) groups[0][i]->update(num);
         else               // even
            for (int i=0; i < groups[1].size(); i++) groups[1][i]->update(num);
         if (num % 3 == 0)  // /3
            for (int i=0; i < groups[2].size(); i++) groups[2][i]->update(num);
}  };

class OddObserver : public Observer {
   int col, row;
public:
   OddObserver( Mediator& med, int c ) {
      col = c;           row = 3;
      gotoxy( col, 1 );  cout << "Odd";
      gotoxy( col, 2 );  cout << "---";
      med.attach( this, Mediator::ODD );  // 2,5. Receivers register with Sender
   }
   void update( int num ) { gotoxy( col, row++ );  cout << num; }
};

class EvenObserver : public Observer {
   int col, row;
public:
   EvenObserver( Mediator& med, int c ) {
      col = c;           row = 3;
      gotoxy( col, 1 );  cout << "/2";
      gotoxy( col, 2 );  cout << "--";
      med.attach( this, Mediator::EVEN );
   }
   void update( int num ) { gotoxy( col, row++ );  cout << num; }
};

class ThreeObserver : public Observer {
   int col, row;
public:
   ThreeObserver( Mediator& med, int c ) {
      col = c;           row = 3;
      gotoxy( col, 1 );  cout << "/3";
      gotoxy( col, 2 );  cout << "--";
      med.attach( this, Mediator::THREE );
   }
   void update( int num ) { gotoxy( col, row++ );  cout << num; }
};

class Publisher { public:            // 6. Sender sends to Mediator
   Publisher( Mediator& med ) { for (int i=1; i < 10; i++) med.disseminate(i); }
};

void main( void ) {
   Mediator   mediator;
   OddObserver(   mediator,  1 );
   EvenObserver(  mediator, 11 );
   ThreeObserver( mediator, 21 );
   Publisher  producer( mediator );  // 4. Sender has handle to Mediator
}

// Odd       /2        /3
// ---       --        --
// 1         2         3
// 3         4         6
// 5         6         9
// 7         8
// 9




// Purpose.  TypedMessage - embellished Observer, decoupled messaging
//
// Messages inherit from TypedMessage<self>
// Message listeners inherit from many Message::Handlers
// Application tells message to publish/broadcast/notify
// Messages are the subject (receive registrations from subscribers)
// Subsystems are the observers (receive broadcast messages)
// TypedMessage accomodates everything: registration, containment, and
//   notification of observers

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

template <class T>
class TypedMessage {
   static vector<Handler*> registry;
public:
   class Handler {
   public:
      Handler() { TypedMessage<T>::registerHandler( this ); }
      virtual void handleEvent( const T* t ) = 0;
   };
   void notify() {
      for (int i=0; i < registry.size(); i++)
         registry.at(i)->handleEvent( (T*)this );
   }
   static void registerHandler( Handler* h ) { registry.push_back( h ); }
};

class On : public TypedMessage<On>  {
   string comment;
public:
   On( string str )   { comment = str; }
   void start() const { cout << "OnEvent.start - " << comment << '\n'; }
};
vector<TypedMessage<On>::Handler*> TypedMessage<On>::registry;

class Off : public TypedMessage<Off>  {
   string comment;
public:
   Off( string str ) { comment = str; }
   void stop() const { cout << "OffEvent.stop - " << comment << '\n'; }
};
vector<TypedMessage<Off>::Handler*> TypedMessage<Off>::registry;

class MasterConsole : public On::Handler, public Off::Handler { public:
   void handleEvent( const On* msg ) {
      cout << "MasterConsole - ";  msg->start(); }
   void handleEvent( const Off* msg ) {
      cout << "MasterConsole - ";  msg->stop(); }
};

class PowerMonitor : public On::Handler { public:
   void handleEvent( const On* msg ) {
      cout << "PowerMonitor - ";  msg->start(); }
};

void main( void ) {
   MasterConsole  mc;
   PowerMonitor   pm;
   On oneEvent( "lights" );  Off thrEvent( "elevators" );
   On twoEvent( "hvac" );    Off fouEvent( "frontDoor" );
   oneEvent.notify();  twoEvent.notify();
   thrEvent.notify();  fouEvent.notify();
}

// MasterConsole - OnEvent.start - lights
// PowerMonitor - OnEvent.start - lights
// MasterConsole - OnEvent.start - hvac
// PowerMonitor - OnEvent.start - hvac
// MasterConsole - OffEvent.stop - elevators
// MasterConsole - OffEvent.stop - frontDoor