#ifndef __AOS_DYNAMIC
#define __AOS_DYNAMIC

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

template <class T> class dyn_var;
template <class T> class dyn_inst;
template <class T> class dyn_add;
template <class T> class dyn_mult;
template <class T> class dyn_sub;
template <class T> class dyn_divide;
template <class U, class T> class dyn_cast;

template <class T>
class dyn_c {
    public:
	class listener {
	    public:
		virtual void changed(dyn_c<T> *) = 0;
	};
	dyn_c() {
		cerr << " *  " << this << endl;
	}
	virtual ~dyn_c() {
		cerr << " +- " << this << endl;
	}
	virtual T value() = 0;
	void inc() {
		usagecount++;
	}
	void dec() {
		usagecount--;
		if (usagecount == 0) delete this;
	}
        virtual void listen(listener *listner) = 0;
        virtual void unlisten(listener *listner) = 0;
    private:
	int usagecount;
	vector<listener *> listeners;
};

template <class T>
class dyn_inst : public dyn_c<T>, public dyn_c<T>::listener {
    public:
	dyn_inst(const T &rhs) {
		_changed = false;
		_current = true;
		_value = rhs;
		owner = 0;
	}
	dyn_inst() {
		_changed = false;
		_current = true;
		_value = 0;
		owner = 0;
	}
	T value() {
		_changed = false;
		_current = true;
		return _value;
	}
	~dyn_inst() {}
	void setValue(T nvalue) {
		_value = nvalue;
		_changed = false;
		changed(this);
	}
	void listen(typename dyn_c<T>::listener *l) { 
		cerr << " >> " << this << "  " << l << endl;
		dyn_c<T>::inc(); owner = l; }
	void unlisten(typename dyn_c<T>::listener *) {
		cerr << " << " << this << endl;
		dyn_c<T>::dec(); };
        void changed(dyn_c<T> *) {
		cerr << this << "  " << _current << "  " << _changed  << endl;
		_current = false;
		if (_changed == false && owner) {
			_changed = true;
                        owner->changed(this);
                }
        }
    protected:
	typename dyn_c<T>::listener *owner;
	T _value;
	bool _changed, _current;
};

template <class U, class T>
class dyn_cast : public dyn_inst<U>, public dyn_c<T>::listener {
    public:
	dyn_c<T> *_i;
	dyn_cast(dyn_c<T> *i) : _i(i) {
		cerr << this << "*  &" << i << endl;
		dyn_inst<U>::_current = false;
		i->listen(this);
	}
	~dyn_cast() {
		cerr << this << "+- &" << endl;
		_i->unlisten(this);
	}
	U value() {
		if (!dyn_inst<U>::_current) {
			dyn_inst<U>::_value = (U)(_i->value());
			dyn_inst<U>::_current = true;
		}
		dyn_inst<U>::_changed = false;
		return dyn_inst<U>::_value;
	}
        void changed(dyn_c<T> *) {
		dyn_inst<U>::changed(this);
        }
};

template <class T>
class dyn_add : public dyn_inst<T> {
    public:
	dyn_c<T> *_l, *_r;
	dyn_add(dyn_c<T> *l, dyn_c<T> *r) : _l(l), _r(r) {
		l->listen(this);
		r->listen(this);
		dyn_inst<T>::_current = false;
	}
	~dyn_add() {
		_l->unlisten(this);
		_r->unlisten(this);
	}
	T value() {
		if (!dyn_inst<T>::_current) {
			dyn_inst<T>::_value = (_l->value() + _r->value());
			dyn_inst<T>::_current = true;
		}
		dyn_inst<T>::_changed = false;
		return dyn_inst<T>::_value;
	}
	virtual std::string name() { return "dyn_add"; }
};

template <class T>
class dyn_sub : public dyn_inst<T> {
    public:
        dyn_c<T> *_l, *_r;
        dyn_sub(dyn_c<T> *l, dyn_c<T> *r) : _l(l), _r(r) {
                l->listen(this);
                r->listen(this);
                dyn_inst<T>::_current = false;
        }
        ~dyn_sub() {
                _l->unlisten(this);
                _r->unlisten(this);
        }
        T value() {
                if (!dyn_inst<T>::_current) {
                        dyn_inst<T>::_value = (_l->value() - _r->value());
			dyn_inst<T>::_current = true;
                }
		dyn_inst<T>::_changed = false;
                return dyn_inst<T>::_value;
        }
};

template <class T>
class dyn_divide : public dyn_inst<T> {
    public:
        dyn_c<T> *_l, *_r;
        dyn_divide(dyn_c<T> *l, dyn_c<T> *r) : _l(l), _r(r) {
                l->listen(this);
                r->listen(this);
                dyn_inst<T>::_current = true;
        }
        ~dyn_divide() {
                _l->unlisten(this);
                _r->unlisten(this);
        }
        T value() {
                if (!dyn_inst<T>::_current) {
			T rval = _r->value();
			if (rval != 0) {
	                        dyn_inst<T>::_value = (_l->value() / rval);
			} else {
				dyn_inst<T>::_value = 0;
			}
			dyn_inst<T>::_current = true;
                }
		dyn_inst<T>::_changed = false;
                return dyn_inst<T>::_value;
        }
};

template <class T>
class dyn_mult : public dyn_inst<T> {
    public:
        dyn_c<T> *_l, *_r;
        dyn_mult(dyn_c<T> *l, dyn_c<T> *r) : _l(l), _r(r) {
                l->listen(this);
                r->listen(this);
                dyn_inst<T>::_current = true;
        }
        ~dyn_mult() {
                _l->unlisten(this);
                _r->unlisten(this);
        }
        T value() {
                if (!dyn_inst<T>::_current) {
                        dyn_inst<T>::_value = _l->value() * _r->value();
			dyn_inst<T>::_current = true;
                }
		dyn_inst<T>::_changed = false;
                return dyn_inst<T>::_value;
        }
	virtual std::string name() { return "dyn_mult"; }
};

template <class T>
class dyn : public dyn_c<T>, public dyn_c<T>::listener {
    public:
	typedef typename dyn_c<T>::listener listener;
	dyn() {
		child = new dyn_inst<T>();
		child->listen(this);
	}
	dyn(dyn<T> &rhs) {
		child = &rhs;
		child->listen(this);
	}
	dyn(const dyn<T> &rhs) : dyn_c<T>(), dyn_c<T>::listener() {
		child = rhs.child;
		child->listen(this);
	}
	dyn(dyn_c<T> *rhs) {
		child = rhs;
		child->listen(this);
	}
	dyn(const T &rhs) { 
		child = new dyn_inst<T>(rhs); 
		child->listen(this); 
	}
	template <class U>
	dyn(dyn<U> &rhs) {
		cerr << "dyn<U>" << endl;
		child = new dyn_cast<T, U>(&rhs);
		child->listen(this);
	}
	template <class U>
	dyn(const dyn<U> &rhs) {
		cerr << "const dyn<U>" << endl;
		child = new dyn_cast<T, U>(rhs.child);
		child->listen(this);
	}
	template <class U>
	dyn(dyn_c<U> *rhs) {
		cerr << "dyn_c<U> *" << endl;
		child = new dyn_cast<T, U>(rhs);
		child->listen(this);
	}
	~dyn() {
		child->unlisten(this);
	}
	T value() {
		return child->value();
	}
	const dyn<T> &operator =(const dyn<T> &rhs) {
		child->unlisten(this);
		child = rhs.child;
		child->listen(this);
		changed(this);
		// based on a=b=c=5, this gives better results (all set to a variable with value 5 independantly)
		return rhs;
	}
	const T &operator =(const T &rhs) {
		if (dyn_inst<T> *cp = dynamic_cast<dyn_inst<T> *>(child)) {
			cp->setValue(rhs);
		} else {
			// move listeners along with the 
			child->unlisten(this);
			child = new dyn_inst<T>(rhs);
			child->listen(this);
			changed(this);
		}
		return rhs;
	}
	dyn<T> &operator +=(const dyn<T> &rhs) {
		dyn_c<T> *nc = new dyn_add<T>(child, rhs.child);
		nc->listen(this);
		child->unlisten(this);
		child = nc;
		return *this;
	}
	dyn<T> &operator -=(const dyn<T> &rhs) {
		dyn_c<T> *nc = new dyn_sub<T>(child, rhs.child);
		nc->listen(this);
		child->unlisten(this);
		child = nc;
		return *this;
	}
	dyn<T> &operator /=(const dyn<T> &rhs) {
		dyn_c<T> *nc = new dyn_divide<T>(child, rhs.child);
                nc->listen(this);
                child->unlisten(this);
		child = nc;
		return *this;
	}
	dyn<T> &operator *=(const dyn<T> &rhs) {
		dyn_c<T> *nc = new dyn_mult<T>(child, rhs.child);
                nc->listen(this);
                child->unlisten(this);
		child = nc;
		return *this;
	}
        virtual void listen(listener *listner) { 
		cerr << " ++ " << this << endl;
		listeners.push_back(listner); 
		listner->changed(this);
	}
        virtual void unlisten(listener *listner) {
		cerr << " -- " << this << endl;
                for (unsigned int i=listeners.size(); i>0;) {
                        i--;
                        if (listeners[i] == listner) {
                                if (i != listeners.size() - 1) {
                                        listeners[i] = listeners[listeners.size() - 1];
                                }
                                listeners.pop_back();
                        }
                }
        }
	virtual void changed(dyn_c<T> *) {
                typename vector<typename dyn<T>::listener *>::iterator lb(listeners.begin()), le(listeners.end());
                while (lb != le) {
                        (*lb)->changed(this);
                        ++lb;
                }
        }
	virtual std::string name() { return "dyn"; }
//    private:
    public:
	dyn_c<T> *child;
	vector<listener *>listeners;
};

template <class T>
dyn<T> operator +(dyn<T> &lhs,       dyn<T> &rhs)			{ return dyn<T>(new dyn_add<T>(&lhs, &rhs));				}
template <class T>
dyn<T> operator +(const dyn<T> &lhs, dyn<T> &rhs)                   	{ return dyn<T>(new dyn_add<T>(lhs.child, &rhs));			}
template <class T>
dyn<T> operator +(dyn<T> &lhs,       const dyn<T> &rhs)             	{ return dyn<T>(new dyn_add<T>(&lhs, rhs.child));			}
template <class T>
dyn<T> operator +(const dyn<T> &lhs, const dyn<T> &rhs)             	{ return dyn<T>(new dyn_add<T>(lhs.child, rhs.child));			}
template <class T>
dyn<T> operator +(dyn<T> &lhs,       const T &rhs)                      { return dyn<T>(new dyn_add<T>(&lhs, new dyn_inst<T>(rhs)));    	}
template <class T>
dyn<T> operator +(const dyn<T> &lhs, const T &rhs)                      { return dyn<T>(new dyn_add<T>(lhs.child, new dyn_inst<T>(rhs)));	}
template <class T>
dyn<T> operator +(const T &lhs,      dyn<T> &rhs)                       { return dyn<T>(new dyn_add<T>(new dyn_inst<T>(lhs), &rhs));		}
template <class T>
dyn<T> operator +(const T &lhs,      const dyn<T> &rhs)                 { return dyn<T>(new dyn_add<T>(new dyn_inst<T>(lhs), rhs.child));	}

template <class T>
dyn<T> operator -(dyn<T> &lhs,       dyn<T> &rhs)                       { return dyn<T>(new dyn_sub<T>(&lhs, &rhs));                    	}
template <class T>
dyn<T> operator -(const dyn<T> &lhs, dyn<T> &rhs)                       { return dyn<T>(new dyn_sub<T>(lhs.child, &rhs));               	}
template <class T>
dyn<T> operator -(dyn<T> &lhs,       const dyn<T> &rhs)                 { return dyn<T>(new dyn_sub<T>(&lhs, rhs.child));               	}
template <class T>
dyn<T> operator -(const dyn<T> &lhs, const dyn<T> &rhs)                 { return dyn<T>(new dyn_sub<T>(lhs.child, rhs.child));          	}
template <class T>
dyn<T> operator -(dyn<T> &lhs,       const T &rhs)                      { return dyn<T>(new dyn_sub<T>(&lhs, new dyn_inst<T>(rhs)));    	}
template <class T>
dyn<T> operator -(const dyn<T> &lhs, const T &rhs)                      { return dyn<T>(new dyn_sub<T>(lhs.child, new dyn_inst<T>(rhs)));	}
template <class T>
dyn<T> operator -(const T &lhs,      dyn<T> &rhs)                       { return dyn<T>(new dyn_sub<T>(new dyn_inst<T>(lhs), &rhs));		}
template <class T>
dyn<T> operator -(const T &lhs,      const dyn<T> &rhs)                 { return dyn<T>(new dyn_sub<T>(new dyn_inst<T>(lhs), rhs.child));	}

template <class T>
dyn<T> operator /(dyn<T> &lhs,       dyn<T> &rhs)                       { return dyn<T>(new dyn_divide<T>(&lhs, &rhs));                    	}
template <class T>
dyn<T> operator /(const dyn<T> &lhs, dyn<T> &rhs)                       { return dyn<T>(new dyn_divide<T>(lhs.child, &rhs));               	}
template <class T>
dyn<T> operator /(dyn<T> &lhs,       const dyn<T> &rhs)                 { return dyn<T>(new dyn_divide<T>(&lhs, rhs.child));               	}
template <class T>
dyn<T> operator /(const dyn<T> &lhs, const dyn<T> &rhs)                 { return dyn<T>(new dyn_divide<T>(lhs.child, rhs.child));          	}
template <class T>
dyn<T> operator /(dyn<T> &lhs,       const T &rhs)                      { return dyn<T>(new dyn_divide<T>(&lhs, new dyn_inst<T>(rhs)));    	}
template <class T>
dyn<T> operator /(const dyn<T> &lhs, const T &rhs)                      { return dyn<T>(new dyn_divide<T>(lhs.child, new dyn_inst<T>(rhs)));	}
template <class T>
dyn<T> operator /(const T &lhs,      dyn<T> &rhs)                       { return dyn<T>(new dyn_divide<T>(new dyn_inst<T>(lhs), &rhs));		}
template <class T>
dyn<T> operator /(const T &lhs,      const dyn<T> &rhs)                 { return dyn<T>(new dyn_divide<T>(new dyn_inst<T>(lhs), rhs.child));	}

template <class T>
dyn<T> operator *(dyn<T> &lhs,       dyn<T> &rhs)                       { return dyn<T>(new dyn_mult<T>(&lhs, &rhs));                    	}
template <class T>
dyn<T> operator *(const dyn<T> &lhs, dyn<T> &rhs)                       { return dyn<T>(new dyn_mult<T>(lhs.child, &rhs));               	}
template <class T>
dyn<T> operator *(dyn<T> &lhs,       const dyn<T> &rhs)                 { return dyn<T>(new dyn_mult<T>(&lhs, rhs.child));               	}
template <class T>
dyn<T> operator *(const dyn<T> &lhs, const dyn<T> &rhs)                 { return dyn<T>(new dyn_mult<T>(lhs.child, rhs.child));          	}
template <class T>
dyn<T> operator *(dyn<T> &lhs,       const T &rhs)                      { return dyn<T>(new dyn_mult<T>(&lhs, new dyn_inst<T>(rhs)));    	}
template <class T>
dyn<T> operator *(const dyn<T> &lhs, const T &rhs)                      { return dyn<T>(new dyn_mult<T>(lhs.child, new dyn_inst<T>(rhs)));	}
template <class T>
dyn<T> operator *(const T &lhs,      dyn<T> &rhs)                       { return dyn<T>(new dyn_mult<T>(new dyn_inst<T>(lhs), &rhs));    	}
template <class T>
dyn<T> operator *(const T &lhs,      const dyn<T> &rhs)                 { return dyn<T>(new dyn_mult<T>(new dyn_inst<T>(lhs), rhs.child));	}


#endif

