//===========================================================================//
// 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               //
//===========================================================================//

#include "AdeptHeaders.hpp"
#include "Attribute.hpp"

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AttributeEntry::AttributeEntry(
	Entity::AttributeID attribute_ID,
	const char *attribute_name,
	RegisteredClass::ClassID attribute_type,
	Entity::AttributePointer attribute_address
):
	Plug(DefaultData),
	attributeName(attribute_name)
{
	attributeName.ToLower();
	attributeID = attribute_ID;
	attributeType = attribute_type;
	attributeAddress = attribute_address;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AttributeEntry::~AttributeEntry()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AttributeEntry::SetValue(
		Entity *entity, 
		void *new_value
	)
{
	STOP(("Not supported for this attribute"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AttributeEntry::GetValue(
		Entity *entity, 
		void *new_value
	)
{
	STOP(("Not supported for this attribute"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	AttributeEntry::GetChangedValue(
		Entity *entity, 
		void *new_value,
		void *current_value,
		Scalar diff_threshold
	)
{
	STOP(("Not supported for this attribute"));
	return false;
}

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
IndirectStateAttributeEntry::~IndirectStateAttributeEntry()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	IndirectStateAttributeEntry::GetValue(
		Entity *entity, 
		void *new_value
	)
{
	StateEngine *state_engine =
		*Cast_Pointer(
			StateEngine**,
			&(entity->*attributeAddress)
		);
	Check_Object(state_engine);
	*Cast_Pointer(StateEngine**,new_value) = state_engine;
}

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DirectStateAttributeEntry::~DirectStateAttributeEntry()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DirectStateAttributeEntry::GetValue(
		Entity *entity, 
		void *new_value
	)
{
	StateEngine *state_engine =
		Cast_Pointer(
			StateEngine*,
			&(entity->*attributeAddress)
		);
	Check_Object(state_engine);
	*Cast_Pointer(StateEngine**,new_value) = state_engine;
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AttributeTable::AttributeTable():
	attributesByID(NULL, true),
	attributesByName(NULL, true)
{
	#if defined(_ARMOR)
		verifyTable = true;
	#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AttributeTable::~AttributeTable()
{
	attributesByID.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AttributeTable::CopyFrom(AttributeTable *attribute_table)
{
	Check_Object(attribute_table);

	TableIteratorOf<AttributeEntry*, Entity::AttributeID>
		iterator(&attribute_table->attributesByID);
	AttributeEntry
		*attribute_entry;

	while ((attribute_entry = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(attribute_entry);
		attributesByID.AddValue(attribute_entry, attribute_entry->attributeID);
		attributesByName.AddValue(attribute_entry, attribute_entry->attributeName);
	}

	#if defined(_ARMOR)
		VerifyTable();
	#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AttributeTable::AddAttributeEntry(AttributeEntry *attribute_entry)
{
	Check_Object(attribute_entry);
	
	//
	// If entry already exists then remove it
	//
	AttributeEntry 
		*found_attribute_entry;

	found_attribute_entry = attributesByID.Find(attribute_entry->attributeID);
	if (found_attribute_entry != NULL)
	{
		Check_Object(found_attribute_entry);
		attributesByID.RemovePlug(found_attribute_entry);
		attributesByName.RemovePlug(found_attribute_entry);
	}
	
	//
	// Add entry to the table
	//
	attributesByID.AddValue(attribute_entry, attribute_entry->attributeID);
	attributesByName.AddValue(attribute_entry, attribute_entry->attributeName);

	//
	// Verify that the attribute IDs correspond to array position
	//
	#if defined(_ARMOR)
		verifyTable = true;
	#endif
}

#if defined(_ARMOR)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	AttributeTable::VerifyTable()
{
	//
	// Verify that the attribute IDs correspond to array position
	//
	if (verifyTable)
	{
		verifyTable = false;

		TableIteratorOf<AttributeEntry*, Entity::AttributeID>
			iterator(&attributesByID);
		unsigned
			table_size;

		table_size = iterator.GetSize();
		for (int i = 0; i < table_size; i++)
		{
			AttributeEntry 
				*test_attribute_entry;

			test_attribute_entry = iterator.GetNth(i);
			Check_Object(test_attribute_entry);
			Verify(test_attribute_entry->attributeID == i);
		}
	}
}
#endif
