//===========================================================================//
// File:	Mission.cpp                                                         //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 02/19/95  JMA  Initial coding.                                            //
// 08/25/97  ECH  Infrastructure changes.                                    //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "Mission.hpp"
#include "Map.hpp"
#include "Tool.hpp"
#include "EntityManager.hpp"
#include "VideoRenderer.hpp"
#include "NameTable.hpp"
#include <MLR\MLR.hpp>
#include <MLR\MLRLight.hpp>

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

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

	//
	//-----------------------------------------------------------------------------
	// No matter what the instance file said, all missions are independent entities
	//-----------------------------------------------------------------------------
	//
	message->replicatorFlags &= ~Replicator::ReplicatorModeMask;
	message->replicatorFlags |= Replicator::IndependentMode;

	//
	//---------------------------------------------------------------
	// Point at the notation file and make other files relative to it
	//---------------------------------------------------------------
	//
	Check_Object(Tool::Instance);
	Page* page = script->instancePage;
	Check_Object(page);
	Tool::Instance->PushFilePath(page->GetNotationFile());
	
	//
	//-----------------------------------------------
	// Add all Entity Names to the Mission Name Table
	//-----------------------------------------------
	//
	Verify(NameTable::GetInstance() == NULL);
	GlobalPointers::AddGlobalPointer(new NameTable(), NameTableGlobalPointerIndex);
	Check_Object(NameTable::GetInstance());

	{
		MString table_name = page->GetName();
		table_name += "{NameTable}";
		Resource name_table_resource(table_name);
		if (name_table_resource.DoesResourceExist() && name_table_resource.IsResourceUpToDate())
		{
			Verify(name_table_resource.DoesResourceExist());
			name_table_resource.LoadData();
			Check_Object(NameTable::GetInstance());
			NameTable::GetInstance()->LoadTable(&name_table_resource);		
			message->m_nameTableStreamResourceID = name_table_resource.GetResourceID();
			if (!name_table_resource.IsRegistered())
				name_table_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
		}
		else
		{
			NotationFile table_file;
			if (page->GetEntry("NameTable", &table_file))
			{
				Tool::Instance->PushFilePath(&table_file);
				NameTable::GetInstance()->LoadTable(&table_file);
				Tool::Instance->PopFilePath();
			}
			//
			//------------------------------------------
			//   Write out the Mission Name Table Stream
			//------------------------------------------
			//
			DynamicMemoryStream name_table_stream;
			Check_Object(NameTable::GetInstance());
			NameTable::GetInstance()->SaveTable(&name_table_stream);

			if (name_table_stream.GetBytesUsed())
			{
				name_table_resource.Save(&name_table_stream, table_file.GetFileDependencies());
				if (name_table_resource.IsRegistered())
					name_table_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
				Check_Object(&name_table_resource);
				message->m_nameTableStreamResourceID = name_table_resource.GetResourceID();
			}
			else
				message->m_nameTableStreamResourceID = ResourceID::Null;
		}
	}

	//
	//-----------------------------------------------------------------
	// Create the map instance and stuff its resource ID in the message
	//-----------------------------------------------------------------
	//
	{
		NotationFile map_file;
		page->GetEntry("Map", &map_file, true);
		Resource map_instance;
		Check_Object(Tool::Instance);
		ReplicatorID starting_id = *script->baseID;
		Tool::Instance->ConstructCreateMessage(
			&map_instance,
			&map_file,
			script->baseID
		);
		message->m_mapResourceID = map_instance.GetResourceID();
		WORD span =
			static_cast<WORD>(script->baseID->localID - starting_id.localID);
		message->replicatorID += span;
	}

	//
	//---------------------------------------------------------------------
	// Open up the contents file, and see if its empty.  If so, we are done
	//---------------------------------------------------------------------
	//
	{
		NotationFile props_file;
		page->GetEntry("Props", &props_file);
		NotationFile::PageIterator *pages = props_file.MakePageIterator();
		Check_Object(pages);
		if (!pages->GetSize())
		{
			message->m_propStreamResourceID = ResourceID::Null;
		}

		//
		//-------------------------------------------------------------
		// Look for the prop stream resource to see if it is up to date
		//-------------------------------------------------------------
		//
		else
		{
			const char* props_filename = props_file.GetFileName();
			Resource prop_resource(props_filename);
			if (
				prop_resource.DoesResourceExist() &&
				prop_resource.IsResourceUpToDate()
			)
			{
				WORD span;
				prop_resource.LoadData();
				prop_resource >> span;
				Verify(span > 0);
				*script->baseID += span;
				message->replicatorID += span;
				message->m_propStreamResourceID = prop_resource.GetResourceID();
				if (!prop_resource.IsRegistered())
					prop_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}

			//
			//---------------------------------------
			// For each page, an entity will be built
			//---------------------------------------
			//
			else
			{
				FileDependencies props_deps(*props_file.GetFileDependencies());
				FileDependencies *parent = Resource::ParentFileDependencies;
				Resource::ParentFileDependencies = &props_deps;
				Check_Object(Tool::Instance);
				Tool::Instance->PushFilePath(&props_file);
				DynamicMemoryStream prop_stream(sizeof(WORD));
				prop_stream << static_cast<WORD>(0);
				Page *instance;
				ReplicatorID starting_id = *script->baseID;
				while ((instance = pages->ReadAndNext()) != NULL)
				{
					Check_Object(instance);

					//
					//--------------------------------
					// Create the entity for this page
					//--------------------------------
					//
					const char *instance_name = instance->GetName();
					Check_Pointer(instance_name);
					Entity::CreateMessage *message =
						Tool::Instance->ConstructCreateMessage(
							&prop_stream,
							instance,
							script->baseID
						);
					Check_Object(message);
					Check_Object(NameTable::GetInstance());
					message->nameID = NameTable::GetInstance()->FindID(instance_name);
					prop_stream.AdvancePointer(message->messageLength);
				}

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (prop_stream.GetBytesUsed() > sizeof(WORD))
				{
					prop_stream.Rewind();
					Verify(*script->baseID != starting_id);
					WORD span =
						static_cast<WORD>(script->baseID->localID - starting_id.localID);
					prop_stream << span;
					message->replicatorID += span;
					prop_resource.Save(&prop_stream, &props_deps);
					Check_Object(&prop_resource);
					message->m_propStreamResourceID = prop_resource.GetResourceID();
				}
				else
					message->m_propStreamResourceID = ResourceID::Null;
				if (!prop_resource.IsRegistered())
					parent->AddDependencies(&props_deps);
				Resource::ParentFileDependencies = parent;
				Tool::Instance->PopFilePath();
			}
		}
		delete pages;
	}

	//
	//-----------------------------------------------
	// For now, no armory until we get it figured out
	//-----------------------------------------------
	//
	{
		NotationFile armory_file;
		page->GetEntry("Armory", &armory_file);
		NotationFile::PageIterator *pages = armory_file.MakePageIterator();
		Check_Object(pages);
		if (!pages->GetSize())
		{
			message->m_armoryStreamResourceID = ResourceID::Null;
		}

		//
		//-------------------------------------------------------------
		// Look for the prop stream resource to see if it is up to date
		//-------------------------------------------------------------
		//
		else
		{
			const char* armory_filename = armory_file.GetFileName();
			Resource armory_resource(armory_filename);
			if (
				armory_resource.DoesResourceExist() &&
				armory_resource.IsResourceUpToDate()
			)
			{
				WORD span;
				armory_resource.LoadData();
				armory_resource >> span;
				Verify(span > 0);
				*script->baseID += span;
				message->replicatorID += span;
				message->m_armoryStreamResourceID = armory_resource.GetResourceID();
				if (!armory_resource.IsRegistered())
					armory_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}

			//
			//---------------------------------------
			// For each page, an entity will be built
			//---------------------------------------
			//
			else
			{
				FileDependencies armory_deps(*armory_file.GetFileDependencies());
				FileDependencies *parent = Resource::ParentFileDependencies;
				Resource::ParentFileDependencies = &armory_deps;
				Check_Object(Tool::Instance);
				Tool::Instance->PushFilePath(&armory_file);
				DynamicMemoryStream armory_stream(sizeof(WORD));
				armory_stream << static_cast<WORD>(0);
				Page *instance;
				ReplicatorID starting_id = *script->baseID;
				while ((instance = pages->ReadAndNext()) != NULL)
				{
					Check_Object(instance);

					//
					//--------------------------------
					// Create the entity for this page
					//--------------------------------
					//
					const char *instance_name = instance->GetName();
					Check_Pointer(instance_name);
					Entity::CreateMessage *message =
						Tool::Instance->ConstructCreateMessage(
							&armory_stream,
							instance,
							script->baseID
						);
					Check_Object(message);
					Check_Object(NameTable::GetInstance());
					message->nameID = NameTable::GetInstance()->FindID(instance_name);
					armory_stream.AdvancePointer(message->messageLength);
				}

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (armory_stream.GetBytesUsed() > sizeof(WORD))
				{
					armory_stream.Rewind();
					Verify(*script->baseID != starting_id);
					WORD span =
						static_cast<WORD>(script->baseID->localID - starting_id.localID);
					armory_stream << span;
					message->replicatorID += span;
					armory_resource.Save(&armory_stream, &armory_deps);
					Check_Object(&armory_resource);
					message->m_armoryStreamResourceID = armory_resource.GetResourceID();
				}
				else
					message->m_armoryStreamResourceID = ResourceID::Null;
				if (!armory_resource.IsRegistered())
					parent->AddDependencies(&armory_deps);
				Resource::ParentFileDependencies = parent;
				Tool::Instance->PopFilePath();
			}
		}
		delete pages;
	}
	Tool::Instance->PopFilePath();
	Verify(stack_level == Tool::Instance->GetStackLevel());

	//
	//------------------
	// Deal with the sky
	//------------------
	//
	message->m_skyResourceID = ResourceID::Null;
	const char* sky_name;
	if (page->GetEntry("Sky", &sky_name))
	{
		//
		//-------------------------------------------------------------
		// If we are dealing with a 3ds file, call the 3ds resourcifier
		//-------------------------------------------------------------
		//
		FileStream file_stream(sky_name);
		const char* file_name = file_stream.GetFileName();

		//
		//---------------------------------------------------------------
		// See if the resource already exists, and if so, just use its ID
		//---------------------------------------------------------------
		//
		Resource sky_res(file_name);
		if (!sky_res.DoesResourceExist() || !sky_res.IsResourceUpToDate())
		{
			FileDependencies erf_dependencies;
			erf_dependencies.AddDependency(&file_stream);
			sky_res.Save(&file_stream, &erf_dependencies);
			if (!sky_res.IsRegistered())
				Resource::ParentFileDependencies->AddDependencies(&erf_dependencies);
		}
		else if (!sky_res.IsRegistered())
			sky_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
		message->m_skyResourceID = sky_res.GetResourceID();
	}

	//
	//------------------------
	// Deal with the Night sky
	//------------------------
	//
	message->m_nightSkyResourceID = ResourceID::Null;
	if (page->GetEntry("NightSky", &sky_name))
	{
		//
		//-------------------------------------------------------------
		// If we are dealing with a 3ds file, call the 3ds resourcifier
		//-------------------------------------------------------------
		//
		FileStream file_stream(sky_name);
		const char* file_name = file_stream.GetFileName();

		//
		//---------------------------------------------------------------
		// See if the resource already exists, and if so, just use its ID
		//---------------------------------------------------------------
		//
		Resource sky_res(file_name);
		if (!sky_res.DoesResourceExist() || !sky_res.IsResourceUpToDate())
		{
			FileDependencies erf_dependencies;
			erf_dependencies.AddDependency(&file_stream);
			sky_res.Save(&file_stream, &erf_dependencies);
			if (!sky_res.IsRegistered())
				Resource::ParentFileDependencies->AddDependencies(&erf_dependencies);
		}
		else if (!sky_res.IsRegistered())
			sky_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
		message->m_nightSkyResourceID = sky_res.GetResourceID();
	}


	//
	//---------------------------
	// Load in the warning bounds
	//---------------------------
	//
	message->m_warningBoundsResourceID = ResourceID::Null;
	const char* bounds_name;
	if (page->GetEntry("WarningBounds", &bounds_name))
	{
		//
		//-------------------------------------------------------------
		// If we are dealing with a 3ds file, call the 3ds resourcifier
		//-------------------------------------------------------------
		//
		FileStream file_stream(bounds_name);
		const char* file_name = file_stream.GetFileName();

		//
		//---------------------------------------------------------------
		// See if the resource already exists, and if so, just use its ID
		//---------------------------------------------------------------
		//
		Resource bounds_res(file_name);
		if (!bounds_res.DoesResourceExist() || !bounds_res.IsResourceUpToDate())
		{
			FileDependencies bounds_dependencies;
			bounds_dependencies.AddDependency(&file_stream);
			bounds_res.Save(&file_stream, &bounds_dependencies);
			if (!bounds_res.IsRegistered())
				Resource::ParentFileDependencies->AddDependencies(&bounds_dependencies);
		}
		else if (!bounds_res.IsRegistered())
			bounds_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
		message->m_warningBoundsResourceID = bounds_res.GetResourceID();
	}

	//
	//---------------------------
	// Load in the mission bounds
	//---------------------------
	//
	message->m_missionBoundsResourceID = ResourceID::Null;
	if (page->GetEntry("MissionBounds", &bounds_name))
	{
		//
		//-------------------------------------------------------------
		// If we are dealing with a 3ds file, call the 3ds resourcifier
		//-------------------------------------------------------------
		//
		FileStream file_stream(bounds_name);
		const char* file_name = file_stream.GetFileName();

		//
		//---------------------------------------------------------------
		// See if the resource already exists, and if so, just use its ID
		//---------------------------------------------------------------
		//
		Resource bounds_res(file_name);
		if (!bounds_res.DoesResourceExist() || !bounds_res.IsResourceUpToDate())
		{
			FileDependencies bounds_dependencies;
			bounds_dependencies.AddDependency(&file_stream);
			bounds_res.Save(&file_stream, &bounds_dependencies);
			if (!bounds_res.IsRegistered())
				Resource::ParentFileDependencies->AddDependencies(&bounds_dependencies);
		}
		else if (!bounds_res.IsRegistered())
			bounds_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
		message->m_missionBoundsResourceID = bounds_res.GetResourceID();
	}

	message->m_isNightMission = false;
	page->GetEntry("IsNight", &message->m_isNightMission);

	//
	//-----------------------
	//Clean up the Name Table
	//-----------------------
	//
	Check_Object(NameTable::GetInstance());
	delete NameTable::GetInstance();
	GlobalPointers::ClearPointer(NameTableGlobalPointerIndex);
}

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

	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *model_stream = script->modelStream;
	Check_Object(model_stream);
	model_stream->AllocateBytes(sizeof(Mission__GameModel));
	Entity__GameModel::ConstructGameModel(script);
	Mission__GameModel *model =
		Cast_Pointer(Mission__GameModel*, model_stream->GetPointer());
	Check_Object(model);
	NotationFile *model_file = script->modelFile;
	Check_Object(model_file);
	Tool::Instance->PushFilePath(model_file);

	//
	//---------------------
	// Read in the fog data
	//---------------------
	//
	Page *page = model_file->GetPage("GameData");
	Check_Object(page);
	model->m_fogColor.red = 0.0f;
	model->m_fogColor.green = 0.0f;
	model->m_fogColor.blue = 0.0f;
	model->m_fogColor.alpha = 1.0f;
	page->GetEntry("FogColor", &model->m_fogColor);

//	model->m_animatedTexturesResourceID = ResourceID::Null;
	
	//
	//-------------------------------------------------------
	// Create messages for the light stream only if it's there
	//-------------------------------------------------------
	//
	{
		NotationFile lights_file;
		if (!page->GetEntry("Lights", &lights_file))
			model->m_lightStreamResourceID = ResourceID::Null;

		//
		//-----------------------------------------------------
		// There is a light stream, so open up the contents file
		//-----------------------------------------------------
		//
		else
		{

			//
			//-------------------------------------------------------------
			// Look for the light stream resource to see if it is up to date
			//-------------------------------------------------------------
			//
			Resource light_resource(lights_file.GetFileName());
			if (
				light_resource.DoesResourceExist() &&
				light_resource.IsResourceUpToDate()
			)
			{
				model->m_lightStreamResourceID = light_resource.GetResourceID();
				if (!light_resource.IsRegistered())
					light_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}

			//
			//------------------------------------------------------------------
			// It is not up to date, so create stream to write the contents into
			//------------------------------------------------------------------
			//
			else
			{
				Tool::Instance->PushFilePath(&lights_file);
				DynamicMemoryStream light_stream;

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

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (light_stream.GetBytesUsed() > sizeof(WORD))
				{
					light_stream.Rewind();
					light_resource.Save(&light_stream, lights_file.GetFileDependencies());
					if (!light_resource.IsRegistered())
						light_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
					Check_Object(&light_resource);
					model->m_lightStreamResourceID = light_resource.GetResourceID();
				}
				else
				{
					model->m_lightStreamResourceID = ResourceID::Null;
					if (!light_resource.IsRegistered())
						Resource::ParentFileDependencies->AddDependencies(lights_file.GetFileDependencies());
				}

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

	//
	//-------------------------------------------------------
	// Create messages for the light stream only if it's there
	//-------------------------------------------------------
	//
	{
		NotationFile lights_file;
		if (!page->GetEntry("NightLights", &lights_file))
			model->m_nightLightStreamResourceID = ResourceID::Null;

		//
		//-----------------------------------------------------
		// There is a light stream, so open up the contents file
		//-----------------------------------------------------
		//
		else
		{

			//
			//-------------------------------------------------------------
			// Look for the light stream resource to see if it is up to date
			//-------------------------------------------------------------
			//
			Resource light_resource(lights_file.GetFileName());
			if (
				light_resource.DoesResourceExist() &&
				light_resource.IsResourceUpToDate()
			)
			{
				model->m_nightLightStreamResourceID = light_resource.GetResourceID();
				if (!light_resource.IsRegistered())
					light_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}

			//
			//------------------------------------------------------------------
			// It is not up to date, so create stream to write the contents into
			//------------------------------------------------------------------
			//
			else
			{
				Tool::Instance->PushFilePath(&lights_file);
				DynamicMemoryStream light_stream;

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

				//
				//-----------------------------------------
				// Only save out the stream if there is one
				//-----------------------------------------
				//
				if (light_stream.GetBytesUsed() > sizeof(WORD))
				{
					light_stream.Rewind();
					light_resource.Save(&light_stream, lights_file.GetFileDependencies());
					if (!light_resource.IsRegistered())
						light_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
					Check_Object(&light_resource);
					model->m_nightLightStreamResourceID = light_resource.GetResourceID();
				}
				else
				{
					model->m_nightLightStreamResourceID = ResourceID::Null;
					if (!light_resource.IsRegistered())
						Resource::ParentFileDependencies->AddDependencies(lights_file.GetFileDependencies());
				}

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

	Tool::Instance->PopFilePath();
	Verify(stack_index == Tool::Instance->GetStackLevel());
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Mission__GameModel::SaveGameModel(
		Mission__GameModel *model,
		Stuff::NotationFile *data_file
	)
{
	Check_Object(model);
	Check_Object(data_file);

	Entity__GameModel::SaveGameModel(model, data_file);
	Page *page = data_file->GetPage("GameData");

	//Save lights file name
	if(model->m_lightStreamResourceID != ResourceID::Null)
	{
		Resource light_resource(model->m_lightStreamResourceID);
		Verify(light_resource.DoesResourceExist());

		page->SetEntry("Lights", light_resource.GetName());
	}

	if(model->m_nightLightStreamResourceID != ResourceID::Null)
	{
		Resource light_resource(model->m_nightLightStreamResourceID);
		Verify(light_resource.DoesResourceExist());

		page->SetEntry("NightLights", light_resource.GetName());
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	Mission__GameModel::ReadAndVerify(
		Mission__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 GeneralFogStartAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogStart < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogStart=%f}: value must be >= 0!",
					model->m_generalFogStart
				);
				result = false;
			}
			break;
		}
		case GeneralFogEndAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogEnd <= model->m_generalFogStart)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogEnd=%f}: value must be > GeneralFogStart!",
					model->m_generalFogEnd
				);
				result = false;
			}
			break;
		}
		case GeneralFogDensityAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogDensity < 0.0f || model->m_generalFogDensity > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogDensity=%f}: value must be between 0 and 2!",
					model->m_generalFogDensity
				);
				result = false;
			}
			break;
		}
		case LightFogStartAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogStart < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogStart=%f}: value must be >= 0!",
					model->m_lightFogStart
				);
				result = false;
			}
			break;
		}
		case LightFogEndAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogEnd <= model->m_lightFogStart)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogEnd=%f}: value must be > LightFogStart!",
					model->m_lightFogEnd
				);
				result = false;
			}
			break;
		}
		case LightFogDensityAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogDensity < 0.0f || model->m_lightFogDensity > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogDensity=%f}: value must be between 0 and 2!",
					model->m_lightFogDensity
				);
				result = false;
			}
			break;
		}
		case CustomFogStartAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogStart < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogStart=%f}: value must be >= 0!",
					model->m_customFogStart
				);
				result = false;
			}
			break;
		}
		case CustomFogEndAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogEnd <= model->m_customFogStart)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogEnd=%f}: value must be > CustomFogStart!",
					model->m_customFogEnd
				);
				result = false;
			}
			break;
		}
		case CustomFogDensityAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogDensity < 0.0f || model->m_customFogDensity > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogDensity=%f}: value must be between 0 and 2!",
					model->m_customFogDensity
				);
				result = false;
			}
			break;
		}

		case GeneralFogStartUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogStartUnderwater < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogStartUnderwater=%f}: value must be >= 0!",
					model->m_generalFogStartUnderwater
				);
				result = false;
			}
			break;
		}
		case GeneralFogEndUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogEndUnderwater <= model->m_generalFogStartUnderwater)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogEndUnderwater=%f}: value must be > GeneralFogStartUnderwater!",
					model->m_generalFogEndUnderwater
				);
				result = false;
			}
			break;
		}
		case GeneralFogDensityUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogDensityUnderwater < 0.0f || model->m_generalFogDensityUnderwater > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogDensityUnderwater=%f}: value must be between 0 and 2!",
					model->m_generalFogDensityUnderwater
				);
				result = false;
			}
			break;
		}
		case LightFogStartUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogStartUnderwater < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogStartUnderwater=%f}: value must be >= 0!",
					model->m_lightFogStartUnderwater
				);
				result = false;
			}
			break;
		}
		case LightFogEndUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogEndUnderwater <= model->m_lightFogStartUnderwater)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogEndUnderwater=%f}: value must be > LightFogStartUnderwater!",
					model->m_lightFogEndUnderwater
				);
				result = false;
			}
			break;
		}
		case LightFogDensityUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogDensityUnderwater < 0.0f || model->m_lightFogDensityUnderwater > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogDensityUnderwater=%f}: value must be between 0 and 2!",
					model->m_lightFogDensityUnderwater
				);
				result = false;
			}
			break;
		}
		case CustomFogStartUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogStartUnderwater < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogStartUnderwater=%f}: value must be >= 0!",
					model->m_customFogStartUnderwater
				);
				result = false;
			}
			break;
		}
		case CustomFogEndUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogEndUnderwater <= model->m_customFogStartUnderwater)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogEndUnderwater=%f}: value must be > CustomFogStartUnderwater!",
					model->m_customFogEndUnderwater
				);
				result = false;
			}
			break;
		}
		case CustomFogDensityUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogDensityUnderwater < 0.0f || model->m_customFogDensityUnderwater > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogDensityUnderwater=%f}: value must be between 0 and 2!",
					model->m_customFogDensityUnderwater
				);
				result = false;
			}
			break;
		}
		
		case GeneralFogStartSmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogStartSmoke < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogStartSmoke=%f}: value must be >= 0!",
					model->m_generalFogStartSmoke
				);
				result = false;
			}
			break;
		}
		case GeneralFogEndSmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogEndSmoke <= model->m_generalFogStartSmoke)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogEndSmoke=%f}: value must be > GeneralFogStartSmoke!",
					model->m_generalFogEndSmoke
				);
				result = false;
			}
			break;
		}
		case GeneralFogDensitySmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_generalFogDensitySmoke < 0.0f || model->m_generalFogDensitySmoke > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogDensitySmoke=%f}: value must be between 0 and 2!",
					model->m_generalFogDensitySmoke
				);
				result = false;
			}
			break;
		}
		case LightFogStartSmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogStartSmoke < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]GeneralFogStartSmoke=%f}: value must be >= 0!",
					model->m_lightFogStartSmoke
				);
				result = false;
			}
			break;
		}
		case LightFogEndSmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogEndSmoke <= model->m_lightFogStartSmoke)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogEndSmoke=%f}: value must be > LightFogStartSmoke!",
					model->m_lightFogEndSmoke
				);
				result = false;
			}
			break;
		}
		case LightFogDensitySmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_lightFogDensitySmoke < 0.0f || model->m_lightFogDensitySmoke > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]LightFogDensitySmoke=%f}: value must be between 0 and 2!",
					model->m_lightFogDensitySmoke
				);
				result = false;
			}
			break;
		}
		case CustomFogStartSmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 100.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogStartSmoke < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogStartSmoke=%f}: value must be >= 0!",
					model->m_customFogStartSmoke
				);
				result = false;
			}
			break;
		}
		case CustomFogEndSmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogEndSmoke <= model->m_customFogStartSmoke)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogEndSmoke=%f}: value must be > CustomFogStartSmoke!",
					model->m_customFogEndSmoke
				);
				result = false;
			}
			break;
		}
		case CustomFogDensitySmokeAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_customFogDensitySmoke < 0.0f || model->m_customFogDensitySmoke > 2.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]CustomFogDensitySmoke=%f}: value must be between 0 and 2!",
					model->m_customFogDensitySmoke
				);
				result = false;
			}
			break;
		}
		
		case HeightFogStartAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_heightFogStart < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]HeightFogStart=%f}: value must be >= 0!",
					model->m_heightFogStart
				);
				result = false;
			}
			break;
		}
		case HeightFogEndAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_heightFogEnd <= model->m_heightFogStart)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]HeightFogEnd=%f}: value must be > HeightFogStart!",
					model->m_heightFogEnd
				);
				result = false;
			}
			break;
		}
		case HeightFogOpacityAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 0.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_heightFogOpacity < 0.0f || model->m_heightFogOpacity > 1.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]HeightFogOpacity=%f}: value must be between 0 and 1!",
					model->m_heightFogOpacity
				);
				result = false;
			}
			break;
		}
		case FogColorAttributeID:
		{
			if(!valid_data)
			{
				RGBAColor value;
				value.red = 0.0f;
				value.green = 0.0f;
				value.blue = 0.0f;
				value.alpha = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case FogColorUnderwaterAttributeID:
		{
			if(!valid_data)
			{
				RGBAColor value;
				value.red = 0.0f;
				value.green = 0.0f;
				value.blue = 0.0f;
				value.alpha = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case FogColorSmokeAttributeID:
		{
			if(!valid_data)
			{
				RGBAColor value;
				value.red = 0.0f;
				value.green = 0.0f;
				value.blue = 0.0f;
				value.alpha = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case AllowRespawnAttributeID:
		{
			if (!valid_data)
			{
				bool value = false;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case AllowSearchLightsAttributeID:
		{
			if (!valid_data)
			{
				bool value = true;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case AllowRunningLightsAttributeID:
		{
			if (!valid_data)
			{
				bool value = true;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case IsNightMissionAttributeID:
		{
			if (!valid_data)
			{
				bool value = false;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case WeatherEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
		case NearClipAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_nearClip < 0.1f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]NearClip=%f}: value must be greater than 0.1!",
					model->m_nearClip
				);
				result = false;
			}
			break;
		}
		case FarClipAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1000.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_farClip <= model->m_nearClip)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]FarClip=%f}: value must be greater than NearClip!",
					model->m_farClip
				);
				result = false;
			}
			break;
		}
		case CanSetTimeAttributeID:
		{
			if (!valid_data)
			{
				bool value = true;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case NightGroundColorAttributeID:
		{
			if(!valid_data)
			{
				RGBAColor value;
				value.red = 0.2f;
				value.green = 0.2f;
				value.blue = 0.2f;
				value.alpha = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case NightFogColorAttributeID:
		{
			if(!valid_data)
			{
				RGBAColor value;
				value.red = 0.0f;
				value.green = 0.0f;
				value.blue = 0.0f;
				value.alpha = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			break;
		}
		case HeatSinkEfficiencyAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 1.0f;
				attribute_entry->SetValue(model, &value);
				result = true;
			}
			if(model->m_heatSinkEfficiency < 0.0f)
			{
				_snprintf(
					*error,
					error_buffer,
					"{[GameData]HeatSinkEfficiency=%f}: value must be >= 0",
					model->m_heatSinkEfficiency
				);
				result = false;
			}
			break;
		}
		case NightWeatherEffectResourceAttributeID:
		{
			if(!valid_data)
			{
				ResourceID value = ResourceID::Null;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
		case WaterSpecularFactorAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 345.0f;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
		case WaterAtNightSpecularFactorAttributeID:
		{
			if(!valid_data)
			{
				Scalar value = 345.0f;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
		case WaterSpecularPowerAttributeID:
		{
			if(!valid_data)
			{
				int value = 32;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
		case WaterAtNightSpecularPowerAttributeID:
		{
			if(!valid_data)
			{
				int value = 32;
				attribute_entry->SetValue(model, (void *)&value);
				result = true;
			}
			break;
		}
	}
	return result;
}