//-----------------------------------------------------------------------------
// File			: ToolsAVP_Entity_LookAt.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/LookAt/ToolsAVP_Entity_LookAt.h"

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

// AVP
#include "Entity/Locations/LookAt/AVP_ServerEntity_LookAt.h"

// Tools
#include "Entity/Tools_SecondaryEntityFile_System.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_Entity_LookAt>			ToolsAVP_Entity_LookAt::s_xList;
ToolsAVP_Entity_LookAt*								ToolsAVP_Entity_LookAt::s_pxSelectedLookAtNode = NULL;

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

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: Constructor
//-----------------------------------------------------------------------------
ToolsAVP_Entity_LookAt::ToolsAVP_Entity_LookAt(Asura_Entity* pxEntity)
: PARENT(pxEntity)
, m_uLinkedLookAt(ASURA_GUID_UNREGISTERED)
, m_bChanged(false)
{
	Type = TOT_Entity_LookAt;
	SetMesh("ToolsShape_MarineLookAt");

	AVP_ServerEntity_LookAt* pxAVPEntity = static_cast< AVP_ServerEntity_LookAt* >( pxEntity );
	m_uLinkedLookAt	= pxAVPEntity->GetLinkedLookAt();

	s_xList.AddToList(this);
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: Deconstructor
//-----------------------------------------------------------------------------
ToolsAVP_Entity_LookAt::~ToolsAVP_Entity_LookAt(void)
{
	s_xList.RemoveFromList(this);
}

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

	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("LookAtNode", "LookAtNode", uGuid);

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

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

			ToolsAVP_Entity_LookAt* pxToolsObject = new ToolsAVP_Entity_LookAt(pxServerObject);

			// Create the game specific tools object and select it.
			if (pxToolsObject == NULL)
			{
				Asura_Assert(false, "ToolsAVP_Entity_LookAt::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(0xffffff, "Created New Look At Node");
				Tools_SaveAsura::SetEntityModified();
			}
		}
	}
}

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

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

	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("LookAtNode", "LookAtNode", uGuid);

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

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

			ToolsAVP_Entity_LookAt* pxToolsObject = new ToolsAVP_Entity_LookAt(pxServerObject);

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

	return NULL;
}

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

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

	Asura_Dialog* pxDialog;

	if (GetLinkedLookAt() == ASURA_GUID_UNREGISTERED)
	{
		pxDialog = new Asura_Function_Dialog("Create Linked LookAt", xOffset, AddLinkedPoint, &m_bChanged);
		pxDialog->SetHelpText("Creates A Linked LookAt Point");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();
	}
	else
	{
		pxDialog = new Asura_Function_Dialog("Delete Linked LookAt", xOffset, DeleteLinkedPoint, &m_bChanged);
		pxDialog->SetHelpText("Deletes A Linked LookAt Point");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: Copy
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::Copy(const Tools_Object* pxObject)
{
	PARENT::Copy(pxObject);
}

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

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: Destroy
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::Destroy(void)
{
	// Make sure we tell our linked node it's not linked any more, if we have one.
	ToolsAVP_Entity_LookAt* pxToolsLinkedLookAt = ToolsAVP_Entity_LookAt::FindEntity( GetLinkedLookAt() );
	if ( pxToolsLinkedLookAt )
	{
		pxToolsLinkedLookAt->SetLinkedLookAt( ASURA_GUID_UNREGISTERED );
		pxToolsLinkedLookAt->m_bChanged = true;
	}

	PARENT::Destroy();
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: OnSelection
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::OnSelection(void)
{
	s_pxSelectedLookAtNode = this;
	PARENT::OnSelection();
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: OnDeselection
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::OnDeselection(void)
{
	PARENT::OnDeselection();
	s_pxSelectedLookAtNode = NULL;
}

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

	if (GetLinkedLookAt() != ASURA_GUID_UNREGISTERED)
	{
		if (GetGuid() < GetLinkedLookAt())
		{
			ToolsAVP_Entity_LookAt* pxToolsLinkedLookAt = ToolsAVP_Entity_LookAt::FindEntity( GetLinkedLookAt() );
			if ( pxToolsLinkedLookAt )
			{
				// Make sure the node we're linked to knows it is linked.
				pxToolsLinkedLookAt->SetLinkedLookAt( GetGuid() );

				// As line drawing is rubbish at the moment draw a cylinder
				Asura_Vector_3 xDirection = pxToolsLinkedLookAt->Position - Position;
				xDirection.Normalise();
				Asura_Vector_3 xStart	= Position + (xDirection * 0.35f);
				Asura_Vector_3 xEnd		= pxToolsLinkedLookAt->Position + (-xDirection * 0.35f);
				Tools_Render::RenderCylinder(xStart, xEnd, 0.05f, 0xff00ff00, false);
			}
		}
	}
}

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

	if ( m_bChanged )
	{
		AVP_ServerEntity_LookAt* pxAVPEntity = GetGameLookAtNode();
		pxAVPEntity->SetLinkedLookAt( GetLinkedLookAt() );

		Tools_SaveAsura::SetEntityModified();
		m_bChanged = false;
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: UpdateWhileSelected
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::UpdateWhileSelected(void)
{
	PARENT::UpdateWhileSelected();
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: AddLinkedPoint
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::AddLinkedPoint(void)
{
	ToolsAVP_Entity_LookAt* pxThisLookAt = s_pxSelectedLookAtNode;
	if (pxThisLookAt)
	{
		if (pxThisLookAt->GetLinkedLookAt() == ASURA_GUID_UNREGISTERED)
		{
			Tools_SecondaryEntityFile_System::PreCreateObject();
			ToolsAVP_Entity_LookAt* pxNewLookAt = static_cast< ToolsAVP_Entity_LookAt* >( CreateAndReturn() );
			Tools_SecondaryEntityFile_System::PostCreateObject();
			if ( pxNewLookAt )
			{
				pxThisLookAt->SetLinkedLookAt( pxNewLookAt->GetGuid() );
				pxNewLookAt->SetLinkedLookAt( pxThisLookAt->GetGuid() );
				pxThisLookAt->m_bChanged = true;
				pxNewLookAt->m_bChanged = true;

				// Refresh the new tools object's overlay so it registers that it has been linked.
				pxNewLookAt->DeleteOverlay();
				pxNewLookAt->CreateOverlay();
				
				Tools_Timed_Message_System::AddMessage(Tools_Timed_Message_System::COLOUR_INFO, "New LookAt Linked");
				
				// Make sure the new look at point is selected
				s_pxSelectedLookAtNode = pxNewLookAt;
			}
			else
			{
				Asura_Assert(false, "ToolsAVP_Entity_LookAt::AddLinkedPoint - couldn't create new linked lookat point");
			}
		}
		else
		{
			// Already have one!
			Tools_Timed_Message_System::AddMessage(Tools_Timed_Message_System::COLOUR_ERROR, "This LookAt Already Has A Linked LookAt");
		}
	}
}

//-----------------------------------------------------------------------------
// ToolsAVP_Entity_LookAt :: DeleteLinkedPoint
//-----------------------------------------------------------------------------
void ToolsAVP_Entity_LookAt::DeleteLinkedPoint(void)
{
	ToolsAVP_Entity_LookAt* pxThisLookAt = s_pxSelectedLookAtNode;

	if (pxThisLookAt)
	{
		if (pxThisLookAt->GetLinkedLookAt() != ASURA_GUID_UNREGISTERED)
		{
			ToolsAVP_Entity_LookAt* pxLinkedLookAt = ToolsAVP_Entity_LookAt::FindEntity(pxThisLookAt->GetLinkedLookAt());

			// Destroy the linked point
			pxLinkedLookAt->Destroy();

			// Update this look at's guid to be unregistered.
			pxThisLookAt->SetLinkedLookAt(ASURA_GUID_UNREGISTERED);
			pxThisLookAt->m_bChanged = true;

			// Refresh The overlay
			pxThisLookAt->DeleteOverlay();
			pxThisLookAt->CreateOverlay();
		}
		else
		{
			// Don't have one!
			Tools_Timed_Message_System::AddMessage(Tools_Timed_Message_System::COLOUR_ERROR, "No Linked Look At Point To Destroy");
		}
	}
}

bool ToolsAVP_Entity_LookAt::IsBaseOrDerivativeOf( int iToolsObjectType ) const
{
	if ( iToolsObjectType == TOT_Entity_LookAt )
	{
		return true;
	}
	return PARENT::IsBaseOrDerivativeOf( iToolsObjectType );
}

AVP_ServerEntity_LookAt* ToolsAVP_Entity_LookAt::GetGameLookAtNode() const
{
	return static_cast< AVP_ServerEntity_LookAt* >( Entity );
}