#include "AdeptHeaders.hpp"
#include "Mover.hpp"
#include "Tool.hpp"


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mover__CreateMessage::ConstructCreateMessage(Script *script)
{
	Check_Object(script);

	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *message_stream = script->messageStream;
	Check_Object(message_stream);
	message_stream->AllocateBytes(sizeof(Mover__CreateMessage));
	Entity__CreateMessage::ConstructCreateMessage(script);
	Mover__CreateMessage *message =
		Cast_Pointer(
			Mover__CreateMessage*,
			message_stream->GetPointer()
		);
	message->messageLength = sizeof(*message);

	//
	//---------------------------------------------------------------
	// Point at the notation file and make other files relative to it
	//---------------------------------------------------------------
	//
	Page *page = script->instancePage;
	Check_Object(page);

	//
	//-----------------------------------------
	// Read the world velocity and acceleration
	//-----------------------------------------
	//
	message->worldSpaceVelocity = Motion3D::Identity;
	page->GetEntry("WorldSpaceVelocity", &message->worldSpaceVelocity);
	message->worldSpaceAcceleration = Motion3D::Identity;
	page->GetEntry("WorldSpaceAcceleration", &message->worldSpaceAcceleration);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mover__GameModel::ConstructGameModel(Script *script)
{
	Check_Object(script);

	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *model_stream = script->modelStream;
	Check_Object(model_stream);
	model_stream->AllocateBytes(sizeof(Mover__GameModel));
	Entity__GameModel::ConstructGameModel(script);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mover__GameModel::ReadAndVerify(
		Mover__GameModel *model, 
		ModelAttributeEntry *attribute_entry, 
		const char *data,
		char **error,
		int error_buffer
	)
{
	Check_Object(attribute_entry);
	bool result = false;
	bool valid_data = (*data != '\0');

	//
	//----------------------------------------
	//Read in the values from the data entered
	//----------------------------------------
	//
	result = 
		Entity__GameModel::ReadAndVerify(
			model, 
			attribute_entry, 
			data,
			error,
			error_buffer
		);

	//
	//---------------------------
	//Verify all the model values
	//---------------------------
	//
	switch(attribute_entry->attributeID)
	{
	case MoverMassAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if(model->moverMass < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MoverMass=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	case MomentOfInertiaAttributeID:
		{
			if(!valid_data)
			{
				Vector3D value = Vector3D::Identity;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if (
				model->momentOfInertia.x < 0.0f
				 || model->momentOfInertia.y < 0.0f
				 || model->momentOfInertia.z < 0.0f
			)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MomentOfInertia=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	case LinearDragCoefficientsAttributeID:
		{
			if(!valid_data)
			{
				Vector3D value = Vector3D::Identity;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if (
				model->linearDragCoefficients.x < 0.0f
				 || model->linearDragCoefficients.y < 0.0f
				 || model->linearDragCoefficients.z < 0.0f
			)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LinearDragCoefficients=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	case AngularDragCoefficientsAttributeID:
		{
			if(!valid_data)
			{
				Vector3D value = Vector3D::Identity;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if (
				model->angularDragCoefficients.x < 0.0f
				 || model->angularDragCoefficients.y < 0.0f
				 || model->angularDragCoefficients.z < 0.0f
			)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]AngularDragCoefficients=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	case FrictionCoefficientAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if (model->frictionCoefficient < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]FrictionCoefficient=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	case ElasticityCoefficientAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if (model->elasticityCoefficient < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]ElasticityCoefficient=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	case MinimumBounceSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model,&value);
				result = true;
			}
			if (model->minimumBounceSpeed < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MinimumBounceSpeed=%s}: values must be >= 0!",
					data
				);
				result = false;
			}
			break;
		}
	}
	return result;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mover::SaveInstanceText(Page *instance_page)
{
	Check_Object(this);
	Check_Object(instance_page);

	Entity::SaveInstanceText(instance_page);

	//
	//-------------------------
	// Save the Execution State
	//-------------------------
	//
	int execution_state = executionState->GetState();
	MString execution_state_text;
	switch(execution_state)
	{
	case ExecutionStateEngine::StraightLineMotionState:
		{
			execution_state_text = "StraightLineMotionState";
			break;
		}
	case ExecutionStateEngine::LinearDragMotionState:
		{
			execution_state_text = "LinearDragMotionState";
			break;
		}
	}

	if (execution_state_text)
	{
		instance_page->SetEntry("ExecutionState", execution_state_text);
	}
	//
	//-----------------------------------------
	// Write the world velocity and acceleration
	//-----------------------------------------
	//
	instance_page->SetEntry("WorldSpaceVelocity",initialWorldSpaceVelocity);
	instance_page->SetEntry("WorldSpaceAcceleration",initialWorldSpaceAcceleration);
}
	