#include <iostream>
#include <iomanip>
#include <string>

// ==== Observer Pattern Framework ============================================

#include <list>
#include <algorithm>

using namespace std;

namespace FIXUP {
//	FIXUP Needed when using BC5.02 because mem_fun is not implemented.
//	FIXUP Needed when using VC5.0 because mem_fun implementatiom in
//	function.h has problems with member functions that return void.
	template<class T>
	class mem_fun_t: public unary_function<T*, void> {
		void(T::*pmf)();
	public:
		explicit mem_fun_t(void(T::*p)()): pmf(p) {
		}
		void operator()(T* p) const {
			(p->*pmf)();
		}
	};

	template<class T> mem_fun_t<T> mem_fun(void(T::*f)()) {
		return mem_fun_t<T>(f);
	}
}
// END FIXUP

// == Observer ==

class SubjectIsDestroyed {}; // Exception

class Subject;

class Observer {
public:
	virtual void update()=0;
	virtual void destruct();
protected:
	Observer(Subject& s);
	virtual ~Observer();
	const Subject* getPointerToSubject() const  {
		if (pointerToSubject==0)
      	throw SubjectIsDestroyed();
     	return pointerToSubject;
	}
private:
	Subject* pointerToSubject;
	Observer(const Observer&);
	void operator=(const Observer&);
};

// == Subject ==

class Subject {
public:
	void attach(Observer* o) {
		observers.push_front(o);
	}
	void detach(Observer* o) {
		observers.remove(o);
	}
protected:
	Subject() {
	}
	virtual ~Subject() {
		using FIXUP::mem_fun;
		for_each(observers.begin(), observers.end(), mem_fun(&Observer::destruct));
	}
	void notify() const {
		using FIXUP::mem_fun;
		for_each(observers.begin(), observers.end(), mem_fun(&Observer::update));
	}
private:
	list<Observer*> observers;
	Subject(const Subject&);
	void operator=(const Subject&);
};

inline Observer::Observer(Subject& s): pointerToSubject(&s) {
	pointerToSubject->attach(this);
}
inline Observer::~Observer() {
	if (pointerToSubject)
		pointerToSubject->detach(this);
}
inline void Observer::destruct() {
	pointerToSubject->detach(this);
	pointerToSubject=0;
}

// == Model<T> ==

template <class T>
class Model: public Subject {
public:
	Model(): value(0) {
	}
	Model(const T& init): value(init) {
	}
	virtual void set(const T& v) {
		value=v;
		notify();
	}
	virtual const T& get() const {
		return value;
	}
protected:
	T value;
};

// == CallOnwrite<T, C> ==

template <class T, class C>
class CallOnWrite: public Observer {
public:
	typedef void (C::*PF)();
	CallOnWrite(Model<T>& m, C* po, PF pfu):
		Observer(m),
		pointerToComponent(po),
		pointerToUpdateFunction(pfu) {
	}
	const Model<T>& operator*() const {
		return static_cast<const Model<T>&>(*getPointerToSubject());
	}
	const Model<T>* operator->() const {
		return static_cast<const Model<T>*>(getPointerToSubject());
	}
protected:
	virtual void update() {
		(pointerToComponent->*pointerToUpdateFunction)();
	}
private:
	PF pointerToUpdateFunction;
	C* pointerToComponent;
};

// ==== Application that uses the Classic Observer Pattern ====================

// == ConcreteSubjects ==

typedef Model<bool> Pin;
typedef Model<short> Register;

// == ConcreteObservers ==

template <class T>
class DecDisplay {
public:
	DecDisplay(Model<T>& m, const string& n):
   	cow(m, this, &DecDisplay::update), name(n) {
	}
private:
	void update() {
		cout<<name<<" = "<<dec<<cow->get()<<endl;
	}
	CallOnWrite<T, DecDisplay<T> > cow;
	string name;
};

template <class T>
class HexDisplay {
public:
	HexDisplay(Model<T>& m, const string& n):
		cow(m, this, &HexDisplay::update), name(n) {
	}
private:
	void update() {
		cout<<name<<" = $"<<setfill('0')<<setw(4)<<hex<<cow->get()<<endl;
	}
	CallOnWrite<T, HexDisplay<T> > cow;
	string name;
};

typedef DecDisplay<short> DecRegisterDisplay;
typedef HexDisplay<short> HexRegisterDisplay;
typedef DecDisplay<bool> PinDisplay;

// == Simulator ==

class Simulator {
public:
	Register pc; // program counter
	Pin pin1;
	void run() {
		for (short i(9); i<16; ++i) {
			if (i%5==0)
				pin1.set(!pin1.get());
			pc.set(i);
		}
	}
};

// == User Interface ==

void main() {
	Simulator s;
	DecRegisterDisplay d1(s.pc, "Program Counter");
	{
		HexRegisterDisplay d2(s.pc, "Program Counter");
		PinDisplay d3(s.pin1, "Pin 1");
		s.run();
	}
	s.run();
#ifdef __TURBOC__
	cout<<"Press a key: "; cin.get();
#endif
}
