
///////////////////////////////////////////////////////////////////////////////
//
// File   : Tools_Entity_Affector.cpp
// Author : Andy Tate
// Date   : 6-Dec-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "Entity/Tools_Entity_Affector.h"

// Asura independent header-files...
#include "Affectors/Asura_Affector.h"
#include "Camera/Asura_Camera.h"
#include "Core/Asura_LOS.h"
#include "Core/Asura_Maths.h"
#include "Entity/Affector/Asura_ServerEntity_Affector.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay.h"
#include "Network/Asura_Message.h"
#include "Rendering/Asura_Text_Output.h"

// Asura platform header-files...

// Tools header-files...
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/Tools_Object_System.h"


#if defined(ASURA_USE_AFFECTORS)

////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::Tools_Entity_Affector
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

Tools_Entity_Affector::Tools_Entity_Affector (Asura_Entity* pxEntity)
: PARENT(pxEntity)
{
	const Asura_ServerEntity_Affector*	pxAsuraEntity	= static_cast<Asura_ServerEntity_Affector*>(Entity);
	const Asura_Affector*				pxAffector		= pxAsuraEntity->GetAffector();

	Type	= TOT_Entity_Affector;

	// Initialise our local variables...
	m_fRange	= pxAffector->GetRange();
	m_fStrength	= pxAffector->GetStrength();
}

/// End of function 'Tools_Entity_Affector::Tools_Entity_Affector'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::AddOverlayControls
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

void Tools_Entity_Affector::AddOverlayControls (Asura_Overlay* pxOverlay,
												Asura_Vector_2& xOffset)
{
	Asura_Dialog*	pxDialog;

	// Add any parent controls...
	PARENT::AddOverlayControls(pxOverlay, xOffset);

	// Add our own controls...
	xOffset.y += Asura_Dialog::SmallSpacing();

	pxDialog = new Asura_Numerical_Dialog("Range", xOffset, &m_fRange, 0.100f, 100.0f, 1.000f, "%.3f", &Changed);
	pxDialog->SetHelpText("This is the range over which the affector works.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog("Strength", xOffset, &m_fStrength, -100.0f, 100.0f, 1.000f, "%.3f", &Changed);
	pxDialog->SetHelpText("This is the strength of the affector at it centre,\nthis scales of to 0 at the limit of the range.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();
}

/// End of function 'Tools_Entity_Affector::AddOverlayControls'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::UpdateWhileSelected
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

void Tools_Entity_Affector::UpdateWhileSelected (void)
{
	Asura_ServerEntity_Affector* pxAsuraEntity = Asura_ServerEntity_Affector::FindEntity(GetGuid());
	if (pxAsuraEntity)
	{
		Asura_Affector* pxAffector = pxAsuraEntity->GetAffector();
		if (pxAffector)
		{

			if(Changed)
			{
				// Initialise our local variables...
				pxAffector->SetRange(m_fRange);
				pxAffector->SetStrength(m_fStrength);
			}

			// Always update the position since we don't appear to be able to check for movement...
			pxAffector->SetPosition(Position);
		}
	}

	// Call the parent...
	PARENT::UpdateWhileSelected();
}

/// End of function 'Tools_Entity_Affector::UpdateWhileSelected'. ///

void Tools_Entity_Affector::SetEntityModified()
{
	PARENT::SetEntityModified();
	Asura_ServerEntity_Affector* pxAsuraEntity = Asura_ServerEntity_Affector::FindEntity(GetGuid());
	if (pxAsuraEntity)
	{
		Asura_Affector* pxAffector = pxAsuraEntity->GetAffector();
		if (pxAffector)
		{
			pxAffector->SetAsActive(pxAsuraEntity->IsEntityActive());
		}
	}
}


////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::HandlesThisMessage
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

bool Tools_Entity_Affector::HandlesThisMessage (int iMessageID)
{
	switch(iMessageID)
	{
		case ASURA_MSG_DESTRUCT:
		case ASURA_MSG_ACTIVATE:
		case ASURA_MSG_DEACTIVATE:
		{
			return(true);
		}

		default:
		{
			return(PARENT::HandlesThisMessage(iMessageID));
		}
	}		// End of switch.
}

/// End of function 'Tools_Entity_Affector::HandlesThisMessage'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::PrintInfo
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

void Tools_Entity_Affector::PrintInfo (float& fX, float& fY)
{
	PARENT::PrintInfo(fX, fY);

	// Print our data...
	Asura_Text_Output::Print(fX, fY++, 0xFFFFFFFF, 0, "Range : %.3f", m_fRange);
	Asura_Text_Output::Print(fX, fY++, 0xFFFFFFFF, 0, "Strength : %.3f", m_fStrength);
}

/// End of function 'Tools_Entity_Affector::PrintInfo'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::Copy
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

void Tools_Entity_Affector::Copy (const Tools_Object* pxObject)
{
	const Tools_Entity_Affector*		pxAffectorObject	= static_cast<const Tools_Entity_Affector*>(pxObject);
	const Asura_ServerEntity_Affector*	pxEntityToCopy		= static_cast<Asura_ServerEntity_Affector*>(pxAffectorObject->Entity);
	const Asura_Affector*				pxAffectorToCopy	= pxEntityToCopy->GetAffector();
	Asura_ServerEntity_Affector*		pxEntity			= static_cast<Asura_ServerEntity_Affector*>(Entity);
	Asura_Affector*						pxAffector			= pxEntity->GetAffector();

	PARENT::Copy(pxObject);

	// Copy our data...
	*pxAffector	= *pxAffectorToCopy;

	// Initialise our local variables...
	m_fRange	= pxAffector->GetRange();
	m_fStrength	= pxAffector->GetStrength();
}

/// End of function 'Tools_Entity_Affector::Copy'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::CreateObjectOfThisType
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

Tools_Object* Tools_Entity_Affector::CreateObjectOfThisType (void) const
{
	Create();
	return(Tools_Object_System::SelectedObject);
}

/// End of function 'Tools_Entity_Affector::CreateObjectOfThisType'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::Render
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

void Tools_Entity_Affector::Render (void)
{
	const Asura_Vector_3	xExtents(m_fRange, m_fRange, m_fRange);
	Tools_Object*			pxRootObject	= GetObjectToSelect();
	u_int					uColour;

	// Do we need to render the outline?
	if(pxRootObject->ShouldRenderSelectionOutline())
	{
		if(pxRootObject->RenderAsSelected())
		{
			uColour	= 0xFF00FF00;	// Green
		}
		else if(pxRootObject->IsGroupSelected())
		{
			uColour = 0xFF0000FF;	// Blue
		}
		else
		{
			uColour	= 0x4000FF00;	// Green
		}
	}
	else
	{
		uColour	= 0x4000FF00;	// Green
	}

	// Render as a sphere...
	Tools_Render::RenderSpheroid(Position, Orientation, xExtents, uColour, false);
}

/// End of function 'Tools_Entity_Affector::Render'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::ObjectIsInLOS
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

bool Tools_Entity_Affector::ObjectIsInLOS (const Asura_Vector_3& xOrigin,
										   const Asura_Vector_3& xDirection,
										   float& fLowest)
{
	float fDistance;
	if(Asura_Maths::RayIntersectsSphere(xOrigin, xDirection, Position, m_fRange, &fDistance, true) && (fDistance < fLowest))
	{
		const Asura_LOS_InputData	xLOSInputData(xOrigin, xDirection, ASURA_GUID_UNREGISTERED, fDistance);
		const Asura_LOS_OutputData*	pxLOSOutputData	= Asura_LOS::TestAgainstEnvironment(&xLOSInputData);

		// Ensure that we discount anything hidden behind the environment...
		if(!pxLOSOutputData->m_bHitEnvironment)
		{
			fLowest = fDistance;
			return true;
		}
	}
	return(false);
}

/// End of function 'Tools_Entity_Affector::ObjectIsInLOS'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Entity_Affector::Create
// Author       : Andy Tate
// Date         : 6-Dec-2006
////////////////////////////////////////////////////////////////////////////////

void Tools_Entity_Affector::Create (void)
{
	const Asura_Guid	uGuid		= Asura_Entity_System::GetCreatedByToolsGuid();
	Tools_Entity_Data*	pxToolsData	= CreateToolsDataWithDefaultName("Affector", "Affector", uGuid, GetNamePrefix());

	if(pxToolsData == NULL)
	{
		Asura_Assert(false, "Tools_Entity_Affector::Create() - no tools data" );
	}
	else
	{
		Asura_ServerEntity_Affector::Create(uGuid);

		Asura_ServerEntity_Affector*	pxServer	= Asura_ServerEntity_Affector::FindEntity(uGuid);

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

			Tools_Entity_Affector* pxToolsObject = new Tools_Entity_Affector(pxServer);

			if(pxToolsObject == NULL)
			{
				Asura_Assert(false, "Tools_Entity_Affector::Create() - no Tools object" );
			}
			else
			{
				Tools_Object_System::SelectObject(pxToolsObject);

				pxToolsObject->Position		= *Asura_Camera::GetPosition();
				pxToolsObject->Orientation	= *Asura_Camera::GetOrientation();

				Tools_Timed_Message_System::AddMessage(0xffffff, "Created new Affector");
				Tools_SaveAsura::SetEntityModified();
			}
		}
	}
}

/// End of function 'Tools_Entity_Affector::Create'. ///

#endif	// defined(ASURA_USE_AFFECTORS)


/// End of file. ///
