//-----------------------------------------------------------------------------
// File			: ToolsAVP_Node_Objective_Marine.cpp
// Author		: Gareth Thomas
// Created		: 23 / 01 / 2007
// Copyright (c) 2007 Rebellion. All rights reserved.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------

// Core
#include "Core/Asura.h"

// Header
#include "Entity/Locations/Objective/Marine/ToolsAVP_Node_Objective_Marine.h"

// Asura
#include "Camera/Asura_Camera.h"
#include "Mesh/Asura_Mesh_System.h"

// AVP
#include "Entity/AVP_Entity_EventIDs.h"
#include "Entity/GamePlayVolume/AVP_ServerEntity_GamePlayVolume.h"
#include "Entity/Locations/Objective/Marine/AVP_ServerEntity_Objective_Marine.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/AVP_ServerNode_GS2Node.h"
#include "Entity/AVP_Messages.h"

// Tools
#include "Entity/Locations/OrientedNode/GamesceneNode/Tools_EntityNode_GS2Node.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/ToolsAVP_Object_Type.h"

//------------------------------------------------------------------------------
// Constants, Defines, Statics and Globals
//------------------------------------------------------------------------------
Asura_Hashed_List<ToolsAVP_Node_Objective_Marine>			ToolsAVP_Node_Objective_Marine::s_xList;
ToolsAVP_Node_Objective_Marine*								ToolsAVP_Node_Objective_Marine::s_pxSelectedMarineObjective = NULL;
bool														ToolsAVP_Node_Objective_Marine::s_bActionLinkTypeChanged = false;
bool														ToolsAVP_Node_Objective_Marine::s_bRequiredGameSceneMethodChanged = false;
bool														ToolsAVP_Node_Objective_Marine::s_bOptionalGameSceneMethodChanged = false;

const char* ToolsAVP_Node_Objective_Marine::s_aszActionLinktypeNames[ToolsAVP_Node_Objective_Marine::MAX_TYPES] =
{
	"Goal's Game Play Volume",
	"Specific Game Play Volume",
	"Specific Game Scenes"
};

//-----------------------------------------------------------------------------
// Function Implementations
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Constructor
//-----------------------------------------------------------------------------
ToolsAVP_Node_Objective_Marine::ToolsAVP_Node_Objective_Marine(Asura_Entity* pxEntity)
: PARENT(pxEntity)
, m_iActionLinkingType(0)
, m_bObjectiveCompleteOnMessage(false)
, m_bRunToAction(false)
{
	Type = TOT_Entity_AI_Marine_Objective;

	SetMesh("ToolsShape_MarineObjective");

	m_xRequiredList.Clear();
	m_xOptionalList.Clear();

	AVP_ServerNode_Objective_Marine* pxAVPEntity = (AVP_ServerNode_Objective_Marine*)Entity;

	if (pxAVPEntity)
	{
		Position = pxAVPEntity->GetPosition();
		m_xPreviousPosition = Position;

		if (pxAVPEntity->GetObjectiveCompleteOnMessageOnly())
			m_bObjectiveCompleteOnMessage = true;
		else
			m_bObjectiveCompleteOnMessage = false;

		if (pxAVPEntity->GetRunToAction())
			m_bRunToAction = true;
		else
			m_bRunToAction = false;

		if (pxAVPEntity->GetShouldUseSpecificGPV() == 1)
		{
			m_iActionLinkingType = 1;
		}
		else if (pxAVPEntity->GetShouldUseSpecificGameScenes() == 1)
		{
			m_iActionLinkingType = 2;

			for ( u_int u = 0; u < pxAVPEntity->GetNumRequiredActions(); ++u )
			{
				Asura_Guid uGuid = pxAVPEntity->GetRequiredActionGuid( u );

				if (uGuid != ASURA_GUID_UNREGISTERED)
				{
					m_xRequiredList.Push_Back(uGuid);
				}
			}

			for ( u_int u = 0; u < pxAVPEntity->GetNumOptionalActions(); ++u )
			{
				Asura_Guid uGuid = pxAVPEntity->GetOptionalActionGuid( u );

				if (uGuid != ASURA_GUID_UNREGISTERED)
				{
					m_xOptionalList.Push_Back(uGuid);
				}
			}
		}
	}

	s_xList.AddToList(this);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Deconstructor
//-----------------------------------------------------------------------------
ToolsAVP_Node_Objective_Marine::~ToolsAVP_Node_Objective_Marine(void)
{
	m_xRequiredList.Clear();
	m_xOptionalList.Clear();

	s_xList.RemoveFromList(this);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective :: HandlesThisMessage
//-----------------------------------------------------------------------------
bool ToolsAVP_Node_Objective_Marine::HandlesThisMessage(int iMessageID )
{
	switch ( iMessageID )
	{
		case AVP_MSGID_AI_OBJECTIVE_COMPLETE:
		{
			return true;

		}break;

		default:
		{
			return PARENT::HandlesThisMessage(iMessageID);
		}break;
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective :: HandlesThisEvent
//-----------------------------------------------------------------------------
bool ToolsAVP_Node_Objective_Marine::HandlesThisEvent(int iEventID) const
{
	switch ( iEventID )
	{
		case AVP_ENTITY_EVENT_MARINE_AI_OBJECTIVE_COMPLETE:
		case AVP_ENTITY_EVENT_MARINE_AI_OBJECTIVE_ACTIONS_COMPLETE:
		{
			return true;
		}break;

		default:
		{
			return PARENT::HandlesThisEvent(iEventID);
		}break;
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: UpdateWhileSelected
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::UpdateWhileSelected(void)
{

	PARENT::UpdateWhileSelected();

	if (Changed)
	{
		Changed = false;
		AVP_ServerNode_Objective_Marine* pxAVPEntity = (AVP_ServerNode_Objective_Marine*)Entity;

		if (pxAVPEntity)
		{
			if (m_bObjectiveCompleteOnMessage)
				pxAVPEntity->SetObjectiveCompleteOnMessageOnly(1);
			else
				pxAVPEntity->SetObjectiveCompleteOnMessageOnly(0);

			if (m_bRunToAction)
				pxAVPEntity->SetRunToAction(1);
			else
				pxAVPEntity->SetRunToAction(0);
		}

		Tools_SaveAsura::SetEntityModified();
	}

	if (s_bActionLinkTypeChanged)
	{
		AVP_ServerNode_Objective_Marine* pxAVPEntity = (AVP_ServerNode_Objective_Marine*)Entity;

		if (pxAVPEntity)
		{
			s_bActionLinkTypeChanged = false;
			DeleteOverlay();
			CreateOverlay();

			if (m_iActionLinkingType == 0)
			{
				pxAVPEntity->SetShouldUseSpecificGPV(false);
				pxAVPEntity->SetShouldUseSpecificGameScenes(false);
			}
			else if (m_iActionLinkingType == 1)
			{
				pxAVPEntity->SetShouldUseSpecificGPV(true);
				pxAVPEntity->SetShouldUseSpecificGameScenes(false);
			}
			else if (m_iActionLinkingType == 2)
			{
				pxAVPEntity->SetShouldUseSpecificGPV(false);
				pxAVPEntity->SetShouldUseSpecificGameScenes(true);
			}
		}
		Tools_SaveAsura::SetEntityModified();
	}

	if ( s_bRequiredGameSceneMethodChanged )
	{
		AVP_ServerNode_Objective_Marine* pxAVPEntity = (AVP_ServerNode_Objective_Marine*)Entity;

		if (pxAVPEntity)
		{
			s_bRequiredGameSceneMethodChanged = false;

			u_int		uSize = m_xRequiredList.Size();
			Asura_Guid* pxGuids = new Asura_Guid[uSize];
			u_int		uNumDone = 0;

			Asura_ListElt< Asura_Guid >* pxTestElt = m_xRequiredList.Front();

			while ( pxTestElt != NULL )
			{
				Asura_Guid uGuid = pxTestElt->Data();

				pxGuids[uNumDone] = uGuid;
				++uNumDone;

				pxTestElt = pxTestElt->Next();
			}

			pxAVPEntity->SetRequiredGuids(pxGuids, uSize);

			delete [] pxGuids;
			Tools_SaveAsura::SetEntityModified();
		}
	}

	if ( s_bOptionalGameSceneMethodChanged )
	{
		AVP_ServerNode_Objective_Marine* pxAVPEntity = (AVP_ServerNode_Objective_Marine*)Entity;

		if (pxAVPEntity)
		{
			s_bOptionalGameSceneMethodChanged = false;

			u_int		uSize = m_xOptionalList.Size();
			Asura_Guid* pxGuids = new Asura_Guid[uSize];
			u_int		uNumDone = 0;

			Asura_ListElt< Asura_Guid >* pxTestElt = m_xOptionalList.Front();

			while ( pxTestElt != NULL )
			{
				Asura_Guid uGuid = pxTestElt->Data();

				pxGuids[uNumDone] = uGuid;
				++uNumDone;

				pxTestElt = pxTestElt->Next();
			}

			pxAVPEntity->SetOptionalGuids(pxGuids, uSize);

			delete [] pxGuids;
			Tools_SaveAsura::SetEntityModified();
		}
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Update
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::Update( void )
{
	PARENT::Update();

	// First Required Ones
	Asura_ListElt< Asura_Guid >* pxTestElt = m_xRequiredList.Front();

	while ( pxTestElt != NULL )
	{
		Asura_Guid uGuid = pxTestElt->Data();

		AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity(uGuid);

		if ( ( !pxGS2Node ) || ( pxGS2Node && pxGS2Node->GetStructureType() != AVP_GS_ST_REQUIRED_MARINE_ACTION ) )
		{
			pxTestElt = pxTestElt->Next();
			m_xRequiredList.Remove( uGuid );
			s_bRequiredGameSceneMethodChanged = true;

			if ( pxGS2Node && pxGS2Node->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION )
			{
				m_xOptionalList.Push_Back(uGuid);
				s_bOptionalGameSceneMethodChanged = true;
			}
		}
		else
		{
			pxTestElt = pxTestElt->Next();
		}
	}

	// Now Optional Ones
	pxTestElt = m_xOptionalList.Front();

	while ( pxTestElt != NULL )
	{
		Asura_Guid uGuid = pxTestElt->Data();

		AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity(uGuid);

		if ( ( !pxGS2Node ) || ( pxGS2Node && pxGS2Node->GetStructureType() != AVP_GS_ST_OPTIONAL_MARINE_ACTION ) )
		{
			pxTestElt = pxTestElt->Next();
			m_xOptionalList.Remove( uGuid );
			s_bOptionalGameSceneMethodChanged = true;

			if ( pxGS2Node && pxGS2Node->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION )
			{
				m_xRequiredList.Push_Back( uGuid );
				s_bRequiredGameSceneMethodChanged = true;
			}
		}
		else
		{
			pxTestElt = pxTestElt->Next();
		}
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Render
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::Render(void)
{
	PARENT::Render();

	if ((s_pxSelectedMarineObjective == this) || (s_bShowVolumes))
	{
		AVP_ServerNode_Objective_Marine* pxAVPEntity = (AVP_ServerNode_Objective_Marine*)Entity;

		if (pxAVPEntity)
		{
			AVP_ServerEntity_GamePlayVolume* pxVolume = NULL;

			if (m_iActionLinkingType == SPECIFIC_GAMEPLAYVOLUME && pxAVPEntity->GetGamePlayVolumeGuid() != ASURA_GUID_UNREGISTERED)
			{
				pxVolume = AVP_ServerEntity_GamePlayVolume::FindEntity(pxAVPEntity->GetGamePlayVolumeGuid());
			}
			else if (m_iActionLinkingType == NO_TYPE)
			{
				pxVolume = AVP_ServerEntity_GamePlayVolume::GetVolumeThatContainsPosition(Position);
			}

			if (pxVolume)
			{
				Tools_Render::RenderCylinder(pxVolume->GetPosition(), Position, 0.025f, 0x88aaaaff, false);

				// render actions
				for (Asura_Hashed_List_It<AVP_ServerNode_GS2Node> it(AVP_ServerNode_GS2Node::GetList()); !it.Done(); it.Next())
				{
					AVP_ServerNode_GS2Node* pxGS2Node = it.GetCurrent();

					if (pxGS2Node)
					{
						if (pxVolume->Contains(pxGS2Node->GetPosition()))
						{
							if (pxGS2Node->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION)
							{
								Tools_Render::RenderCylinder(pxGS2Node->GetPosition(), Position, 0.025f, 0xffff0000, false);
							}
							else if (pxGS2Node->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION)
							{
								Tools_Render::RenderCylinder(pxGS2Node->GetPosition(), Position, 0.025f, 0xff00ff00, false);
							}
						}
					}
				}
			}
			else
			{
				if (m_iActionLinkingType == SPECIFIC_GAMESCENES)
				{
					// required
					Asura_ListElt< Asura_Guid >* pxTestElt = m_xRequiredList.Front();

					while ( pxTestElt != NULL )
					{
						Asura_Guid uGuid = pxTestElt->Data();

						if (uGuid != ASURA_GUID_UNREGISTERED)
						{
							AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity(uGuid);

							if (pxGS2Node)
							{
								Tools_Render::RenderCylinder(pxGS2Node->GetPosition(), Position, 0.025f, 0xffff0000, false);
							}
						}

						pxTestElt = pxTestElt->Next();
					}

					// optional
					pxTestElt = m_xOptionalList.Front();

					while ( pxTestElt != NULL )
					{
						Asura_Guid uGuid = pxTestElt->Data();

						if (uGuid != ASURA_GUID_UNREGISTERED)
						{
							AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity(uGuid);

							if (pxGS2Node)
							{
								Tools_Render::RenderCylinder(pxGS2Node->GetPosition(), Position, 0.025f, 0xff00ff00, false);
							}
						}

						pxTestElt = pxTestElt->Next();
					}
				}
			}
		}
	}
}

//------------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: UpdatePositionInAsuraData
//------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::UpdatePositionInAsuraData(bool bUpdateLinkedObjects)
{
	AVP_ServerNode_Objective_Marine* pxAVPEntity = static_cast<AVP_ServerNode_Objective_Marine*>(Entity);

	if (s_bMoveVolumeWithObject)
	{
		Asura_Vector_3 xOffset = Position - m_xPreviousPosition;

		for (int i = 0; i < pxAVPEntity->m_iNumVolumes; i += 1)
		{
			pxAVPEntity->DisplaceVolumes(xOffset);
		}

		if (m_pxVolumeController)
		{
			m_pxVolumeController->MoveVolumeObjects(xOffset);
		}
	}

	//	Update the position if it has changed
	if	(pxAVPEntity->m_xPosition != Position)
	{
		pxAVPEntity->SetPosition(Position);

		Tools_SaveAsura::SetEntityModified();
	}

	m_xPreviousPosition = Position;

	PARENT::UpdatePositionInAsuraData(bUpdateLinkedObjects);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: AddOverlayControls
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::AddOverlayControls(class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset)
{
	PARENT::AddOverlayControls(pxOverlay, xOffset);

	Asura_Dialog* pxDialog;

	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_DropDown_List_Dialog(xOffset, ToolsAVP_Node_Objective_Marine::GetActionLinkTypeNames(), &m_iActionLinkingType, ToolsAVP_Node_Objective_Marine::MAX_TYPES, ToolsAVP_Node_Objective_Marine::MAX_TYPES, NULL, &s_bActionLinkTypeChanged, "");
	pxDialog->SetHelpText("The type of Goal");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	if (m_iActionLinkingType == SPECIFIC_GAMEPLAYVOLUME)
	{
		pxDialog = new Asura_StringDisplay_Dialog("Select The Game Play Volume:", xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("", xOffset, SelectGPV, &s_bActionLinkTypeChanged);
		pxDialog->SetHelpText("Selects The Game Play Volume The Goal Will use To Find Its Action Game Scenes");
		UpdateGamePlayVolumeTextDialog(pxDialog);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Clear The Selected Game Play Volume", xOffset, ClearGPV, &s_bActionLinkTypeChanged);
		pxDialog->SetHelpText("Clears The Game Play Volume The Goal Will use To Find Its Action Game Scenes");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();
	}
	else if (m_iActionLinkingType == SPECIFIC_GAMESCENES)
	{
		pxDialog = new Asura_StringDisplay_Dialog("Required Action Game Scenes", xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Add Required Action", xOffset, SelectRequiredActionToAdd, &s_bRequiredGameSceneMethodChanged);
		pxDialog->SetHelpText("Allows Selection of a Required Game Scene Node");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Remove Required Action(s)", xOffset, SelectRequiredActionToRemove, &s_bRequiredGameSceneMethodChanged);
		pxDialog->SetHelpText("Allows Selection of a Required Game Scene Node");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		pxDialog = new Asura_StringDisplay_Dialog("Optional Action Game Scenes(s)", xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Add Optional Action(s)", xOffset, SelectOptionalActionToAdd, &s_bOptionalGameSceneMethodChanged);
		pxDialog->SetHelpText("Allows Selection of a Optional Game Scene Node");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Remove Optional Action(s)", xOffset, SelectOptionalActionToRemove, &s_bOptionalGameSceneMethodChanged);
		pxDialog->SetHelpText("Allows Selection of a Optional Game Scene Node");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();
	}

	pxDialog = new Asura_Tickbox_Dialog("Loop Goal GameScenes Until Message Complete Received", xOffset, &m_bObjectiveCompleteOnMessage, &Changed);
	pxDialog->SetHelpText("If this is ticked the goal will only be recognised as complete when you send an 'Goal Complete' message to this entity.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

// 	pxDialog = new Asura_Tickbox_Dialog("Run While Pathing To GameScene Action", xOffset, &m_bRunToAction, &Changed);
// 	pxDialog->SetHelpText("If this is ticked the Marine/Android Actors will run to their GameScene rather than walk while pathing.");
// 	pxOverlay->AddDialog(pxDialog);
// 	xOffset.y += Asura_Dialog::LargeSpacing();
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::SelectRequiredActionToAdd( void )
{
	if ( !s_pxSelectedMarineObjective ) { return; }

	ToolsAVP_ChooseGS2Object* pxChooseObject = new ToolsAVP_ChooseGS2Object(TOT_Entity_GS2Node, AVP_GS_ST_REQUIRED_MARINE_ACTION, true, SetRequiredAction );
	pxChooseObject->SetAllowMultipleSelection( true );
	Tools_Object_System::ChooseObject("Select The Required action Game Scene Node", pxChooseObject);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::SelectOptionalActionToAdd( void )
{
	if ( !s_pxSelectedMarineObjective ) { return; }

	ToolsAVP_ChooseGS2Object* pxChooseObject = new ToolsAVP_ChooseGS2Object(TOT_Entity_GS2Node, AVP_GS_ST_OPTIONAL_MARINE_ACTION, true, SetOptionalAction );
	pxChooseObject->SetAllowMultipleSelection( true );
	Tools_Object_System::ChooseObject("Select The Required action Game Scene Node", pxChooseObject);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::SelectRequiredActionToRemove( void )
{
	if ( !s_pxSelectedMarineObjective ) { return; }

	ToolsAVP_ChooseGS2Object* pxChooseObject = new ToolsAVP_ChooseGS2Object(TOT_Entity_GS2Node, AVP_GS_ST_REQUIRED_MARINE_ACTION, false, RemoveRequiredAction );
	pxChooseObject->SetAllowMultipleSelection( true );
	Tools_Object_System::ChooseObject("Select The Required action Game Scene Node", pxChooseObject);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::SelectOptionalActionToRemove( void )
{
	if ( !s_pxSelectedMarineObjective ) { return; }

	ToolsAVP_ChooseGS2Object* pxChooseObject = new ToolsAVP_ChooseGS2Object(TOT_Entity_GS2Node, AVP_GS_ST_OPTIONAL_MARINE_ACTION, false, RemoveOptionalAction );
	pxChooseObject->SetAllowMultipleSelection( true );
	Tools_Object_System::ChooseObject("Select The Required action Game Scene Node", pxChooseObject);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
bool ToolsAVP_ChooseGS2Object::CanBeSelected(Tools_Object* pxObject)
{
	if (pxObject->Type != TOT_Entity_AVPGS2Node)
	{
		return false;
	}

	AVP_ServerNode_GS2Node* pxNode = AVP_ServerNode_GS2Node::FindEntity( pxObject->GetGuid() );

	if ( ( !pxNode ) || ( pxNode->GetStructureType() != m_iStructureType ) )
	{
		return false;
	}

	ToolsAVP_Node_Objective_Marine* pxToolsObjective = ToolsAVP_Node_Objective_Marine::GetSelectedObjective();

	if ( !pxToolsObjective )
	{
		return false;
	}

	if (m_bAdd)
	{
		// Check we haven't already got it added
		if ( ( (pxNode->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION) && ( pxToolsObjective->m_xRequiredList.Find( pxNode->GetGuid() ) ) ) || ( (pxNode->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION) && ( pxToolsObjective->m_xOptionalList.Find( pxNode->GetGuid() ) ) ) )
		{
			return false;
		}
	}
	else
	{
		// check we have got it added already to remove
		if ( ( (pxNode->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION) && ( !pxToolsObjective->m_xRequiredList.Find( pxNode->GetGuid() ) ) ) || ( (pxNode->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION) && ( !pxToolsObjective->m_xOptionalList.Find( pxNode->GetGuid() ) ) ) )
		{
			return false;
		}
	}
	
	return true;
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::SetRequiredAction( Asura_Guid uGuid )
{
	ToolsAVP_Node_Objective_Marine* pxToolsObjective = ToolsAVP_Node_Objective_Marine::GetSelectedObjective();
	if ( !pxToolsObjective ) { return; }
	if ( uGuid == ASURA_GUID_UNREGISTERED ) { return; }

	pxToolsObjective->m_xRequiredList.Push_Back(uGuid);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::RemoveRequiredAction( Asura_Guid uGuid )
{
	ToolsAVP_Node_Objective_Marine* pxToolsObjective = ToolsAVP_Node_Objective_Marine::GetSelectedObjective();
	if ( !pxToolsObjective ) { return; }
	if ( uGuid == ASURA_GUID_UNREGISTERED ) { return; }

	pxToolsObjective->m_xRequiredList.Remove(uGuid);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::SetOptionalAction( Asura_Guid uGuid )
{
	ToolsAVP_Node_Objective_Marine* pxToolsObjective = ToolsAVP_Node_Objective_Marine::GetSelectedObjective();
	if ( !pxToolsObjective ) { return; }
	if ( uGuid == ASURA_GUID_UNREGISTERED ) { return; }

	pxToolsObjective->m_xOptionalList.Push_Back(uGuid);
}

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::RemoveOptionalAction( Asura_Guid uGuid )
{
	ToolsAVP_Node_Objective_Marine* pxToolsObjective = ToolsAVP_Node_Objective_Marine::GetSelectedObjective();
	if ( !pxToolsObjective ) { return; }
	if ( uGuid == ASURA_GUID_UNREGISTERED ) { return; }

	pxToolsObjective->m_xOptionalList.Remove(uGuid);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Create
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::Create(void)
{
	const Asura_Guid uGuid = Asura_Entity_System::GetCreatedByToolsGuid();

	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("AI Marine Goal", "AI Marine Goal", uGuid);

	if (pxToolsData == NULL)
	{
		Asura_Assert(false, "ToolsAVP_Node_Objective_Marine::Create() - no tools data");
	}
	else
	{
		AVP_ServerNode_Objective_Marine* pxServerObject = new AVP_ServerNode_Objective_Marine(uGuid);

		if (pxServerObject == NULL)
		{
			Asura_Assert(false, "ToolsAVP_Node_Objective_Marine::Create() - no server object" );
		}
		else
		{
			pxServerObject->ToolsData = pxToolsData;

			ToolsAVP_Node_Objective_Marine* pxToolsObject = new ToolsAVP_Node_Objective_Marine(pxServerObject);

			// Create the game specific tools object and select it.
			if (pxToolsObject == NULL)
			{
				Asura_Assert(false, "ToolsAVP_Node_Objective_Marine::Create() - no tools object");
			}
			else
			{
				Tools_Object_System::SelectObject(pxToolsObject);

				pxToolsObject->Position		= *Asura_Camera::GetPosition();
				pxToolsObject->m_uGuid		= uGuid;

				pxServerObject->SetPosition(pxToolsObject->Position);

				Tools_Timed_Message_System::AddMessage(Tools_Timed_Message_System::COLOUR_INFO, "Created New Goal");
				Tools_SaveAsura::SetEntityModified();
			}
		}
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Verify
//-----------------------------------------------------------------------------
bool ToolsAVP_Node_Objective_Marine::Verify( const bool bAutomatic )
{
	bool bOk = true;

	AVP_ServerNode_Objective* pxObjective = AVP_ServerNode_Objective::FindEntity( GetGuid() );

	if ( pxObjective )
	{
		if ( pxObjective->GetNumberOfVolumes() == 0)
		{
			bOk = false;
			Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Objective / AI Goal", new Tools_MessageLogAction_GotoEntity( GetGuid() ), "Objective / AI Goal %u has NO VOLUME", GetGuid() );
		}
	}

	return bOk;
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Create
//-----------------------------------------------------------------------------
Tools_Object* ToolsAVP_Node_Objective_Marine::Create(Asura_Entity* pxEntity)
{
	return new ToolsAVP_Node_Objective_Marine(pxEntity);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: CreateAndReturn
//-----------------------------------------------------------------------------
Tools_Object* ToolsAVP_Node_Objective_Marine::CreateAndReturn(void)
{
	const Asura_Guid uGuid = Asura_Entity_System::GetCreatedByToolsGuid();

	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("AI Marine Goal", "AI Marine Goal", uGuid);

	if (pxToolsData == NULL)
	{
		Asura_Assert(false, "ToolsAVP_Node_Objective_Marine::Create() - no tools data");
	}
	else
	{
		AVP_ServerNode_Objective_Marine* pxServerObject = new AVP_ServerNode_Objective_Marine(uGuid);

		if (pxServerObject == NULL)
		{
			Asura_Assert(false, "ToolsAVP_Node_Objective_Marine::Create() - no server object" );
		}
		else
		{
			pxServerObject->ToolsData = pxToolsData;

			ToolsAVP_Node_Objective_Marine* pxToolsObject = new ToolsAVP_Node_Objective_Marine(pxServerObject);

			// Create the game specific tools object and select it.
			if (pxToolsObject == NULL)
			{
				Asura_Assert(false, "ToolsAVP_Node_Objective_Marine::Create() - no tools object");
			}
			else
			{
				Tools_Object_System::SelectObject(pxToolsObject);

				pxToolsObject->Position		= *Asura_Camera::GetPosition();
				pxToolsObject->m_uGuid		= uGuid;

				pxServerObject->SetPosition(pxToolsObject->Position);

				Tools_Timed_Message_System::AddMessage(Tools_Timed_Message_System::COLOUR_INFO, "Created New AI Goal");
				Tools_SaveAsura::SetEntityModified();
				return pxToolsObject;
			}
		}
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: Project_Create
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::Project_Create(void)
{
	ToolsAVP_Node_Objective_Marine::Create();
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: CreateObjectOfThisType
//-----------------------------------------------------------------------------
Tools_Object* ToolsAVP_Node_Objective_Marine::CreateObjectOfThisType(void) const
{
	return CreateAndReturn();
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: OnSelection
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::OnSelection(void)
{
	s_pxSelectedMarineObjective = this;

	PARENT::OnSelection();
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: OnDeselection
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective_Marine::OnDeselection(void)
{
	PARENT::OnDeselection();

	s_pxSelectedMarineObjective = NULL;
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective_Marine :: IsBaseOrDerivativeOf
//-----------------------------------------------------------------------------
bool ToolsAVP_Node_Objective_Marine::IsBaseOrDerivativeOf( int iToolsObjectType ) const
{
	if ( iToolsObjectType == TOT_Entity_AI_Marine_Objective )
	{
		return true;
	}

	return PARENT::IsBaseOrDerivativeOf( iToolsObjectType );
}