#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

// ==== Observer Pattern Framework ============================================

#include "observer.h"

// ==== 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;
};

typedef DecDisplay<short> RegisterDisplay;
typedef DecDisplay<bool> PinDisplay;

// == Breakpoint ==

template<class Compare> class Breakpoint {
public:
	typedef Compare::first_argument_type ValueType;
	Breakpoint(Model<ValueType>& t, const ValueType& v, const string& s):
		cow(t, this, &Breakpoint::update), value(v), str(s) {
	}
private:
	void update() {
		if (comp(cow->get(), value))
			cout<<"Breakpoint "<<str<<value<<" is hit."<<endl;
	}
	Compare comp;
	CallOnWrite<ValueType, Breakpoint<Compare> > cow;
	ValueType value;
	string str;
};

// == 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;
	RegisterDisplay d1(s.pc, "Program Counter");
	{
		Breakpoint<less<short> > b1(s.pc, 12, string("program counter < "));
		s.run();
	}
	Breakpoint<equal_to<bool> > b2(s.pin1, true, string("Pin 1 = "));
	s.run();
#ifdef __TURBOC__
	cout<<"Press a key: "; cin.get();
#endif
}
