//===========================================================================//
// File:	Vehicle_Tool.cpp																	  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 09/09/98  JSE  Inital base class based off of Shadowrun/Adept                                //
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "MW4Headers.hpp"

#include "Vehicle.hpp"
#include "Subsystem.hpp"
#include "Engine.hpp"
#include "Torso.hpp"
#include "MWDamageObject.hpp"
#include "MaterialEffectHolder.hpp"

#include <Adept\Tool.hpp>
#include <Adept\EntityManager.hpp>
#include <MLR\MLRLight.hpp>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Vehicle__GameModel::ConstructGameModel(Script *script)
{
	Check_Object(script);
	#if defined(_ARMOR)
		int stack_level = Tool::Instance->GetStackLevel();
	#endif

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

	Verify(stack_level == Tool::Instance->GetStackLevel());

	Vehicle__GameModel *model =
		Cast_Pointer(Vehicle__GameModel*, model_stream->GetPointer());

	//
	//------------------------------
	// Set up the model file pointer
	//------------------------------
	//
	NotationFile *model_file = script->modelFile;
	Check_Object(model_file);
	model->trailEffectsTable = ResourceID::Null;
	Page *game_page = model_file->GetPage("GameData");
	Check_Object(game_page);

	//
	//-------------------------
	// Create the effects table
	//-------------------------
	//
	NotationFile effects_file;
	if (game_page->GetEntry("TrailEffectsFile", &effects_file))
		model->trailEffectsTable = CreateEffectTableResource(&effects_file, MaterialCount);

	//
	//-------------------------------------------------------------
	// If there is no shadow entry, set the stream resource to NULL
	//-------------------------------------------------------------
	//
	NotationFile shadow_file;
	if (!game_page->GetEntry("Shadow", &shadow_file))
		model->shadowStream = ResourceID::Null;

	//
	//------------------------------------
	// Otherwise, rebuild the light stream
	//------------------------------------
	//
	else
	{
		Tool::Instance->PushFilePath(&shadow_file);
		DynamicMemoryStream shadow_stream;

		//
		//----------------------------------------------------
		// Read each light in and write it out into the binary
		//----------------------------------------------------
		//
		MidLevelRenderer::WriteMLRVersion(&shadow_stream);
		NotationFile::PageIterator *pages = shadow_file.MakePageIterator();
		Check_Object(pages);
		Page *shadow_page;
		while ((shadow_page = pages->ReadAndNext()) != NULL)
		{
			Check_Object(shadow_page);
			MidLevelRenderer::MLRLight* shadow =
				MidLevelRenderer::MLRLight::Make(shadow_page);
			Check_Object(shadow);
			shadow->Save(&shadow_stream);
			delete shadow;
		}

		//
		//-----------------------------------------
		// Only save out the stream if there is one
		//-----------------------------------------
		//
		if (shadow_stream.GetBytesUsed() > 0)
		{
			shadow_stream.Rewind();
			Resource shadow_resource(shadow_file.GetFileName());
			shadow_resource.Save(&shadow_stream, shadow_file.GetFileDependencies());
			shadow_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			Check_Object(&shadow_resource);
			model->shadowStream = shadow_resource.GetResourceID();
		}
		else
		{
			model->shadowStream = ResourceID::Null;
			Resource::ParentFileDependencies->AddDependencies(shadow_file.GetFileDependencies());
		}

		//
		//------------------------
		// Clean up the tool stack
		//------------------------
		//
		Check_Object(pages);
		delete pages;
		Tool::Instance->PopFilePath();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Vehicle__GameModel::ReadAndVerify(
		Vehicle__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 = 
		BaseClass::ReadAndVerify(
			model, 
			attribute_entry, 
			data,
			error,
			error_buffer
		);
	//
	//---------------------------
	//Verify all the model values
	//---------------------------
	//
	switch(attribute_entry->attributeID)
	{
	case FullStopTurnRateAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 10.1f*Radians_Per_Degree;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->fullStopTurnRate < 10.0f*Radians_Per_Degree)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]FullStopTurnRate=%f}: value must be >= 10.0!",
					model->fullStopTurnRate*Degrees_Per_Radian
				);
				result = false;
			}
			break;
		}
	case TopSpeedTurnRateAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 10.1f*Radians_Per_Degree;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->topSpeedTurnRate < 10.0f*Radians_Per_Degree)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]TopSpeedTurnRate=%f}: value must be >= 10.0!",
					model->topSpeedTurnRate
				);
				result = false;
			}
			break;
		}
	case MaxSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->maxSpeed < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MaxSpeed=%f}: value must be >= 0!",
					model->maxSpeed
				);
				result = false;
			}
			break;
		}
	case MinMaxSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = model->maxSpeed;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->minMaxSpeed < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MinMaxSpeed=%f}: value must be >= 0!",
					model->minMaxSpeed
				);
				result = false;
			}
			break;
		}
	case MinSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->minSpeed > model->maxSpeed)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MinSpeed=%f}: value must be <= MaxSpeed %f!",
					model->minSpeed,
					model->maxSpeed
				);
				result = false;
			}
			break;
		}
	case MaxReverseSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = -1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->maxReverseSpeed > 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MaxReverseSpeed=%f}: value must be <= 0!",
					model->maxReverseSpeed
				);
				result = false;
			}
			break;
		}
	case MinReverseSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->minReverseSpeed < model->maxReverseSpeed)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MinReverseSpeed=%f}: value must be >= MaxReverseSpeed!",
					model->minReverseSpeed
				);
				result = false;
			}
			break;
		}
	case AccelerationAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->acceleration < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]Acceleration=%f}: value must be >= 0!",
					model->acceleration
				);
				result = false;
			}
			break;
		}
	case DeccelerationAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->decceleration < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]Decceleration=%f}: value must be >= 0!",
					model->decceleration
				);
				result = false;
			}
			break;
		}
	case ReverseAccelerationMultiplierAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->reverseAccelerationMultiplier < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]ReverseAccelerationMultiplier=%f}: value must be >= 0!",
					model->reverseAccelerationMultiplier
				);
				result = false;
			}
			break;
		}
	case ReverseDeccelerationMultiplierAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->reverseDeccelerationMultiplier < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]ReverseDeccelerationMultiplier=%f}: value must be >= 0!",
					model->reverseDeccelerationMultiplier
				);
				result = false;
			}
			break;
		}
	case TargetLockTimeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 3.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->targetLockTime < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]TargetLockTime=%f}: value must be >= 0!",
					model->targetLockTime
				);
				result = false;
			}
			break;
		}

	case MinStandTransitionSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->minStandTransitionSpeed < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MinStandTransitionSpeed=%f}: value must be > 0!",
					model->minStandTransitionSpeed
				);
				result = false;
			}
			break;
		}


	case MaxGimpSpeedAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->maxGimpSpeed < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MaxGimpSpeed=%f}: value must be > 0!",
					model->maxGimpSpeed
				);
				result = false;
			}
			break;
		}



	case MaxSlopeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 55.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if (model->modelmaxSlope < 0)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]MaxSlope=%f}: value must be >= 0!",
					model->modelmaxSlope
				);
				result = false;
			}
			else
			{
				model->modelmaxSlope = model->modelmaxSlope * Radians_Per_Degree;
			}
			break;
		}

	

	case StartSlopeDecelerationAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 40.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if (model->modelstartSlopeDeceleration < 0)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]StartSlopeDeceleration=%f}: value must be >= 0!",
					model->modelstartSlopeDeceleration
				);
				result = false;
			}
			else
			{
				model->modelstartSlopeDeceleration = model->modelstartSlopeDeceleration * Radians_Per_Degree;
			}
			break;
		}

	case SlopeDecel1AttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 20.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->slopeDecel1 < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]SlopeDecel1=%f}: value must be > 0!",
					model->slopeDecel1
				);
				result = false;
			}
			break;
		}

	case SlopeDecel2AttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 40.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->slopeDecel2 < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]SlopeDecel2=%f}: value must be > 0!",
					model->slopeDecel2
				);
				result = false;
			}
			break;
		}

	case SlopeDecel3AttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 60.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->slopeDecel3 < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]SlopeDecel3=%f}: value must be > 0!",
					model->slopeDecel3
				);
				result = false;
			}
			break;
		}
	case AttackTypeAttributeID:
		{
			if(!valid_data)
			{
				int value = 0;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_attackType < 0)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]AttackType=%f}: value must be > 0!",
					model->m_attackType
				);
				result = false;
			}
			break;
		}
	case TreadLengthAttributeID:
		{
			if(!valid_data)
			{
				// Default tread length is set to 6 meters
				Scalar value = 6.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_treadLength <= 0)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]TreadLength=%f}: value must be > 0!",
					model->m_treadLength
				);
				result = false;
			}
			break;
		}
	}

	return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	
void
	Vehicle::SaveInstanceText(Page *instance_page)
{
	Check_Object(this);
	Check_Object(instance_page);

	BaseClass::SaveInstanceText(instance_page);

	//
	//-------------------------
	// Save the Execution State
	//-------------------------
	//
	int execution_state = executionState->GetState();
	MString execution_state_text;
	switch(execution_state)
	{
	case ExecutionStateEngine::FallingMotionState:
		{
			execution_state_text = "FallingMotionState";
			break;
		}
	case ExecutionStateEngine::FlyingMotionState:
		{
			execution_state_text = "FlyingMotionState";
			break;
		}
	case ExecutionStateEngine::DrivingMotionState:
		{
			execution_state_text = "DrivingMotionState";
			break;
		}
	}
	if (execution_state_text)
	{
		instance_page->SetEntry("ExecutionState", execution_state_text);
	}
}
