//
// Tools_HierarchyNode_Object.cpp
//
// Created by KJFL - 15 October 2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

#include "Ragdoll/Tools_HierarchyNode_Object.h"

#include "Animation/Asura_Hierarchy.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Overlay.h"
#include "Physics/Asura_Physics_Ragdoll_Description.h"
#include "Rendering/Asura_Text_Output.h"

// Tools
#include "Misc/Tools_Render.h"
#include "Objects/Tools_Object_System.h"
#include "Ragdoll/Tools_RagdollCollision_Object.h"
#include "Ragdoll/Tools_Mode_RagdollEditor.h"

Asura_Vector_2 Tools_HierarchyNode_Object::s_xPropertiesOverlayPosition(30,10);
Tools_HierarchyNode_Object* Tools_HierarchyNode_Object::s_pxCurrentlyEditedObject=NULL;

static const float fNODE_RADIUS = 0.02f;

Tools_HierarchyNode_Object::Tools_HierarchyNode_Object( Asura_Hierarchy_Skin* pxSkin, int iBoneIndex, Asura_Physics_Ragdoll_Desc_HierarchyNode* pxHierarchyNode )
: Tools_Object(TOT_HierarchyNode)
, m_pxSkin( pxSkin )
, m_iBoneIndex( iBoneIndex ) 
, m_pxHierarchyNode( pxHierarchyNode )
{
	m_iParentBoneIndex = m_pxSkin->GetParentBoneIndex( iBoneIndex );
	m_uDefaultCollisionObject = m_pxHierarchyNode->GetCollisionObject();
	m_pxColDialog = 0;
	m_pxColDialog2 = 0;
}

const char* Tools_HierarchyNode_Object::GetName( void )
{
	return m_pxSkin->SectionData[m_iBoneIndex].SectionName.GetString();
}

void Tools_HierarchyNode_Object::UpdatePosition( const Asura_Vector_3& xPos, const Asura_Matrix_3x3& xMat )
{
	Position = xPos;
	Orientation = xMat;
}

void Tools_HierarchyNode_Object::Render()
{
	const Asura_Vector_3 xSizes( fNODE_RADIUS, fNODE_RADIUS, fNODE_RADIUS );

	// Render the node as a grey sphere if not selected
	u_int uNodeColour = 0xff3f3f3f;

	// Match what the Tools does for object selection - red for prime selection, blue for rest of a group selection
	if (RenderAsSelected())
	{
		uNodeColour = 0xffff0000;
	}
	else if (IsGroupSelected())
	{
		uNodeColour = 0xff0000ff;
	}

	Tools_Render::RenderSpheroid( Position, Orientation, xSizes, uNodeColour, true );

//	if ( Tools_Mode_Hierarchy::GetDrawJointAxes() )
	{
		//const float fJointAxesSize = 0.1f;
//		Asura_Render::RenderAxes( Position, Orientation, fJointAxesSize );
	}
}

void Tools_HierarchyNode_Object::PrintInfo(float& x,float& y)
{
	Tools_Object::PrintInfo(x,y);
	
	// show the bone's parent name too
	const int iParent = m_pxSkin->ParentBone[m_iBoneIndex];
	Asura_Text_Output::Print( x, y++, 0xffffffff, 0, "Parent : %s", (( iParent >= 0 ) ? m_pxSkin->SectionData[iParent].SectionName : "*None*") );

//	Asura_Text_Output::Print(x,y++,0xffffffff,0,"Pos: %f %f %f", Position.x, Position.y, Position.z );
//	const Asura_Quat xOri( Orientation );
//	Asura_Text_Output::Print(x,y++,0xffffffff,0,"Ori: %f %f %f %f", xOri.x, xOri.y, xOri.z, xOri.w );
}

bool Tools_HierarchyNode_Object::IsSelectable()
{
	return true;
}

void Tools_HierarchyNode_Object::OnSelection()
{
	s_pxCurrentlyEditedObject = this;
	CreatePropertiesOverlay();
}

void Tools_HierarchyNode_Object::OnDeselection()
{
	DeletePropertiesOverlay();
	s_pxCurrentlyEditedObject = NULL;
}

void Tools_HierarchyNode_Object::OnGroupDeselection()
{
	DeletePropertiesOverlay();
	s_pxCurrentlyEditedObject = NULL;
}

bool Tools_HierarchyNode_Object::ObjectIsInLOS(const Asura_Vector_3& xAlpha, const Asura_Vector_3& xBeta, float& fLowest)
{
	// Do LOS test against the sphere
	float fDist = fLowest;
	bool bInLOS = Asura_Maths::RayIntersectsSphere( xAlpha, xBeta, Position, fNODE_RADIUS, &fDist );
	if ( bInLOS )
	{
		fLowest = fDist;
	}												   

	return bInLOS;
}

bool Tools_HierarchyNode_Object::IsDraggable() const
{
	return false;
}


void Tools_HierarchyNode_Object::CreatePropertiesOverlay( void )
{
	Asura_Overlay* pxOverlay = new Asura_Overlay( GetName(), false, &s_xPropertiesOverlayPosition);
	pxOverlay->m_uID = TOOLS_OVERLAY_SELECTEDOBJECT;

	Asura_Dialog* pxDialog;
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);

	m_pxColDialog = new Asura_StringDisplay_Dialog( "", xOffset );
	pxOverlay->AddDialog( m_pxColDialog );
	xOffset.y+=Asura_Dialog::LargeSpacing() + Asura_Dialog::DefaultSpacing();

	m_pxColDialog2 = new Asura_StringDisplay_Dialog( "", xOffset );
	pxOverlay->AddDialog( m_pxColDialog2 );
	xOffset.y+=Asura_Dialog::LargeSpacing() + Asura_Dialog::DefaultSpacing();
	
	pxDialog = new Asura_Function_Dialog( "Clear Override Collision Object", xOffset, &Tools_HierarchyNode_Object::ClearCollisionObject );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog( "Set Override Collision Object", xOffset, &Tools_HierarchyNode_Object::ChooseCollisionObject );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y+=Asura_Dialog::DefaultSpacing();


	UpdateDialogLabels();

 	Asura_Overlay_System::SubmitNewOverlay(pxOverlay,false);
	
}

void Tools_HierarchyNode_Object::DeletePropertiesOverlay( void )
{
	m_pxColDialog = 0;
	m_pxColDialog2 = 0;
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_SELECTEDOBJECT);
}

void Tools_HierarchyNode_Object::UpdateDialogLabels( void )
{
	if ( s_pxCurrentlyEditedObject && m_pxColDialog )
	{
		Asura_String xName("Default Collision Object:\n");

		Asura_Assert( m_pxHierarchyNode, "No associated Hierarchy Node" );
		if (!m_pxHierarchyNode) return;

		xName += Tools_Mode_RagdollEditor::GetNameOfCollisionObject( m_uDefaultCollisionObject );
	
		m_pxColDialog->UpdateLabel( xName.GetString() );
	}
	if ( s_pxCurrentlyEditedObject && m_pxColDialog2 )
	{
		Asura_String xName("Override Collision Object:\n");

		Asura_Assert( m_pxHierarchyNode, "No associated Hierarchy Node" );
		if (!m_pxHierarchyNode) return;

		xName += Tools_Mode_RagdollEditor::GetNameOfCollisionObject( m_pxHierarchyNode->Tools_GetOverrideCollisionObject() );
	
		m_pxColDialog2->UpdateLabel( xName.GetString() );
	}
}

void Tools_HierarchyNode_Object::ChooseCollisionObject( void )
{
	Tools_NodeChooseCollisionObject* pxChooseObject = new Tools_NodeChooseCollisionObject( s_pxCurrentlyEditedObject );

	Tools_Object_System::ChooseObject( "Please choose a collision object to link this node to.", pxChooseObject );

}


void Tools_HierarchyNode_Object::ClearCollisionObject( void )
{
	if (s_pxCurrentlyEditedObject)
	{
		s_pxCurrentlyEditedObject->m_pxHierarchyNode->Tools_SetOverrideCollisionObject( Asura_Physics_Ragdoll_Description::uINVALID_INDEX );
	}
}

void Tools_HierarchyNode_Object::SetCollisionObject( u_int uCollisionObjectIndex )
{
	m_uDefaultCollisionObject = uCollisionObjectIndex;

	u_int uOverrideCollisionObject = m_pxHierarchyNode->Tools_GetOverrideCollisionObject();

	if (uOverrideCollisionObject!=Asura_Physics_Ragdoll_Description::uINVALID_INDEX)
	{
		uCollisionObjectIndex = uOverrideCollisionObject;
	}

	Asura_AMatrix3x3 xMatrix;
	Asura_AVector3 xPosition;

	const Tools_RagdollCollision_Object* pxColObj = 0;
	{
		Asura_List_It<Tools_RagdollCollision_Object> xIt( Tools_RagdollCollision_Object::GetList() );

		for ( ; !xIt.Done() ; xIt.Next() )
		{
			Tools_RagdollCollision_Object* pxToolsObject = xIt.GetCurrent();
			if ( pxToolsObject->GetCollisionObjectIndex() == uCollisionObjectIndex )
			{
				pxColObj = pxToolsObject;
			}
		}
	}

	if (!pxColObj) return;

	pxColObj->GetRagdollObjectOrientationAndPosition( xMatrix, xPosition );
	xMatrix.Transpose();

	// What we actually want to store is the orientation relative to our collision object
	Asura_AMatrix3x3 xNodeMatrix;
	xNodeMatrix.FromMat3( Orientation );

	xPosition = xNodeMatrix.ApplyTranspose( Asura_AVector3(Position) - xPosition ) ;
	xNodeMatrix = xNodeMatrix*xMatrix;
	
	m_pxHierarchyNode->Tools_Initialise( xNodeMatrix, xPosition, uCollisionObjectIndex );

	UpdateDialogLabels();
}

bool Tools_NodeChooseCollisionObject::CanBeSelected( Tools_Object* pxObject )
{
	if (!pxObject) return false;

	return ( pxObject->Type == TOT_RagdollCollision );
}

void Tools_NodeChooseCollisionObject::ObjectSelected( Tools_Object* pxObject )
{
	if (!pxObject) return;

	if ( pxObject->Type == TOT_RagdollCollision )
	{
		Tools_RagdollCollision_Object* pxCol = reinterpret_cast<Tools_RagdollCollision_Object*>(pxObject);
		
		u_int uIndex= pxCol->GetCollisionObjectIndex();
		m_pxNode->GetRagdollHierarchyNode()->Tools_SetOverrideCollisionObject( uIndex );
		m_pxNode->SetCollisionObject( uIndex );
	}
}


