/*
 * Copyright (c) 2008
 * Evan Teran
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appears in all copies and that both the
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the same name not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission. We make no representations about the
 * suitability this software for any purpose. It is provided "as is"
 * without express or implied warranty.
 */

#ifndef PROPERTY_H_20060118_H_
#define PROPERTY_H_20060118_H_

template <class T, class Object>
struct PropertyBase {

	typedef void (Object::*setter_ptr)(T);
	typedef T (Object::*getter_ptr)() const;

	PropertyBase(Object *_owner) : owner(_owner) { }
	
protected:
	const Object *base() const	{ return owner; }
	Object *base()				{ return owner; }

private:
	Object *owner;
};


template <class T, class Object, typename PropertyBase<T, Object>::getter_ptr G>
struct PropertyRO : public virtual PropertyBase<T, Object> {

	PropertyRO(Object *_owner) : PropertyBase<T, Object>(_owner) {
	}
	
	operator T () const {
		return (PropertyBase<T, Object>::base()->*G)();
	}
};


template <class T, class Object, typename PropertyBase<T, Object>::setter_ptr S>
struct PropertyWO : public virtual PropertyBase<T, Object> {


	PropertyWO(Object *_owner) : PropertyBase<T, Object>(_owner) {
	}
	
	T operator=(const T &value) {
		(PropertyBase<T, Object>::base()->*S)(value);
		return value;
	}
};

template <class T, class Object, typename PropertyBase<T, Object>::getter_ptr G, typename PropertyBase<T, Object>::setter_ptr S>
struct PropertyRW : public PropertyRO<T, Object, G>, public PropertyWO<T, Object, S> {
	
	using PropertyWO<T, Object, S>::operator= ;
	
	PropertyRW(Object *_owner) :  	
			PropertyBase<T, Object>(_owner),
			PropertyRO<T, Object, G>(_owner),
			PropertyWO<T, Object, S>(_owner) {
	}
};

#endif
