//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Entity_InteractObject.cpp
//
// Copyright (c) 2007 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////


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

// This file's header.
#include "Entity/PhysicalObject/Interact/ToolsAVP_Entity_InteractObject.h"

// Engine independent.
#include "Animation/Asura_AnimationBlend.h"
#include "Animation/Asura_AnimationController_Animation.h"
#include "Camera/Asura_Camera.h"
#include "Entity/Asura_Entity_Event.h"
#include "Entity/Asura_StaticMessage_System.h"
#include "Hierarchy/Tools_Animation_Files.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/Tools_Object_System.h"
#include "Shapes/Asura_Shape_System.h"

// Project independent.
#include "Entity/PhysicalObject/ToolsAVP_Entity_PhysicalObject.h"
#include "Entity/PhysicalObject/Interact/AVP_ServerEntity_InteractObject.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/AVP_Messages.h"
#include "Misc/Tools_Render.h"
#include "Objects/ToolsAVP_Object_Type.h"

// Tools
#include "Entity/Tools_MessageEditor.h"
#include "Shapes/Tools_Shapes.h"

static bool s_bStartsOnChanged = false;

// Class statics
ToolsAVP_Entity_InteractObject*						ToolsAVP_Entity_InteractObject::s_pxThis;
Asura_Hashed_List<ToolsAVP_Entity_InteractObject>	ToolsAVP_Entity_InteractObject::s_xList;

ToolsAVP_Entity_InteractObject::ToolsAVP_Entity_InteractObject( AVP_ServerEntity_InteractObject* pxInteractObject )
: PARENT( pxInteractObject )
, Tools_Entity_PhysicalObject( pxInteractObject )
, m_fAlphaTimer( 0.0f )
, m_pxActorVolumeController( NULL )
, m_pxOnTargetVolumeController( NULL )
, m_pxOffTargetVolumeController( NULL )
{
	m_xPreviousPositionForVolumes = Position;
	m_xPreviousOrientationForVolumes.FromMatrix(Orientation);

	m_pxInteractObject = pxInteractObject;

	Type = TOT_Entity_InteractiveObject;
	s_xList.AddToList(this);
}

ToolsAVP_Entity_InteractObject::~ToolsAVP_Entity_InteractObject()
{
	delete m_pxActorVolumeController;
	delete m_pxOnTargetVolumeController;
	delete m_pxOffTargetVolumeController;

	s_xList.RemoveFromList(this);
}

void ToolsAVP_Entity_InteractObject::Create()
{
	CreationHelper( "Interaction Object", "InteractObj", 
		AVP_ServerEntity_InteractObject::CreateFromTools, Create);
}

Tools_Object* ToolsAVP_Entity_InteractObject::Create( Asura_Entity* pxEntity )
{
	ToolsAVP_Entity_InteractObject* pxObject = new ToolsAVP_Entity_InteractObject( AVP_ServerEntity_InteractObject::FindEntity( pxEntity->GetGuid() ) );
	pxObject->UpdateToolsData();
	return pxObject;
}

void ToolsAVP_Entity_InteractObject::Copy( const Tools_Object* pxObject )
{
	PARENT::Copy( pxObject );

	ToolsAVP_Entity_InteractObject* pxFrom = ToolsAVP_Entity_InteractObject::FindEntity( pxObject->GetGuid() );
	if ( pxFrom )
	{
		m_xPreviousPositionForVolumes = pxFrom->Position;
		m_xPreviousOrientationForVolumes.FromMatrix(pxFrom->Orientation);

		m_pxPhysicalObject->SetBlueprintHashID( pxFrom->m_pxPhysicalObject->GetBlueprintHashID() );
		m_pxPhysicalObject->SetBlueprintTypeHashID( pxFrom->m_pxPhysicalObject->GetBlueprintTypeHashID() );
		m_pxPhysicalObject->InitFromBlueprint();

		if ( pxFrom->m_pxInteractObject->m_pxActorVolume )
		{
			delete m_pxInteractObject->m_pxActorVolume;
			m_pxInteractObject->m_pxActorVolume = new Asura_OrientedVolume( *pxFrom->m_pxInteractObject->m_pxActorVolume );
		}

		if ( pxFrom->m_pxInteractObject->m_pxOnTargetVolume )
		{
			delete m_pxInteractObject->m_pxOnTargetVolume;
			m_pxInteractObject->m_pxOnTargetVolume = new Asura_OBB( *pxFrom->m_pxInteractObject->m_pxOnTargetVolume );
		}
		
		if ( pxFrom->m_pxInteractObject->m_pxOffTargetVolume )
		{
			delete m_pxInteractObject->m_pxOffTargetVolume;
			m_pxInteractObject->m_pxOffTargetVolume = new Asura_OBB( *pxFrom->m_pxInteractObject->m_pxOffTargetVolume );
		}

		Asura_StaticMessage_System::DeleteMessageBlock( m_pxInteractObject->m_usTurnOnMessageBlock );
		m_pxInteractObject->m_usTurnOnMessageBlock = Asura_StaticMessage_System::CopyMessageBlock( pxFrom->m_pxInteractObject->m_usTurnOnMessageBlock, pxFrom->GetGuid(), GetGuid() );

		Asura_StaticMessage_System::DeleteMessageBlock( m_pxInteractObject->m_usTurnOffMessageBlock );
		m_pxInteractObject->m_usTurnOffMessageBlock = Asura_StaticMessage_System::CopyMessageBlock( pxFrom->m_pxInteractObject->m_usTurnOffMessageBlock, pxFrom->GetGuid(), GetGuid() );

		m_pxInteractObject->m_uFlags = pxFrom->m_pxInteractObject->m_uFlags;

		UpdateToolsData();
	}
}

Tools_Object* ToolsAVP_Entity_InteractObject::CreateObjectOfThisType() const
{
	const Asura_Guid uGuid = Asura_Entity_System::GetCreatedByToolsGuid();

	// Set up tools data and auto-create a unique name (prompt for new name if there is a clash).
	Tools_Entity_Data *pxToolsData = CreateToolsDataWithDefaultName("Interaction Object", "InteractObj", uGuid);

	if(pxToolsData == NULL)
	{
		Asura_Assert(false, "ToolsAVP_Entity_InteractObject::Create() - no tools data");
	}
	else
	{
		AVP_ServerEntity_InteractObject* pxServerObject = new AVP_ServerEntity_InteractObject(uGuid);
		pxServerObject->ToolsData = pxToolsData;
		ToolsAVP_Entity_InteractObject *pxToolsObject = new ToolsAVP_Entity_InteractObject(pxServerObject);
		Tools_Object_System::SelectObject(pxToolsObject);

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

		Tools_SaveAsura::SetEntityModified();
		return pxToolsObject;
	}
	return NULL;
}

void ToolsAVP_Entity_InteractObject::Destroy()
{
	Asura_StaticMessage_System::DeleteMessageBlock( m_pxInteractObject->m_usTurnOnMessageBlock );
	m_pxInteractObject->m_usTurnOnMessageBlock = ASURA_STATICMESSAGE_EMPTYBLOCK;

	Asura_StaticMessage_System::DeleteMessageBlock( m_pxInteractObject->m_usTurnOffMessageBlock );
	m_pxInteractObject->m_usTurnOffMessageBlock = ASURA_STATICMESSAGE_EMPTYBLOCK;

	PARENT::Destroy();
}

void ToolsAVP_Entity_InteractObject::UpdateAnimationWhileSelected()
{
	if ( s_bStartsOnChanged )
	{
		s_bStartsOnChanged = false;
		SetEntityModified();
		Asura_Blueprint* pxBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( m_pxInteractObject->GetBlueprintTypeHashID(), m_pxInteractObject->GetBlueprintHashID() );
		if ( pxBlueprint )
		{
			Asura_Value xValue;
			if ( pxBlueprint->GetParameterValueByHashID( m_pxInteractObject->m_bOn ? 0x6e416d75 : 0x59ec4099, xValue ) ) // Anim.Interaction.TurnOnf : Anim.Interaction.TurnOff
			{
				SetAnim( xValue.GetHashIDValue(), false );
			}
		}
	}
}

void ToolsAVP_Entity_InteractObject::UpdateWhileSelected()
{
	PARENT::UpdateWhileSelected();

	UpdateAnimationWhileSelected();

	if ( m_pxActorVolumeController )
	{
		m_pxActorVolumeController->ShowVolumes( m_pxActorVolumeController->IsSelected() );
	}

	if ( m_pxOnTargetVolumeController )
	{
		m_pxOnTargetVolumeController->ShowVolumes( m_pxOnTargetVolumeController->IsSelected() );
	}
	if ( m_pxOffTargetVolumeController )
	{
		m_pxOffTargetVolumeController->ShowVolumes( m_pxOffTargetVolumeController->IsSelected() );
	}
}

void ToolsAVP_Entity_InteractObject::UpdatePositionInAsuraData( bool bUpdateLinkedObjects )
{
	PARENT::UpdatePositionInAsuraData( bUpdateLinkedObjects );

	m_xPreviousOrientationForVolumes.Invert();
	Asura_Quat		xRotation		= Asura_Quat( Orientation ) * m_xPreviousOrientationForVolumes;

	if ( m_pxInteractObject->m_pxActorVolume )
	{
		Asura_Vector_3 xCentre = m_pxInteractObject->m_pxActorVolume->m_xBox.CalculateCentre();
		Asura_Vector_3 xOffset = xCentre - m_xPreviousPositionForVolumes;
		xOffset = xRotation.RotateVector( xOffset);
		m_pxInteractObject->m_pxActorVolume->m_xBox.Displace( Position + xOffset - xCentre );
		m_pxInteractObject->m_pxActorVolume->m_xOrient = xRotation * m_pxInteractObject->m_pxActorVolume->m_xOrient;
	}

	if ( m_pxInteractObject->m_pxOnTargetVolume )
	{
		const Asura_AVector3& xCentre = m_pxInteractObject->m_pxOnTargetVolume->GetCentre();
		Asura_AVector3 xOffset = xCentre - Asura_AVector3( m_xPreviousPositionForVolumes );
		xOffset = xRotation.RotateVector( xOffset);
		m_pxInteractObject->m_pxOnTargetVolume->SetCentre( Asura_AVector3( Position ) + xOffset );
		Asura_Quat xOri;
		xOri.FromMatrix( m_pxInteractObject->m_pxOnTargetVolume->GetOrientation() );
		xOri = xRotation * xOri;
		Asura_AMatrix3x3 xOriMat;
		xOri.ToMatrix( xOriMat );
		m_pxInteractObject->m_pxOnTargetVolume->SetOrientation( xOriMat );
	}

	if ( m_pxInteractObject->m_pxOffTargetVolume )
	{
		const Asura_AVector3& xCentre = m_pxInteractObject->m_pxOffTargetVolume->GetCentre();
		Asura_AVector3 xOffset = xCentre - Asura_AVector3( m_xPreviousPositionForVolumes );
		xOffset = xRotation.RotateVector( xOffset);
		m_pxInteractObject->m_pxOffTargetVolume->SetCentre( Asura_AVector3( Position ) + xOffset );
		Asura_Quat xOri;
		xOri.FromMatrix( m_pxInteractObject->m_pxOffTargetVolume->GetOrientation() );
		xOri = xRotation * xOri;
		Asura_AMatrix3x3 xOriMat;
		xOri.ToMatrix( xOriMat );
		m_pxInteractObject->m_pxOffTargetVolume->SetOrientation( xOriMat );
	}

	m_xPreviousPositionForVolumes = Position;
	m_xPreviousOrientationForVolumes = Asura_Quat( Orientation );
}

void ToolsAVP_Entity_InteractObject::AddActionsControls( Asura_Overlay* pxOverlay, Asura_Vector_2& xOffset )
{
	Asura_Char szBuffer[32];
	Asura_PrintfToBfr( szBuffer,"On turn on (%d)", 32, true, Asura_StaticMessage_System::GetNumberOfMessagesInBlock( m_pxInteractObject->m_usTurnOnMessageBlock ) );
	Asura_Dialog* pxDialog = new Asura_Function_Dialog( szBuffer, xOffset, EditOnTurnOnMessages );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	Asura_PrintfToBfr( szBuffer,"On turn off (%d)", 32, true, Asura_StaticMessage_System::GetNumberOfMessagesInBlock( m_pxInteractObject->m_usTurnOffMessageBlock ) );
	pxDialog = new Asura_Function_Dialog( szBuffer, xOffset, EditOnTurnOffMessages );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Starts On", xOffset, &m_pxInteractObject->m_uFlags, 0x00000010, &s_bStartsOnChanged );
	pxDialog->SetHelpText( "This trigger will start in the 'On' state." );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::LargeSpacing();
}

void ToolsAVP_Entity_InteractObject::AddOverlayControls( Asura_Overlay* pxOverlay, Asura_Vector_2& xOffset )
{
	PARENT::AddOverlayControls( pxOverlay, xOffset );
	xOffset.y += Asura_Dialog::DefaultSpacing();
	
	AddActionsControls( pxOverlay, xOffset );

	Asura_Dialog* pxDialog = new Asura_FlagTickbox_Dialog( "Starts Enabled", xOffset, &m_pxInteractObject->m_uFlags, 0x00000100, &Changed );
	pxDialog->SetHelpText( "This trigger will start enabled allowing it to be used by actors." );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Trigger once", xOffset, &m_pxInteractObject->m_uFlags, 0x00000001, &Changed );
	pxDialog->SetHelpText( "This trigger will disable itself once it gets used.\nTherefore it will only be useable once, unless it is re-enabled." );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::LargeSpacing();

	// actor volume
	pxDialog = new Asura_FlagTickbox_Dialog( "Use actor volume", xOffset, &m_pxInteractObject->m_uFlags, 0x00000002, &Changed );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog( "Edit actor volume", xOffset, EditActorVolume, &Changed );
	pxDialog->SetHelpText( "Edits the volume the actor must be within to activate the trigger." );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	// target volume
	pxDialog = new Asura_FlagTickbox_Dialog( "Use 'Off' target volume", xOffset, &m_pxInteractObject->m_uFlags, 0x00000008, &Changed );
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog( "Edit 'Off' target volume", xOffset, EditOffTargetVolume, &Changed );
	pxDialog->SetHelpText( "Edits the volume the actor must be looking at to activate the trigger while it is in the 'Off' state." );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Use 'On' target volume", xOffset, &m_pxInteractObject->m_uFlags, 0x00000004, &Changed );
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog( "Edit 'On' target volume", xOffset, EditOnTargetVolume, &Changed );
	pxDialog->SetHelpText( "Edits the volume the actor must be looking at to activate the trigger while it is in the 'On' state." );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	// entity type flags
	pxDialog = new Asura_FlagTickbox_Dialog( "Use by Aliens", xOffset, &m_pxInteractObject->m_uFlags, 0x00000020, &Changed );
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Use by Humans", xOffset, &m_pxInteractObject->m_uFlags, 0x00000040, &Changed );
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_FlagTickbox_Dialog( "Use by Predators", xOffset, &m_pxInteractObject->m_uFlags, 0x00000080, &Changed );
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();
}

void ToolsAVP_Entity_InteractObject::OnSelection()
{
	s_pxThis = this;
	PARENT::OnSelection();
}

void ToolsAVP_Entity_InteractObject::OnDeselection()
{
	PARENT::OnDeselection();
	s_pxThis = NULL;
}

bool ToolsAVP_Entity_InteractObject::HandlesThisMessage( int iMessageID )
{
	if ( iMessageID == ASURA_MSG_SWITCHON || iMessageID == ASURA_MSG_SWITCHOFF || iMessageID == AVP_MSGID_INTERACTION_OBJECT_ENABLE || iMessageID == AVP_MSGID_INTERACTION_OBJECT_DISABLE || iMessageID == AVP_MSGID_TRIGGER_INTERACTION_ON_LOCAL_PLAYER || iMessageID == AVP_MSGID_INTERACTION_OBJECT_INITIALISE_TO_ON || iMessageID == AVP_MSGID_INTERACTION_OBJECT_INITIALISE_TO_OFF	)
	{
		return true;
	}
	else
	{
		return PARENT::HandlesThisMessage( iMessageID );
	}
}

bool ToolsAVP_Entity_InteractObject::OwnsThisMessageBlock( unsigned short usMessageBlockID )
{
	if ( m_pxInteractObject && ( m_pxInteractObject->m_usTurnOnMessageBlock == usMessageBlockID || m_pxInteractObject->m_usTurnOffMessageBlock == usMessageBlockID ) )
	{
		return true;
	}
	// else
	return PARENT::OwnsThisMessageBlock( usMessageBlockID );
}

bool ToolsAVP_Entity_InteractObject::GetEventDescForMessageBlock( unsigned short usMessageBlockID, Asura_String& xOutputDesc )
{
	if ( m_pxInteractObject ) 
	{
		if ( m_pxInteractObject->m_usTurnOnMessageBlock == usMessageBlockID )
		{
			xOutputDesc = "On Turn On";
			return true;
		}
		else if ( m_pxInteractObject->m_usTurnOnMessageBlock == usMessageBlockID )
		{
			xOutputDesc = "On Turn Off";
			return true;
		}
	}
	// else
	return PARENT::GetEventDescForMessageBlock( usMessageBlockID, xOutputDesc );
}

void ToolsAVP_Entity_InteractObject::EditOnTurnOnMessages()
{
	Asura_Assert( s_pxThis, "" );
	Asura_Assert( s_pxThis->m_pxInteractObject, "" );

	#ifdef ASURA_TOOLS_USE_NEW_MESSAGE_EDITOR
	Tools_MessageEditor::StartMessageEditingMode(&s_pxThis->m_pxInteractObject->m_usTurnOnMessageBlock);
	#else
	Tools_Object_System::EditMessageBlock( "On Turn On", &s_pxThis->m_pxInteractObject->m_usTurnOnMessageBlock );
	#endif
}

void ToolsAVP_Entity_InteractObject::EditOnTurnOffMessages()
{
	Asura_Assert( s_pxThis, "" );
	Asura_Assert( s_pxThis->m_pxInteractObject, "" );

	#ifdef ASURA_TOOLS_USE_NEW_MESSAGE_EDITOR
	Tools_MessageEditor::StartMessageEditingMode(&s_pxThis->m_pxInteractObject->m_usTurnOffMessageBlock);
	#else
	Tools_Object_System::EditMessageBlock( "On Turn Off", &s_pxThis->m_pxInteractObject->m_usTurnOffMessageBlock );
	#endif
}

void ToolsAVP_Entity_InteractObject::UpdateToolsData()
{
	PARENT::UpdateToolsData();

	Asura_Assert( m_pxInteractObject, "" );
	if ( m_pxInteractObject->GetSkinID() != ASURA_HASH_ID_UNSET )
	{
		SetToolsSkinAndAnim( m_pxInteractObject->GetSkinFileID(), m_pxInteractObject->GetSkinID(), m_pxInteractObject->GetAnimID(), m_pxInteractObject->GetAnimFileID() );
		if ( GetAnimation() && m_pxInteractObject->GetAnimID() != ASURA_HASH_ID_UNSET )
		{
			Asura_AnimationBlend* pxBlend = new Asura_AnimationBlend_AnimatedTween( 0.0f, false );
			Asura_AnimationController_Animation* pxAACA = GetAnimation()->CreateControllerAnimation( AAC_FLAG_ACTIVE | AAC_FLAG_ALLOW_DESTROY_FROM_MESSAGE, 0, m_pxInteractObject->GetAnimID(), pxBlend );
			if ( pxAACA )
			{
				pxAACA->Play();
				pxAACA->SetParametricTimer( 1.0f );
			}
			else
			{
				delete pxBlend;
			}
		}
	}
}

void ToolsAVP_Entity_InteractObject::EditActorVolume()
{
	if ( s_pxThis->m_pxActorVolumeController  == NULL )
	{
		s_pxThis->m_pxActorVolumeController = new ToolsAVP_Entity_InteractObject_ActorVolumeEdit_Controller( s_pxThis );
	}
	s_pxThis->m_pxActorVolumeController->StartVolumeEditing();
}

void ToolsAVP_Entity_InteractObject::EditOnTargetVolume()
{
	if ( s_pxThis->m_pxOnTargetVolumeController == NULL )
	{
		s_pxThis->m_pxOnTargetVolumeController =  new ToolsAVP_Entity_InteractObject_OnTargetVolumeEdit_Controller( s_pxThis );
	}
	s_pxThis->m_pxOnTargetVolumeController->StartVolumeEditing();
}

void ToolsAVP_Entity_InteractObject::EditOffTargetVolume()
{
	if ( s_pxThis->m_pxOffTargetVolumeController == NULL )
	{
		s_pxThis->m_pxOffTargetVolumeController =  new ToolsAVP_Entity_InteractObject_OffTargetVolumeEdit_Controller( s_pxThis );
	}
	s_pxThis->m_pxOffTargetVolumeController->StartVolumeEditing();
}

ToolsAVP_Entity_InteractObject_ActorVolumeEdit_Controller::ToolsAVP_Entity_InteractObject_ActorVolumeEdit_Controller( ToolsAVP_Entity_InteractObject* pxToolsEntity )
: PARENT( &pxToolsEntity->Changed )
, m_pxToolsEntity( pxToolsEntity )
{
	m_xOV.m_xBox.SetToPoint( m_pxToolsEntity->Position + Asura_Vector_3( 0.0f, -1.0f, 0.0f ) );
	m_xOV.m_xBox.Grow( 1.0f );
	m_xOV.m_xOrient.Identity();
}

void ToolsAVP_Entity_InteractObject_ActorVolumeEdit_Controller::StartVolumeEditing()
{
	m_pxToolsEntity->m_pxInteractObject->m_bUseActorVolume = true;
	if ( m_pxToolsEntity->m_pxInteractObject->m_pxActorVolume == NULL )
	{
		m_pxToolsEntity->m_pxInteractObject->m_pxActorVolume = new Asura_OrientedVolume;
	}
	else
	{
		m_xOV = *m_pxToolsEntity->m_pxInteractObject->m_pxActorVolume;
	}
	PARENT::StartVolumeEditing();
}

void ToolsAVP_Entity_InteractObject_ActorVolumeEdit_Controller::EndVolumeEditing()
{
	PARENT::EndVolumeEditing();
	*m_pxToolsEntity->m_pxInteractObject->m_pxActorVolume = m_xOV;
	Tools_Object_System::SelectObject( m_pxToolsEntity );
}

ToolsAVP_Entity_InteractObject_OnTargetVolumeEdit_Controller::ToolsAVP_Entity_InteractObject_OnTargetVolumeEdit_Controller( ToolsAVP_Entity_InteractObject* pxToolsEntity )
: PARENT( &pxToolsEntity->Changed )
, m_pxToolsEntity( pxToolsEntity )
{
	m_xOV.m_xBox.SetToPoint( m_pxToolsEntity->Position + Asura_Vector_3( 0.0f, -1.0f, 0.0f ) );
	m_xOV.m_xBox.Grow( 1.0f );
	m_xOV.m_xOrient.Identity();
}

void ToolsAVP_Entity_InteractObject_OnTargetVolumeEdit_Controller::StartVolumeEditing()
{
	m_pxToolsEntity->m_pxInteractObject->m_bUseOnTargetVolume = true;
	if ( m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume == NULL )
	{
		m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume = new Asura_OBB;
	}
	else
	{
		const Asura_AVector3& xHalfExtents = m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume->GetHalfExtents();
		const Asura_AVector3& xPoint = m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume->GetCentre();
		m_xOV.m_xBox.Reset();
		m_xOV.m_xBox.Set( Asura_Vector_3( xPoint + xHalfExtents ) );
		m_xOV.m_xBox.Set( Asura_Vector_3( xPoint - xHalfExtents ) );
		m_xOV.m_xOrient.FromMatrix( m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume->GetOrientation() );
	}
	PARENT::StartVolumeEditing();
}

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

	m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume->SetCentre( Asura_AVector3( m_xOV.m_xBox.CalculateCentre() ) );
	m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume->SetHalfExtents( Asura_AVector3( m_xOV.m_xBox.CalculateExtents() * 0.5f ) );
	Asura_AMatrix3x3 xOri;
	m_xOV.m_xOrient.ToMatrix( xOri );
	m_pxToolsEntity->m_pxInteractObject->m_pxOnTargetVolume->SetOrientation( xOri );
	Tools_Object_System::SelectObject( m_pxToolsEntity );
}

ToolsAVP_Entity_InteractObject_OffTargetVolumeEdit_Controller::ToolsAVP_Entity_InteractObject_OffTargetVolumeEdit_Controller( ToolsAVP_Entity_InteractObject* pxToolsEntity )
: PARENT( &pxToolsEntity->Changed )
, m_pxToolsEntity( pxToolsEntity )
{
	m_xOV.m_xBox.SetToPoint( m_pxToolsEntity->Position + Asura_Vector_3( 0.0f, -1.0f, 0.0f ) );
	m_xOV.m_xBox.Grow( 1.0f );
	m_xOV.m_xOrient.Identity();
}

void ToolsAVP_Entity_InteractObject_OffTargetVolumeEdit_Controller::StartVolumeEditing()
{
	m_pxToolsEntity->m_pxInteractObject->m_bUseOffTargetVolume = true;
	if ( m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume == NULL )
	{
		m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume = new Asura_OBB;
	}
	else
	{
		const Asura_AVector3& xHalfExtents = m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume->GetHalfExtents();
		const Asura_AVector3& xPoint = m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume->GetCentre();
		m_xOV.m_xBox.Reset();
		m_xOV.m_xBox.Set( Asura_Vector_3( xPoint + xHalfExtents ) );
		m_xOV.m_xBox.Set( Asura_Vector_3( xPoint - xHalfExtents ) );
		m_xOV.m_xOrient.FromMatrix( m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume->GetOrientation() );
	}
	PARENT::StartVolumeEditing();
}

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

	m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume->SetCentre( Asura_AVector3( m_xOV.m_xBox.CalculateCentre() ) );
	m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume->SetHalfExtents( Asura_AVector3( m_xOV.m_xBox.CalculateExtents() * 0.5f ) );
	Asura_AMatrix3x3 xOri;
	m_xOV.m_xOrient.ToMatrix( xOri );
	m_pxToolsEntity->m_pxInteractObject->m_pxOffTargetVolume->SetOrientation( xOri );
	Tools_Object_System::SelectObject( m_pxToolsEntity );
}
