/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
****************************************************************************/

#pragma once

#include "glmAbstractAttribute.h"
#include "glmRTTI.h"

namespace glm
{
	// template base class for inspectable attributes
	template < class TValue, class TOwner >
	class AbstractAttributeT : public AbstractAttribute
	{
		GLM_ABSTRACT_RTTI_T0_T1("890b55dc-bc4a-4e63-8adb-32d645edd196", glm::AbstractAttributeT, TValue, TOwner, void)

	public:

		virtual ~AbstractAttributeT();
		virtual TValue getValue(const TOwner& owner) const;
		virtual void setValue(TOwner& owner, TValue value) const;

	protected:

		AbstractAttributeT() {}
		AbstractAttributeT(const char* name, const RTTI* ownerRTTI);
		AbstractAttributeT(const AbstractAttributeT& attribute);
	};

	template <class TValue, class TOwner>
	RTTI * glm::AbstractAttributeT<TValue, TOwner>::_rtti(NULL);

	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	AbstractAttributeT<TValue, TOwner>::AbstractAttributeT(const char* name, const RTTI* ownerRTTI)
		: AbstractAttribute(name, ownerRTTI)
	{}

	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	AbstractAttributeT<TValue, TOwner>::AbstractAttributeT(const AbstractAttributeT<TValue, TOwner>& attribute) :
		AbstractAttribute(attribute)
	{}

	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	AbstractAttributeT<TValue, TOwner>::~AbstractAttributeT()
	{}

	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	TValue AbstractAttributeT<TValue, TOwner>::getValue(const TOwner&) const
	{
		GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
			getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
	}

	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	void AbstractAttributeT<TValue, TOwner>::setValue(TOwner&, TValue) const
	{
		GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
			getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
	}

	//-------------------------------------------------------------------------
	// AbstractAttribute Specialization for TValue& 
	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	class AbstractAttributeT<TValue&, TOwner> : public AbstractAttribute
	{
		GLM_ABSTRACT_RTTI_T0_T1("2dc64baa-96cc-4b6b-8daf-59f7095eb845", glm::AbstractAttributeT, TValue&, TOwner, void)

	public:

		virtual ~AbstractAttributeT() {}

		virtual TValue&	getReference(const TOwner&) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

		virtual void setReference(TOwner&, TValue&) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

	protected:

		AbstractAttributeT() {}
		AbstractAttributeT(const char* name, const RTTI* ownerRTTI)
			: AbstractAttribute(name, ownerRTTI)
		{}

		AbstractAttributeT(const AbstractAttributeT<TValue&, TOwner>& attribute) :
			AbstractAttribute(attribute)
		{}
	};

	template <class TValue, class TOwner>
	RTTI * glm::AbstractAttributeT<TValue&, TOwner>::_rtti(NULL);

	//-------------------------------------------------------------------------
	// AbstractAttribute Specialization for const TValue& 
	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	class AbstractAttributeT< const TValue&, TOwner > : public AbstractAttribute
	{
		GLM_ABSTRACT_RTTI_T0_T1("027d8908-42af-41d2-88ec-578b284e9eac", glm::AbstractAttributeT, const TValue&, TOwner, void)

	public:

		virtual ~AbstractAttributeT() {}

		virtual const TValue& getConstReference(const TOwner&) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

		virtual void setConstReference(TOwner&, const TValue&) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

	protected:

		AbstractAttributeT() {}
		AbstractAttributeT(const char* name, const RTTI* ownerRTTI)
			: AbstractAttribute(name, ownerRTTI)
		{}

		AbstractAttributeT(const AbstractAttributeT<const TValue&, TOwner>& attribute) :
			AbstractAttribute(attribute)
		{}
	};

	template <class TValue, class TOwner>
	RTTI * glm::AbstractAttributeT<const TValue&, TOwner>::_rtti(NULL);

	//-------------------------------------------------------------------------
	// AbstractAttribute Specialization for TValue*
	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	class AbstractAttributeT< TValue*, TOwner > : public AbstractAttribute
	{
		GLM_ABSTRACT_RTTI_T0_T1("45163da5-0153-45a9-a6c7-f3b7c50ab45c", glm::AbstractAttributeT, TValue*, TOwner, void)

	public:

		virtual ~AbstractAttributeT() {}

		virtual TValue* getPointer(const TOwner*) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

		virtual void setPointer(TOwner*, TValue*) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

	protected:

		AbstractAttributeT() {}
		AbstractAttributeT(const char* name, const RTTI* ownerRTTI)
			: AbstractAttribute(name, ownerRTTI) {}
		AbstractAttributeT(const AbstractAttributeT<TValue*, TOwner>& attribute) :
			AbstractAttribute(attribute) {}
	};

	template <class TValue, class TOwner>
	RTTI * glm::AbstractAttributeT< TValue*, TOwner >::_rtti(NULL);

	//-------------------------------------------------------------------------
	// AbstractAttribute Specialization for const TValue*
	//-------------------------------------------------------------------------
	template <class TValue, class TOwner>
	class AbstractAttributeT< const TValue*, TOwner > : public AbstractAttribute
	{
		GLM_ABSTRACT_RTTI_T0_T1("7c1895ea-f09f-4a82-b60d-4d23cc6f13ca", glm::AbstractAttributeT, const TValue*, TOwner, void)

	public:

		virtual ~AbstractAttributeT() {}

		virtual const TValue* getConstPointer(const TOwner&) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

		virtual void setConstPointer(TOwner&, const TValue*) const
		{
			GLM_EXIT("Not implemented in AbstractAttributeT derived class, for the attribute %s of type %s from an object of type %s",
				getName(), getRTTI().getTypeName(), getOwnerRTTI().getTypeName());
		}

	protected:

		AbstractAttributeT() {}
		AbstractAttributeT(const char* name, const RTTI* ownerRTTI)
			: AbstractAttribute(name, ownerRTTI)
		{}
		AbstractAttributeT(const AbstractAttributeT<const TValue*, TOwner>& attribute) :
			AbstractAttribute(attribute)
		{}
	};

	template <class TValue, class TOwner>
	RTTI * glm::AbstractAttributeT< const TValue*, TOwner >::_rtti(NULL);
}
