#ifndef OSGINTROSPECTION_VARIANT_CAST_
#define OSGINTROSPECTION_VARIANT_CAST_

#include <osgIntrospection/Value>
#include <osgIntrospection/ReaderWriter>

#include <sstream>

namespace osgIntrospection
{

	/// Tries to convert an instance of Value to an object of type T.
	/// If T is a plain type or a pointer type (either const or non-const),
	/// and it matches the type of the value contained in v, then the actual
	/// value of type T is returned. If T is a [const] reference type, and 
	/// its base (non reference) type matches the internal value's type, 
	/// then a [const] reference to the internal value is returned.
	/// If none of the above conditions are met, a conversion is attempted
	/// as described in Value::convert() and then variant_cast is called again 
	/// with the converted value as parameter.
	/// If the conversion can't be completed, an exception is thrown.
	/// Conversions that attempt to make a const pointer non-const will fail.
	template<typename T> T variant_cast(const Value &v)
	{
		// return value
		Value::Instance<T> *i = dynamic_cast<Value::Instance<T> *>(v.inbox_->inst_);
		if (i) return i->data_;

		// return reference to value
		i = dynamic_cast<Value::Instance<T> *>(v.inbox_->ref_inst_);
		if (i) return i->data_;

		// return const reference to value
		i = dynamic_cast<Value::Instance<T> *>(v.inbox_->const_ref_inst_);
		if (i) return i->data_;

		// try to convert v to type T and restart
		return variant_cast<T>(v.convertTo(typeof(T)));
	}

	/// Returns a typed pointer to the data contained in a Value 
	/// instance. If the value's type is not identical to type T,
	/// a null pointer is returned.
	template<typename T> T *extract_raw_data(Value &v)
	{
		Value::Instance<T> *i = dynamic_cast<Value::Instance<T> *>(v.inbox_->inst_);
		if (i) return &i->data_;
		return 0;
	}

	/// Returns a typed pointer to the data contained in a const Value 
	/// instance. If the value's type is not identical to type T, a
	/// null pointer is returned.
	template<typename T> const T *extract_raw_data(const Value &v)
	{
		Value::Instance<T> *i = dynamic_cast<Value::Instance<T> *>(v.inbox_->inst_);
		if (i) return &i->data_;
		return 0;
	}

}

#endif
