//===========================================================================//
// File: Attribute.hpp                                                       //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 08/25/97  JMA  Infrastructure changes												  //
// 08/25/97  ECH	Infrastructure changes												  //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-97, Virtual World Entertainment, Inc.                  //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Entity.hpp"

namespace Adept {

	//##########################################################################
	//########################    AttributeEntry    ############################
	//##########################################################################

	class AttributeEntry:
		public Stuff::Plug
	{
		friend class AttributeTable;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		AttributeEntry(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			RegisteredClass::ClassID attribute_type,
			Entity::AttributePointer attribute_address
		);
		virtual 
			~AttributeEntry();

		void
			TestInstance() const
				{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		virtual void
			SetValue(
				Entity *entity, 
				void *new_value
			);

		virtual void
			GetValue(
				Entity *entity, 
				void *new_value
			);

		virtual bool
			GetChangedValue(
				Entity *entity, 
				void *new_value,
				void *current_value,
				Stuff::Scalar difference_threshold
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		Entity::AttributeID
			attributeID;
		Stuff::MString
			attributeName;
		RegisteredClass::ClassID
			attributeType;

	protected:
		Entity::AttributePointer
			attributeAddress;
	};

	//##########################################################################
	//######################    DirectAttributeEntryOf    ######################
	//##########################################################################

	template <class T, int ID> class DirectAttributeEntryOf:
		public AttributeEntry
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		DirectAttributeEntryOf(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			Entity::AttributePointer attribute_address
		);
		~DirectAttributeEntryOf();

		void
			TestInstance() const
				{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		void
			SetValue(
				Entity *entity, 
				void *new_value
			);

		bool
			GetChangedValue(
				Entity *entity, 
				void *new_value,
				void *current_value,
				Stuff::Scalar difference_threshold
			);
		void
			GetValue(
				Entity *entity, 
				void *new_value
			);
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID>
		DirectAttributeEntryOf<T, ID>::DirectAttributeEntryOf(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			Entity::AttributePointer attribute_address
		):
			AttributeEntry(
				attribute_ID,
				attribute_name,
				ID,
				attribute_address
			)			
	{
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID>
		DirectAttributeEntryOf<T, ID>::~DirectAttributeEntryOf()
	{
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID> void
		DirectAttributeEntryOf<T, ID>::SetValue(
			Entity *entity, 
			void *new_value
		)
	{
		Check_Object(entity);
		Check_Pointer(new_value);
		Verify(attributeAddress != NULL);

		void *pointer = &(entity->*attributeAddress);
		*Cast_Pointer(T*,pointer) = *Cast_Pointer(T*,new_value);
	}
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID> void
		DirectAttributeEntryOf<T, ID>::GetValue(
			Entity *entity, 
			void *new_value
		)
	{
		Check_Object(entity);
		Check_Pointer(new_value);
		Verify(attributeAddress != NULL);

		void *pointer = &(entity->*attributeAddress);
		*Cast_Pointer(T*,new_value) = *Cast_Pointer(T*,pointer);
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID> bool
		DirectAttributeEntryOf<T, ID>::GetChangedValue(
			Entity *entity, 
			void *new_value,
			void *current_value,
			Stuff::Scalar diff_threshold
		)
	{
		Check_Object(entity);
		Check_Pointer(new_value);
		Check_Pointer(current_value);
		Verify(attributeAddress != NULL);

		void *pointer = &(entity->*attributeAddress);

		if (
			!Close_Enough(
				*Cast_Pointer(T*, pointer),
				*Cast_Pointer(T*, current_value),
				diff_threshold
			)
		)
		{
			*Cast_Pointer(T*, new_value) = *Cast_Pointer(T*, pointer);
			return true;
		}
		return false;
	}

	//##########################################################################
	//#####################    IndirectAttributeEntryOf    #####################
	//##########################################################################

	template <class T, int ID> class IndirectAttributeEntryOf:
		public AttributeEntry
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		IndirectAttributeEntryOf(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			Entity::AttributePointer attribute_address
		);
		~IndirectAttributeEntryOf();

		void
			TestInstance() const
				{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		void
			SetValue(
				Entity *entity, 
				void *new_value
			);

		bool
			GetChangedValue(
				Entity *entity, 
				void *new_value,
				void *current_value,
				Stuff::Scalar difference_threshold
			);
		void
			GetValue(
				Entity *entity, 
				void *new_value
			);
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID>
		IndirectAttributeEntryOf<T, ID>::IndirectAttributeEntryOf(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			Entity::AttributePointer attribute_address
		):
			AttributeEntry(
				attribute_ID,
				attribute_name,
				ID,
				attribute_address
			)			
	{
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID>
		IndirectAttributeEntryOf<T, ID>::~IndirectAttributeEntryOf()
	{
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID> void
		IndirectAttributeEntryOf<T, ID>::SetValue(
			Entity *entity, 
			void *new_value
		)
	{
		Check_Object(entity);
		Check_Pointer(new_value);
		Verify(attributeAddress != NULL);

		void *pointer = &(entity->*attributeAddress);
		**Cast_Pointer(T**, pointer) = *Cast_Pointer(T*, new_value);
	}
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID> void
		IndirectAttributeEntryOf<T, ID>::GetValue(
			Entity *entity, 
			void *new_value
		)
	{
		Check_Object(entity);
		Check_Pointer(new_value);
		Verify(attributeAddress != NULL);

		void *pointer = &(entity->*attributeAddress);
		*Cast_Pointer(T*, new_value) = **Cast_Pointer(T**, pointer);
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	template <class T, int ID> bool
		IndirectAttributeEntryOf<T, ID>::GetChangedValue(
			Entity *entity, 
			void *new_value,
			void *current_value,
			Stuff::Scalar diff_threshold
		)
	{
		Check_Object(entity);
		Check_Pointer(new_value);
		Check_Pointer(current_value);
		Verify(attributeAddress != NULL);

		void *pointer = &(entity->*attributeAddress);

		if (
			!Close_Enough(
				**Cast_Pointer(T**, pointer),
				*Cast_Pointer(T*, current_value),
				diff_threshold
			)
		)
		{
			*Cast_Pointer(T*, new_value) = **Cast_Pointer(T**, pointer);
			return true;
		}
		return false;
	}

	//##########################################################################
	//###################    IndirectStateAttributeEntry    ####################
	//##########################################################################

	class IndirectStateAttributeEntry:
		public AttributeEntry
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		IndirectStateAttributeEntry(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			RegisteredClass::ClassID attribute_type,
			Entity::AttributePointer attribute_address
		);
		~IndirectStateAttributeEntry();

		void
			TestInstance() const
				{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		void
			GetValue(
				Entity *entity, 
				void *new_value
			);
	};

	//##########################################################################
	//####################    DirectStateAttributeEntry    #####################
	//##########################################################################

	class DirectStateAttributeEntry:
		public AttributeEntry
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		DirectStateAttributeEntry(
			Entity::AttributeID attribute_ID,
			const char *attribute_name,
			RegisteredClass::ClassID attribute_type,
			Entity::AttributePointer attribute_address
		);
		~DirectStateAttributeEntry();

		void
			TestInstance() const
				{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		void
			GetValue(
				Entity *entity, 
				void *new_value
			);
	};

	//##########################################################################
	//########################    AttributeTable    ############################
	//##########################################################################

	class AttributeTable
		#if defined(_ARMOR)
			: public Stuff::Signature
		#endif
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		AttributeTable();
		~AttributeTable();

		void
			TestInstance()
				{}
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	public:
		void
			CopyFrom(AttributeTable *attribute_table);

		void
			AddAttributeEntry(AttributeEntry *attribute_entry);

		AttributeEntry*
			GetAttributeEntry(Entity::AttributeID attribute_ID);
		AttributeEntry*
			GetAttributeEntry(const char *attribute_name);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	private:
		Stuff::TableOf<AttributeEntry*, Entity::AttributeID>
			attributesByID;
		Stuff::TableOf<AttributeEntry*, Stuff::MString>
			attributesByName;

		#if defined(_ARMOR)
			bool
				verifyTable;
			void
				VerifyTable();
		#endif
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	inline AttributeEntry*
		AttributeTable::GetAttributeEntry(Entity::AttributeID attribute_ID)
	{
		#if defined(_ARMOR)
			VerifyTable();
		#endif
		Stuff::TableIteratorOf<AttributeEntry*, Entity::AttributeID>
			iterator(&attributesByID);
		return iterator.GetNth(attribute_ID);
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	inline AttributeEntry*
		AttributeTable::GetAttributeEntry(const char *attribute_name)
	{
		#if defined(_ARMOR)
			VerifyTable();
		#endif
		return attributesByName.Find(attribute_name);
	}

}

