#include <iostream>
#include <iomanip>
#include <string>
#include <function>

using namespace std;

// ==== COM Observer Pattern Framework ========================================

#include "observer.h"
#include "clntxdef.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;

// == Components ==

template <class Func>
class UnaryComponent {
typedef Func::argument_type T;
public:
	UnaryComponent(Model<T>& i1, Model<T>& o):
			in1(i1, this, &UnaryComponent::update),
			out(o) {
		update();
	}
private:
	void update() {
		currentValue=func(in1->get());
		if (out.get()!=currentValue)
			out.set(currentValue);
	}
	Func func;
	T currentValue;
	CallOnWrite<T, UnaryComponent<Func> > in1;
	Model<T>& out;
};

struct buffer : public unary_function<bool, bool> {
	bool operator() (bool b) const {
		return b;
   }
};

typedef UnaryComponent<buffer> Buffer;

// == GUID COM Components ==

DEFINE_GUID(CLSID_EXOR,0xAD6AFA60,0xD7A5,0x11D1,0xAB,0x71,0,0,0x1B,0x1C,0x56,0xEE);

// == Simulator ==

class Simulator {
public:
	Pin pin1, pin2, pin3;
	void run() {
		pin1.set(0); pin2.set(0);
		pin1.set(1); pin2.set(0);
		pin1.set(1); pin2.set(1);
		pin1.set(1); pin2.set(0);
		pin1.set(0); pin2.set(0);
	}
};

// == User Interface ==

void main() {
	Simulator s;
	PinDisplay d1(s.pin3, "Pin 3");

	COMComponent exor(CLSID_EXOR);
	COMModel<IBoolModel> in1(exor.getNextBitModel());
	COMModel<IBoolModel> in2(exor.getNextBitModel());
	COMModel<IBoolModel> out(exor.getNextBitModel());

	Buffer buf1(s.pin1, in1);
	Buffer buf2(s.pin2, in2);
	Buffer buf3(out, s.pin3);

	s.run();
#ifdef __TURBOC__
	cout<<"Press a key: "; cin.get();
#endif
}
