//-----------------------------------------------------------------------------
// File			: ToolsAVP_Node_Objective.cpp
// Author		: Gareth Thomas
// Created		: 18 / 12 / 2007
// Copyright (c) 2007 Rebellion. All rights reserved.
//-----------------------------------------------------------------------------

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

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

// Header
#include "Entity/Locations/Objective/ToolsAVP_Node_Objective.h"

// Asura
#include "Camera/Asura_Camera.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Volume/Asura_Volume_Cuboid.h"
#include "Volume/Asura_Volume_Cylinder.h"
#include "Volume/Asura_Volume_Sphere.h"

// AVP
#include "Entity/Locations/Objective/AVP_ServerNode_Objective.h"

// Tools
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/ToolsAVP_Object_Type.h"
#include "Entity/GamePlayVolume/ToolsAVP_Entity_GamePlayVolume.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/ToolsAVP_Object_Type.h"
#include "ToolsAVP_ChooseObjects.h"

//------------------------------------------------------------------------------
// Constants, Defines, Statics and Globals
//------------------------------------------------------------------------------
Asura_Hashed_List<ToolsAVP_Node_Objective>				ToolsAVP_Node_Objective::s_xList;
ToolsAVP_Node_Objective*								ToolsAVP_Node_Objective::s_pxSelectedObjective = NULL;

bool													ToolsAVP_Node_Objective::s_bVolumesEdited = false;
bool													ToolsAVP_Node_Objective::s_bShowVolumes = false;
bool													ToolsAVP_Node_Objective::s_bShowSelectedVolume = false;
bool													ToolsAVP_Node_Objective::s_bMoveVolumeWithObject = true;

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

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective :: Constructor
//-----------------------------------------------------------------------------
ToolsAVP_Node_Objective::ToolsAVP_Node_Objective(Asura_Entity* pxEntity)
: PARENT(pxEntity)
{
	Type = TOT_Entity_AI_Objective;
	m_pxVolumeController = 0;

	s_xList.AddToList(this);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective :: Deconstructor
//-----------------------------------------------------------------------------
ToolsAVP_Node_Objective::~ToolsAVP_Node_Objective(void)
{
	if (m_pxVolumeController)
	{
		delete (m_pxVolumeController);
		m_pxVolumeController = NULL;
	}

	s_xList.RemoveFromList(this);
}

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

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

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

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

			ToolsAVP_Node_Objective* pxToolsObject = new ToolsAVP_Node_Objective(pxServerObject);

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

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

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

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

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

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

			ToolsAVP_Node_Objective* pxToolsObject = new ToolsAVP_Node_Objective(pxServerObject);

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

	return NULL;
}

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

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

//-----------------------------------------------------------------------------
// ToolsAVP_Node_Objective :: OnSelection
//-----------------------------------------------------------------------------
void ToolsAVP_Node_Objective::OnSelection(void)
{
	s_pxSelectedObjective = this;

	PARENT::OnSelection();
}

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

	s_pxSelectedObjective = NULL;
}

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

	return PARENT::IsBaseOrDerivativeOf( iToolsObjectType );
}

void ToolsAVP_Node_Objective::UpdateWhileSelected(void)
{
	if (s_bVolumesEdited)
	{
		s_bVolumesEdited = false;
		Tools_SaveAsura::SetEntityModified();
	}
}

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

	Asura_Dialog* pxDialog = new Asura_Function_Dialog("Edit Volumes", xOffset, EditVolume, &s_bVolumesEdited);
	pxDialog->SetHelpText("Edits The Volume(s).");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog("Show Selected Volume", xOffset, &s_bShowSelectedVolume, &Changed);
	pxDialog->SetHelpText("Select To Show All The Volumes Of The Selected GamePlayVolume.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog("Show All Volumes", xOffset, &s_bShowVolumes, &Changed);
	pxDialog->SetHelpText("Select To Show All The Volumes Of All GamePlayVolume In The Level.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog("Move Volume With Object", xOffset, &s_bMoveVolumeWithObject);
	pxDialog->SetHelpText("The Volumes Attached To This Entity Should Be Moved When The Trigger's Tools Object Is Moved.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();
}

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

	if ((s_bShowVolumes) || ((s_bShowSelectedVolume) && (this == s_pxSelectedObjective)))
	{
		AVP_ServerNode_Objective* pxAVPEntity = (AVP_ServerNode_Objective*)Entity;

		if (pxAVPEntity)
		{
			for (int i = 0; i < pxAVPEntity->m_iNumVolumes; ++i)
			{
				switch (pxAVPEntity->GetVolume(i)->GetClassification())
				{
				case ASURA_VOLUME_CLASSIFICATION_CUBOID:
					{
						Asura_Volume_Cuboid*	pxCubeVolume	= static_cast<Asura_Volume_Cuboid*>(pxAVPEntity->GetVolume(i));
						Asura_Bounding_Box		xRelativeBox	= *pxCubeVolume->GetVolumeBox();
						Asura_Vector_3			xCentre			= xRelativeBox.CalculateCentre();

						xRelativeBox.Displace(-xCentre);

						Asura_Matrix_3x3 xMat;
						pxCubeVolume->GetVolumeOrient()->ToMatrix(xMat);

						Tools_Render::RenderCube(xRelativeBox, xCentre, xMat, 0xff00ff00, true);
						Tools_Render::RenderCube(xRelativeBox, xCentre, xMat, 0x6655ff55, false);

					}break;
				case ASURA_VOLUME_CLASSIFICATION_SPHERE:
					{
						Asura_Volume_Sphere* pxSphereVolume = static_cast<Asura_Volume_Sphere*>(pxAVPEntity->GetVolume(i));

						Asura_Matrix_3x3 xMat;
						pxSphereVolume->GetVolumeOrient()->ToMatrix(xMat);

						float			fRadius = *pxSphereVolume->GetRadiusPtr();
						Asura_Vector_3 xExtents = Asura_Vector_3(fRadius, fRadius, fRadius);

						Tools_Render::RenderSpheroid(*pxSphereVolume->GetPositionPtr(), xMat, xExtents, 0xff00ff00, true);
						Tools_Render::RenderSpheroid(*pxSphereVolume->GetPositionPtr(), xMat, xExtents, 0x6655ff55, false);

					}break;
				case ASURA_VOLUME_CLASSIFICATION_CYLINDER:
					{
						Asura_Volume_Cylinder* pxCylinderVolume = static_cast<Asura_Volume_Cylinder*>(pxAVPEntity->GetVolume(i));

						Asura_Matrix_3x3 xMat;
						pxCylinderVolume->GetVolumeOrient()->ToMatrix(xMat);

						Asura_Vector_3 xUp = Asura_Vector_3(xMat.e12, xMat.e22, xMat.e32);
						Asura_Vector_3 xStart = *pxCylinderVolume->GetPositionPtr();
						Asura_Vector_3 xEnd = *pxCylinderVolume->GetPositionPtr() + (-xUp * *pxCylinderVolume->GetHeightPtr());

						Tools_Render::RenderCylinder(xStart, xEnd, *pxCylinderVolume->GetRadiusPtr(), 0xff00ff00, true);
						Tools_Render::RenderCylinder(xStart, xEnd, *pxCylinderVolume->GetRadiusPtr(), 0x6655ff55, false);

					}break;
				default:
					{
						Asura_Assert(0,"ToolsAVP_Node_Objective_Marine :: Render - Unkown Volume Classification");

					}break;
				}
			}
		}
	}
}


//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
void ToolsAVP_Node_Objective::UpdateGamePlayVolumeTextDialog(Asura_Dialog* pxDialog)
{
	AVP_ServerNode_Objective* pxAVPObjective = (AVP_ServerNode_Objective*)Entity;
	Asura_Guid	uGPVGuid = ASURA_GUID_UNREGISTERED;

	if (pxAVPObjective)
	{
		uGPVGuid = pxAVPObjective->GetGamePlayVolumeGuid();
	}

	if (uGPVGuid != ASURA_GUID_UNREGISTERED)
	{
		ToolsAVP_Entity_GamePlayVolume* pxGPV = (ToolsAVP_Entity_GamePlayVolume*)ToolsAVP_Entity_GamePlayVolume::FindEntity(uGPVGuid);

		if (pxGPV)
		{
			pxDialog->UpdateLabel(pxGPV->GetName());
		}
		else
		{
			pxDialog->UpdateLabel("GPV Not Found, please reselect");
		}
	}
	else
	{
		pxDialog->UpdateLabel("UNSET");
	}
}

//------------------------------------------------------------------------------
// ToolsAVP_Entity_GamePlayVolume :: SelectGPV
//------------------------------------------------------------------------------
void ToolsAVP_Node_Objective::SelectGPV(void)
{
	ToolsAVP_ChooseObject_ByType* pxChooseObject = new ToolsAVP_ChooseObject_ByType(TOT_Entity_GamePlayVolume, SetSelectedGPV);
	Tools_Object_System::ChooseObject("Select The Game Play Volume Object", pxChooseObject);
}

//------------------------------------------------------------------------------
// ToolsAVP_Entity_GamePlayVolume :: SelectGPV
//------------------------------------------------------------------------------
void ToolsAVP_Node_Objective::SetSelectedGPV(Asura_Guid uGuid)
{
	if (!s_pxSelectedObjective || uGuid == ASURA_GUID_UNREGISTERED)
		return;

	ToolsAVP_Node_Objective*		pxToolsObjective = s_pxSelectedObjective;
	AVP_ServerNode_Objective*	pxAVPEntity = (AVP_ServerNode_Objective*)pxToolsObjective->Entity;

	if (pxAVPEntity)
	{
		pxAVPEntity->SetGamePlayVolumeGuid(uGuid);
	}
}

//------------------------------------------------------------------------------
// ToolsAVP_Entity_GamePlayVolume :: ClearGPV
//------------------------------------------------------------------------------
void ToolsAVP_Node_Objective::ClearGPV(void)
{
	if (!s_pxSelectedObjective)
		return;

	ToolsAVP_Node_Objective*		pxToolsObjective = s_pxSelectedObjective;
	AVP_ServerNode_Objective*	pxAVPEntity = (AVP_ServerNode_Objective*)pxToolsObjective->Entity;

	if (pxAVPEntity)
	{
		pxAVPEntity->SetGamePlayVolumeGuid(ASURA_GUID_UNREGISTERED);
	}
}

//------------------------------------------------------------------------------
// ToolsAVP_Entity_GamePlayVolume :: EditVolume
//------------------------------------------------------------------------------
void ToolsAVP_Node_Objective::EditVolume(void)
{
	Asura_Assert(ThisEntity, "ToolsAVP_Node_Objective_Marine::EditVolume - Entity Doesn't exist for editing");

	ToolsAVP_Node_Objective* pxToolsEntity = s_pxSelectedObjective;

	//create controller for editing volumes if it hasn't been done yet
	if (!pxToolsEntity->GetVolumeController())
	{
		pxToolsEntity->m_pxVolumeController = new ToolsAVP_Objective_VolumeEdit_Controller(pxToolsEntity);
	}

	//and get it to create the volume objects
	pxToolsEntity->GetVolumeController()->StartVolumeEditing();

	s_bVolumesEdited = true;
}

//---------------------------------------------------
// ToolsAVP_MarineObjective_VolumeEdit_Controller
//---------------------------------------------------
ToolsAVP_Objective_VolumeEdit_Controller::ToolsAVP_Objective_VolumeEdit_Controller(ToolsAVP_Node_Objective* pxToolsEntity)
:PARENT(&pxToolsEntity->Changed)
{
	m_pxToolsEntity = pxToolsEntity;
	m_pxAVPEntity = (AVP_ServerNode_Objective*) pxToolsEntity->Entity;
}

void ToolsAVP_Objective_VolumeEdit_Controller::StartVolumeEditing()
{
	PARENT::StartVolumeEditing();

	if (GetNumberOfVolumes() == 0)
	{
		//create a volume if none exists yet
		CreateVolumeCuboid();
	}
}

void ToolsAVP_Objective_VolumeEdit_Controller::EndVolumeEditing()
{
	PARENT::EndVolumeEditing();

	//select the owner
	Tools_Object_System::SelectObject(m_pxToolsEntity);
}


void ToolsAVP_Objective_VolumeEdit_Controller::CreateVolumeCuboidMain()
{
	Asura_Volume_Cuboid* pxVolume = new Asura_Volume_Cuboid();
	pxVolume->SetPosition(m_pxToolsEntity->Position);
	m_pxAVPEntity->AddVolume(pxVolume);
	++m_pxAVPEntity->m_iNumVolumes;
}

void ToolsAVP_Objective_VolumeEdit_Controller::CreateVolumeSphereMain()
{
	Asura_Volume_Sphere* pxVolume = new Asura_Volume_Sphere();
	pxVolume->SetPosition(m_pxToolsEntity->Position);
	m_pxAVPEntity->AddVolume(pxVolume);
	++m_pxAVPEntity->m_iNumVolumes;
}

void ToolsAVP_Objective_VolumeEdit_Controller::CreateVolumeCylinderMain()
{
	Asura_Volume_Cylinder* pxVolume = new Asura_Volume_Cylinder();
	pxVolume->SetPosition(m_pxToolsEntity->Position);
	m_pxAVPEntity->AddVolume(pxVolume);
	++m_pxAVPEntity->m_iNumVolumes;
}

void ToolsAVP_Objective_VolumeEdit_Controller::DeleteVolumeMain(int iIndex)
{
	m_pxAVPEntity->RemoveVolume(static_cast<u_int>(iIndex));
	--m_pxAVPEntity->m_iNumVolumes;
}