//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Entity_PlayerObjective.cpp
//
// Created by AJK 01 / 10 / 2008
//
// Copyright (c) 2009 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

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

// Header
#include "Entity/ObjectiveSystem/PlayerObjective/ToolsAVP_Entity_PlayerObjective.h"

// Asura
#include "Camera/Asura_Camera.h"
#include "Mesh/Asura_Mesh_System.h"
#include "GUIMenu/Asura_GUIMenu_Element_Text.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#include "Core/Asura_HashedLocalisedText.h"

// AVP
#include "Entity/AVP_Entity_EventIDs.h"
#include "Entity/ObjectiveSystem/PlayerObjective/AVP_ServerEntity_LocationMarker.h"
#include "Entity/ObjectiveSystem/PlayerObjective/AVP_ServerEntity_PlayerObjective.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/AVP_Messages.h"

// Tools
#include "Entity/Tools_SecondaryEntityFile_System.h"
#include "Entity/ObjectiveSystem/PlayerObjective/ToolsAVP_Entity_LocationMarker.h"
#include "GUIMenu/Tools_GUIMenu_Element_Text.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/ToolsAVP_Object_Type.h"
#include "GUIMenu/Tools_GUIMenu_System.h"
#include "Misc/Tools_LOS.h"

// Statics definition
Asura_Hashed_List<ToolsAVP_Entity_PlayerObjective>	ToolsAVP_Entity_PlayerObjective::s_xList;
ToolsAVP_Entity_PlayerObjective*					ToolsAVP_Entity_PlayerObjective::s_pxSelectedPlayerObjective = NULL;

ToolsAVP_Entity_PlayerObjective::ToolsAVP_Entity_PlayerObjective(Asura_Entity* pxEntity)
: PARENT(pxEntity)
, m_pxOverlay(NULL)
{
	Type = TOT_Entity_Player_Objective;

	SetMesh("ToolsShape_PlayerObjective");

	AVP_ServerEntity_PlayerObjective* pxAVPEntity = (AVP_ServerEntity_PlayerObjective*)Entity;

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

	s_xList.AddToList(this);
}

void ToolsAVP_Entity_PlayerObjective::Destroy()
{
	// Destroy and delete tools and AVP objects
	AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(Entity);
	if(pxAVPEntity)
	{
		Asura_LinkList_It< Asura_Guid > xLinkListIter( pxAVPEntity->m_xMarkerList );
		while ( !xLinkListIter.Done() )
		{
			ToolsAVP_Entity_LocationMarker* pxToDestroy = ToolsAVP_Entity_LocationMarker::FindEntity( *xLinkListIter.GetCurrent() );
			xLinkListIter.Next();
			pxToDestroy->Destroy();
		}
	}

	PARENT::Destroy();
}

ToolsAVP_Entity_PlayerObjective::~ToolsAVP_Entity_PlayerObjective(void)
{
	s_xList.RemoveFromList(this);
}

void ToolsAVP_Entity_PlayerObjective::AddOverlayControls(class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset)
{
	AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(Entity);

	if(pxAVPEntity)
	{
		PARENT::AddOverlayControls(pxOverlay, xOffset);

		Asura_Dialog* pxDialog = new Asura_Function_Dialog("Text",xOffset,ChooseText,(int)this);
		pxDialog->SetHelpText("Select the text to use.");
		pxDialog->m_iControlID = Asura_GetHashID("SelectText");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		//Drop down box for setting the objective target location
		pxDialog = new Asura_StringDisplay_Dialog("Inital objective target:", xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();
		pxDialog = new Asura_DropDown_List_Dialog(xOffset, AVP_ServerEntity_PlayerObjective::s_aszTargetTypes, &pxAVPEntity->m_iTargetType, AVP_ServerEntity_PlayerObjective::NUM_TARGET_TYPES, AVP_ServerEntity_PlayerObjective::NUM_TARGET_TYPES, NULL, &Changed,"");
		pxDialog->SetHelpText("Select the inital target type for this objective.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		// Location markers
		pxDialog = new Asura_StringDisplay_Dialog("Location markers", xOffset);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Add location marker ( e )", xOffset, AddLocationMarker, 0);
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();

		pxDialog = new Asura_Function_Dialog("Select target", xOffset, SelectEntity, &Changed);
		pxDialog->SetHelpText("Enables the actor/marker to track.");
		pxDialog->SetIsEnabledFunction( GetHasTarget );
		pxOverlay->AddDialog(pxDialog);
		pxDialog->m_iControlID = Asura_GetHashID("SelectEntity");
		xOffset.y += Asura_Dialog::DefaultSpacing();

		m_pxOverlay = pxOverlay;
		// Update text
		UpdateText();
		UpdateTargetGuid();
	}
}

void ToolsAVP_Entity_PlayerObjective::SelectEntity(void)
{
	ToolsAVP_ChooseObject_ByType*     pxChooseObject = NULL;
	AVP_ServerEntity_PlayerObjective* pxEntity = AVP_ServerEntity_PlayerObjective::GetList()->FindObject(ThisEntity->GetGuid());
	if ( pxEntity )
	{
		if ( pxEntity->m_iTargetType == AVP_ServerEntity_PlayerObjective::TARGET_ENTITY )
		{
			pxChooseObject = new ToolsAVP_ChooseObject_ByType( TOT_Entity_Marine, SetSelectedEntity );
			pxChooseObject->AddType(TOT_Entity_Alien);
			pxChooseObject->AddType(TOT_Entity_Predator);
			pxChooseObject->AddType(TOT_Entity_AlienQueen);
			pxChooseObject->AddType(TOT_Entity_Android);
			pxChooseObject->AddType(TOT_Entity_Civilian);
			pxChooseObject->AddType(TOT_Entity_Predalien);
		}
		else if ( pxEntity->m_iTargetType == AVP_ServerEntity_PlayerObjective::TARGET_LOCATION_MARKER)
		{
			pxChooseObject = new ToolsAVP_ChooseObject_ByType( TOT_Entity_LocationMarker, SetSelectedEntity );
		}
	}

	Tools_Object_System::ChooseObject("Pick the Entity/Location", pxChooseObject);
}

bool ToolsAVP_Entity_PlayerObjective::GetHasTarget()
{
	AVP_ServerEntity_PlayerObjective* pxEntity = AVP_ServerEntity_PlayerObjective::GetList()->FindObject(ThisEntity->GetGuid());

	return(   pxEntity->m_iTargetType == AVP_ServerEntity_PlayerObjective::TARGET_ENTITY
		   || pxEntity->m_iTargetType == AVP_ServerEntity_PlayerObjective::TARGET_LOCATION_MARKER );
}

void ToolsAVP_Entity_PlayerObjective::SetSelectedEntity(Asura_Guid uGuid)
{
	if (s_pxSelectedPlayerObjective != NULL)
	{
		AVP_ServerEntity_PlayerObjective* pxEntity = AVP_ServerEntity_PlayerObjective::FindEntity(s_pxSelectedPlayerObjective->GetGuid());

		if (pxEntity)
		{
			pxEntity->SetTargetGuid(uGuid);
			s_pxSelectedPlayerObjective->DeleteOverlay();
			s_pxSelectedPlayerObjective->CreateOverlay();
		}
	}
}

void ToolsAVP_Entity_PlayerObjective::Update()
{
	PARENT::Update();

	AVP_ServerEntity_PlayerObjective* pxEntity = AVP_ServerEntity_PlayerObjective::GetList()->FindObject(this->GetGuid());

	if (pxEntity)
	{
		if (pxEntity->GetTargetGuid() != ASURA_GUID_UNREGISTERED)
		{
			Asura_Entity_Server* pxTargetEntity = Asura_Entity_Server::FindEntity(pxEntity->GetTargetGuid());

			if (!pxTargetEntity)
			{
				pxEntity->SetTargetGuid(ASURA_GUID_UNREGISTERED);
			}
		}
	}
}

void ToolsAVP_Entity_PlayerObjective::UpdateTargetGuid()
{
	AVP_ServerEntity_PlayerObjective* pxEntity = AVP_ServerEntity_PlayerObjective::GetList()->FindObject(ThisEntity->GetGuid());

	if(pxEntity)
	{
		char szText[100];

		if ( ( pxEntity->m_iTargetType == AVP_ServerEntity_PlayerObjective::TARGET_ENTITY ) || ( pxEntity->m_iTargetType == AVP_ServerEntity_PlayerObjective::TARGET_LOCATION_MARKER ) )
		{
			Asura_PrintfToBfr(szText,"Target GUID : %d",sizeof(szText),true, pxEntity->GetTargetGuid());	
		}
		else
		{
			strcpy(szText,"Select Target");
		}
		m_pxOverlay->UpdateDialogLabel(Asura_GetHashID("SelectEntity"),szText);
	}
}

void ToolsAVP_Entity_PlayerObjective::UpdateText()
{
	Asura_Hash_ID uMenuPage = Asura_GetHashID("Menu") ;

	AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(Entity);

	if(pxAVPEntity)
	{
		char szText[100];
		const Asura_HashedLocalisedText_Page* pxPage = Asura_HashedLocalisedText::GetPage(uMenuPage);

		const char* szTextID = 0;

		if(pxPage && pxPage->HasTextIDStrings())
		{
			szTextID = pxPage->GetTextIDString(pxAVPEntity->GetObjectiveText().GetTextID());
		}

		if(szTextID)
		{
			Asura_PrintfToBfr(szText,"Name : %s",sizeof(szText),true,szTextID);	
		}
		else
		{
			strcpy(szText,"Name : *Unknown*");
		}

		m_pxOverlay->UpdateDialogLabel(Asura_GetHashID("SelectText"),szText);
	}
}

void ToolsAVP_Entity_PlayerObjective::ChooseText()
{
	Asura_Hash_ID uMenuPage = Asura_GetHashID("Menu") ;


	AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(Entity);

	if(pxAVPEntity)
	{
		Asura_Hash_ID uTextID = pxAVPEntity->GetObjectiveText().GetTextID();
		if(!Tools_Mode_GUIMenu::ChooseText(uMenuPage, uTextID)) { return; }

		if(uTextID != pxAVPEntity->GetObjectiveText().GetTextID())
		{
			pxAVPEntity->GetObjectiveText().SetTextID(uTextID);
			UpdateText();
			Tools_SaveAsura::SetEntityModified(pxAVPEntity);
		}	
	}
}

void ToolsAVP_Entity_PlayerObjective::Create(void)
{
	const Asura_Guid uGuid = Asura_Entity_System::GetCreatedByToolsGuid();

	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("Player Objective", "Player Objective", uGuid);

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

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

			ToolsAVP_Entity_PlayerObjective* pxToolsObject = new ToolsAVP_Entity_PlayerObjective(pxServerObject);

			// Create the game specific tools object and select it.
			if (pxToolsObject == NULL)
			{
				Asura_Assert(false, "ToolsAVP_Entity_PlayerObjective::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 player objective");
				Tools_SaveAsura::SetEntityModified();
			}
		}
	}
}

Tools_Object* ToolsAVP_Entity_PlayerObjective::Create(Asura_Entity* pxEntity)
{
	return new ToolsAVP_Entity_PlayerObjective(pxEntity);
}

Tools_Object* ToolsAVP_Entity_PlayerObjective::CreateAndReturn(void)
{
	const Asura_Guid uGuid = Asura_Entity_System::GetCreatedByToolsGuid();

	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("Player Objective", "Player Objective", uGuid);

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

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

			ToolsAVP_Entity_PlayerObjective* pxToolsObject = new ToolsAVP_Entity_PlayerObjective(pxServerObject);

			// Create the game specific tools object and select it.
			if (pxToolsObject == NULL)
			{
				Asura_Assert(false, "ToolsAVP_Entity_PlayerObjective::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 player Objective");
				Tools_SaveAsura::SetEntityModified();
				return pxToolsObject;
			}
		}
	}

	return NULL;
}

void ToolsAVP_Entity_PlayerObjective::Project_Create(void)
{
	ToolsAVP_Entity_PlayerObjective::Create();
}

Tools_Object* ToolsAVP_Entity_PlayerObjective::CreateObjectOfThisType(void) const
{
	return CreateAndReturn();
}

void ToolsAVP_Entity_PlayerObjective::OnSelection(void)
{
	s_pxSelectedPlayerObjective = this;

	PARENT::OnSelection();
}

void ToolsAVP_Entity_PlayerObjective::OnDeselection(void)
{
	PARENT::OnDeselection();

	s_pxSelectedPlayerObjective = NULL;
}

void ToolsAVP_Entity_PlayerObjective::Render()
{
	PARENT::Render();
	AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(Entity);

	if(pxAVPEntity)
	{
		Asura_LinkList_ConstIt< Asura_Guid > xLinkListIter( pxAVPEntity->m_xMarkerList );
		while ( !xLinkListIter.Done() )
		{
			AVP_ServerEntity_LocationMarker* pxMarker = AVP_ServerEntity_LocationMarker::FindEntity(  (*xLinkListIter.GetCurrent()) );
			if(pxMarker)
			{
				Asura_Vector_3   xPosition = pxMarker->GetPosition();
				Asura_Matrix_3x3 xOrientation;
				xOrientation.Identity();

				if ( pxAVPEntity->m_uTargetGuid == pxMarker->GetGuid() )
				{
					Asura_Render::RenderLine( Position, xPosition, 0xff00ff00 );
				}
				else
				{
					Asura_Render::RenderLine( Position, xPosition, 0xffffffff );
				}
			}

			xLinkListIter.Next();
		}
	}
}

void ToolsAVP_Entity_PlayerObjective::UpdatePositionInAsuraData( bool bUpdateLinkedObjects )
{
	AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(Entity);
	
	pxAVPEntity->SetPosition( Position );

	PARENT::UpdatePositionInAsuraData( bUpdateLinkedObjects );
}

void ToolsAVP_Entity_PlayerObjective::AddLocationMarker(int iUserData)
{
	Asura_Assert(s_pxSelectedPlayerObjective, "No RoomNode selected, should be impossible.");
	if (!s_pxSelectedPlayerObjective) { return; }

	// Create a new location marker
	AVP_ServerEntity_LocationMarker* pxNewMarker = AVP_ServerEntity_LocationMarker::Create( Asura_Entity_System::GetCreatedByToolsGuid() );
	if ( pxNewMarker )
	{			
		Asura_Vector_3 xPosition;
		// Add an emerge point under the cursor.
		int iPolyIndex, iModuleIndex;
		if ( iUserData == 0 || !Tools_LOS::FindPolyAndPositionUnderCursor( iPolyIndex, iModuleIndex, xPosition ) )
		{
			xPosition = *Asura_Camera::GetPosition();				
		}

		pxNewMarker->SetPosition( xPosition );
		pxNewMarker->SetPlayerObjectiveGuid( s_pxSelectedPlayerObjective->GetGuid() );

		AVP_ServerEntity_PlayerObjective* pxAVPEntity = static_cast<AVP_ServerEntity_PlayerObjective*>(s_pxSelectedPlayerObjective->Entity);

		pxAVPEntity->m_xMarkerList.Push_Back( pxNewMarker->GetGuid() );

		// Add the tools side marker point
		// Create the tools marker point
		Tools_SecondaryEntityFile_System::PreCreateObject();
		ToolsAVP_Entity_LocationMarker* pxNewToolsMarker = static_cast< ToolsAVP_Entity_LocationMarker* > (ToolsAVP_Entity_LocationMarker::Create( pxNewMarker ) );
		Tools_SecondaryEntityFile_System::PostCreateObject();
		if ( pxNewToolsMarker )
		{
			pxNewToolsMarker->SetLocationMarker( pxNewMarker );
		}
	}
	s_pxSelectedPlayerObjective->SetEntityModified();
}

void ToolsAVP_Entity_PlayerObjective::UpdateWhileSelected()
{
	// Execute keyboard shortcuts
	if( !Asura_Overlay_System::OverlaysHaveKeyboardFocus() )
	{
		if(!Asura_UserInput::KeyPressed(ASURA_KEYID_ALT) && !Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
		{
			if ( !Asura_UserInput::KeyPressed( ASURA_KEYID_SHIFT ) )
			{
				if(Asura_UserInput::DebouncedKeyPressed('e'))
				{
					AddLocationMarker(1);
				}
			}
		}
	}

	PARENT::UpdateWhileSelected();
}

bool ToolsAVP_Entity_PlayerObjective::HandlesThisMessage(int iMessageID)
{
	switch(iMessageID)
	{
		case AVP_MSGID_PLAYER_OBJECTIVE_SET_MARKER_LOCATION:
		case AVP_MSGID_PLAYER_OBJECTIVE_SET_TARGET_ENTITY:
		case AVP_MSGID_PLAYER_OBJECTIVE_SET_CURRENT:
		case AVP_MSGID_PLAYER_OBJECTIVE_SET_COMPLETE:
		case AVP_MSGID_PLAYER_OBJECTIVE_SET_USE_OWN_LOCATION:
		case AVP_MSGID_PLAYER_OBJECTIVE_SET_NO_MARKER:
		{
			// This entity can receive change ownership messages
			return true;
		}
		default:
		{
			return PARENT::HandlesThisMessage(iMessageID); 
		}
	}
}

