#include "Mix/Private/Scene/Common/ActorNode.h"

#include "Mix/Private/Scene/Common/ActorRevision.h"
#include "Mix/Private/Scene/Common/ActorModel.h"
#include "Mix/Private/Scene/Common/ActorMesh.h"
#include "Mix/Private/Scene/Common/ActorConstraint.h"
#include "Mix/Private/Scene/Common/ActorDynamicsPart.h"
#include "Mix/Private/Scene/Common/ActorCollider.h"
#include "Mix/Private/Scene/Common/ActorSensor.h"

#ifdef _DEBUG
	#include "Mix/Graphics/Utility/IPerspectiveRenderer.h"
	#include "Mix/Private/Scene/Common/Debug.h"
#endif //_DEBUG

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* ActorNode::FAILED_ADD_CONSTRAINT = L"コンストレイントの追加に失敗";

ActorNode* ActorNode::CreateInstance( Mix::Scene::IActorModel* pOwner )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, ActorNode, pOwner );
}

ActorNode::ActorNode( Mix::Scene::IActorModel* pOwner ) :
m_pOwner( NULL ),
m_Name( L"" ),
m_pMesh( NULL ),
m_pDynamicsPart( NULL ),
m_pRevision( NULL ),
m_ParentIndex( -1 ),
m_UserIndex( 0 ),
m_pUserPtr( NULL )
{
	MIX_ASSERT( pOwner != NULL );
	m_pOwner = pOwner;
}

ActorNode::~ActorNode( void )
{
	MIX_ASSERT( m_pOwner == NULL );

	Dispose();
}

void ActorNode::SetName( const wchar_t* pName )
{
	m_Name = pName;
}

void ActorNode::SetGeometricMatrix( const Mix::Matrix4x4& mat )
{
	m_GeometricMat = mat;
	m_InvGeometricMat = m_GeometricMat.ToInverse();
}

const Mix::Matrix4x4& ActorNode::GetGeometricMatrix( void ) const
{
	return m_GeometricMat;
}

void ActorNode::SetDefLocalMatrix( const Mix::Matrix4x4& mat )
{
	m_DefLocalMat = m_LocalMat = mat;
}

const Mix::Matrix4x4& ActorNode::GetDefLocalMatrix( void ) const
{
	return m_DefLocalMat;
}

Float32* ActorNode::GetDefLocalMatrixPtrF( void )
{
	return &( m_DefLocalMat.m[0][0] );
}

Mix::Matrix4x4* ActorNode::GetLocalMatrixPtr( void )
{
	return &m_LocalMat;
}

const Mix::Matrix4x4* ActorNode::GetWorldMatrixPtr( void ) const
{
	return &m_WorldMat;
}

Mix::Scene::Common::ActorMesh* ActorNode::GetMeshPtr( void )
{
	return m_pMesh;
}

void ActorNode::SetMesh( Mix::Scene::Common::ActorMesh* pMesh )
{
	MIX_ASSERT( m_pMesh == NULL );

	MIX_ADD_REF( pMesh );
	m_pMesh = pMesh;

	if( m_pMesh != NULL )
	{
		m_pMesh->Link( &m_WorldMat );
	}
}

Mix::Scene::Common::ActorDynamicsPart* ActorNode::GetDynamicsPartPtr( void )
{
	return m_pDynamicsPart;
}

void ActorNode::SetDynamicsPart( Mix::Scene::Common::ActorDynamicsPart* pDynamicsPart )
{
	MIX_ASSERT( pDynamicsPart != NULL );
	MIX_ASSERT( m_pDynamicsPart == NULL );
	MIX_ASSERT( m_pOwner != NULL );

	Mix::Scene::Common::ActorModel* pInternalOwner = static_cast<Mix::Scene::Common::ActorModel*>( m_pOwner );

	MIX_ADD_REF( pDynamicsPart );
	m_pDynamicsPart = pDynamicsPart;

	m_pDynamicsPart->SetLink(	this,
								( m_pParent != NULL )? &( m_pParent->m_WorldMat ) : pInternalOwner->GetWorldMatrixPtr(),
								&m_WorldMat );
}

Mix::Scene::Common::ActorRevision* ActorNode::GetRevisionPtr( void ) const
{
	return m_pRevision;
}

void ActorNode::SetRevisionPtr( Mix::Scene::Common::ActorRevision* pRevision )
{
	MIX_ASSERT( pRevision != NULL );
	MIX_ASSERT( m_pRevision == NULL );

	m_pRevision = pRevision;
}

void ActorNode::SetParent( Int32 parentIndex, ActorNode* pParent )
{
	m_ParentIndex = parentIndex;
	m_pParent = pParent;

	if( m_pParent != NULL )
	{
		m_pParent->m_ChildPtrList.push_back( this );
	}
}

void ActorNode::ReserveChilds( UInt32 count )
{
	m_ChildPtrList.reserve( count );
}

UInt32 ActorNode::GetChildCount( void ) const
{
	return MIX_UIT_TO_UI32( m_ChildPtrList.size() );
}

ActorNode* ActorNode::GetChildPtr( UInt32 index ) const
{
	MIX_ASSERT( m_ChildPtrList.size() > index );

	return m_ChildPtrList[index];
}

ActorNode* const* ActorNode::GetChilds( void ) const
{
	MIX_ASSERT( m_ChildPtrList.size() > 0 );

	return &( m_ChildPtrList[0] );
}

void ActorNode::UpdateConstraint( void )
{
	if( m_ConstraintMap.size() > 0 )
	{
		ActorNode::ConstraintMap::iterator it_begin = m_ConstraintMap.begin();
		ActorNode::ConstraintMap::iterator it_end = m_ConstraintMap.end();
		ActorNode::ConstraintMap::iterator it;

		for( it = it_begin; it != it_end; ++it )
		{
			it->second->Update( m_WorldMat );
		}
	}
}

void ActorNode::Reset( const Mix::Matrix4x4& parentWorldMat )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 行列
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_ASSERT( m_pRevision != NULL );

	m_WorldMat = m_GeometricMat * m_LocalMat * parentWorldMat;

	m_pRevision->Clear();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// コンストレイント
	////////////////////////////////////////////////////////////////////////////////////////////////////

	UpdateConstraint();
}

void ActorNode::Refresh( const Mix::Matrix4x4& parentWorldMat )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 行列
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_ASSERT( m_pRevision != NULL );

	if( m_pRevision->IsControlWorldTransform() == True )
	{
		if( m_pRevision->IsWorldTransform() == True )
		{
			m_LocalMat = m_WorldMat * parentWorldMat.ToInverse();
			m_LocalMat = m_InvGeometricMat * m_LocalMat;
		}
	}
	else
	{
		m_WorldMat = m_GeometricMat * m_LocalMat * parentWorldMat;
	}

	m_pRevision->Clear();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// コンストレイント
	////////////////////////////////////////////////////////////////////////////////////////////////////

	UpdateConstraint();
}

const ActorNode::ConstraintMap& ActorNode::GetConstraintMap( void ) const
{
	return m_ConstraintMap;
}

void ActorNode::Dispose( void )
{
	m_ParentIndex = -1;
	m_pParent = NULL;

	m_ChildPtrList.clear();

	if( m_pDynamicsPart != NULL )
	{
		m_pDynamicsPart->Dispose();
	}

	if( m_pMesh != NULL )
	{
		m_pMesh->Dispose();
	}

	m_pRevision = NULL;

	MIX_RELEASE( m_pDynamicsPart );
	MIX_RELEASE( m_pMesh );

	m_pOwner = NULL;
}

#ifdef _DEBUG
	
void ActorNode::Debug_Draw(	UInt32 flags,
							Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer,
							Float32 axisScaling,
							Float32 jointFrameMinSize,
							Float32 jointLimitScaling )
{
	MIX_ASSERT( pPerspectiveRenderer != NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 軸
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( MIX_TESTBIT( flags, Mix::Scene::DDF_ACTORMODEL_AXIS ) == Mix::Scene::DDF_ACTORMODEL_AXIS )
	{
		pPerspectiveRenderer->SetMatrix( m_WorldMat );
		pPerspectiveRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
		pPerspectiveRenderer->AddAxis( axisScaling );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 骨格
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( MIX_TESTBIT( flags, Mix::Scene::DDF_ACTORMODEL_SKELETAL ) == Mix::Scene::DDF_ACTORMODEL_SKELETAL )
	{
		UIntT childCount = m_ChildPtrList.size();
		Mix::Vector3 worldPos = m_WorldMat.GetTranslation();

		pPerspectiveRenderer->SetMatrix( Mix::Matrix4x4::Identity() );
		pPerspectiveRenderer->SetColor( Mix::Scene::Common::Debug::GetDrawColor( Mix::Scene::DDC_ACTORMODEL_SKELETAL ) );

		for( UIntT i = 0; i < childCount; i++ )
		{
			Mix::Vector3 childWorldPos = m_ChildPtrList[i]->GetWorldMatrix().GetTranslation();
			pPerspectiveRenderer->AddLine( worldPos, childWorldPos );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクスパート
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pDynamicsPart != NULL )
	{
		m_pDynamicsPart->Debug_Draw( flags, pPerspectiveRenderer, axisScaling, jointFrameMinSize, jointLimitScaling );
	}
}

#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IActorNode
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean ActorNode::GetOwner( Mix::Scene::IActorModel** ppOwner )
{
	if( m_pOwner != NULL )
	{
		MIX_ADD_REF( m_pOwner );
		( *ppOwner ) = m_pOwner;
	}
	else
	{
		return False;
	}

	return True;
}

Mix::Scene::IActorModel* ActorNode::GetOwnerPtr( void ) const
{
	return m_pOwner;
}

Int32 ActorNode::GetParentIndex( void ) const
{
	return m_ParentIndex;
}

const wchar_t* ActorNode::GetName( void ) const
{
	return m_Name.GetConstPtr();
}

Boolean ActorNode::IsDraw( void ) const
{
	return ( m_pMesh != NULL )? m_pMesh->IsDraw() : False;
}

void ActorNode::SetDraw( Boolean state, UInt32 depth )
{
	if( m_pMesh != NULL )
	{
		m_pMesh->SetDraw( state );
	}

	if( depth > 0 )
	{
		ActorNode::ChildPtrList::iterator it_begin = m_ChildPtrList.begin();
		ActorNode::ChildPtrList::iterator it_end = m_ChildPtrList.end();
		ActorNode::ChildPtrList::iterator it;

		depth--;

		for( it = it_begin; it != it_end; ++it )
		{
			( *it )->SetDraw( state, depth );
		}
	}
}

void ActorNode::ResetLocalMatrix( void )
{
	m_LocalMat = m_DefLocalMat;
}

Boolean ActorNode::ExistsCollider( void ) const
{
	return ( ( m_pDynamicsPart != NULL ) && ( m_pDynamicsPart->GetColliderPtr() != NULL ) );
}

Boolean ActorNode::GetCollider( Mix::Scene::IActorCollider** ppCollider )
{
	MIX_ASSERT( ppCollider != NULL );

	if( m_pDynamicsPart == NULL )
	{
		return False;
	}

	Mix::Scene::Common::ActorCollider* pCollider = m_pDynamicsPart->GetColliderPtr();
	if( pCollider == NULL )
	{
		return False;
	}

	MIX_ADD_REF( pCollider );
	( *ppCollider ) = pCollider;

	return True;
}

UInt32 ActorNode::GetSensorCount( void ) const
{
	return ( m_pDynamicsPart != NULL )? m_pDynamicsPart->GetSensorCount() : 0;
}

Boolean ActorNode::GetSensor( UInt32 index, Mix::Scene::IActorSensor** ppSensor )
{
	MIX_ASSERT( ppSensor != NULL );

	if( m_pDynamicsPart == NULL )
	{
		return False;
	}

	Mix::Scene::Common::ActorSensor* pSensor = m_pDynamicsPart->GetSensorPtr( index );
	if( pSensor == NULL )
	{
		return False;
	}

	MIX_ADD_REF( pSensor );
	( *ppSensor ) = pSensor;

	return True;
}

Boolean ActorNode::GetConstraint( const wchar_t* pName, Mix::Scene::IActorConstraint** ppConstraint )
{
	if( ( pName == NULL ) ||
		( ::wcslen( pName ) == 0 ) ||
		( ppConstraint == NULL ) )
	{
		MIX_LOG_ERROR( L"%s : %s : pName[%s] ppConstraint[%s]",
			ActorNode::FAILED_ADD_CONSTRAINT,
			Mix::STR_ILLEGALARG,
			MIX_LOG_STR( pName ),
			MIX_LOG_PTR( ppConstraint ) );

		return False;
	}

	ActorNode::ConstraintMap::iterator it = m_ConstraintMap.find( pName );
	if( it != m_ConstraintMap.end() )
	{
		return False;
	}

	MIX_ADD_REF( it->second );
	( *ppConstraint ) = it->second;

	return True;
}

Boolean ActorNode::AddConstraint( const wchar_t* pName, Mix::Scene::IActorConstraint** ppConstraint )
{
	if( ( pName == NULL ) ||
		( ::wcslen( pName ) == 0 ) ||
		( ppConstraint == NULL ) )
	{
		MIX_LOG_ERROR( L"%s : %s : pName[%s] ppConstraint[%s]",
			ActorNode::FAILED_ADD_CONSTRAINT,
			Mix::STR_ILLEGALARG,
			MIX_LOG_STR( pName ),
			MIX_LOG_PTR( ppConstraint ) );

		return False;
	}

	ActorNode::ConstraintMap::iterator it = m_ConstraintMap.find( pName );
	if( it != m_ConstraintMap.end() )
	{
		MIX_LOG_ERROR( L"%s : 名前が重複しています : NodeName[%s] ConstraintName[%s]",
			ActorNode::FAILED_ADD_CONSTRAINT,
			m_Name.GetConstPtr(),
			pName );

		return False;
	}

	ActorConstraint* pConstraint = ActorConstraint::CreateInstance( pName );
	if( pConstraint != NULL )
	{
		m_ConstraintMap.insert( ActorNode::ConstraintMap::value_type( pName, pConstraint ) );
	}
	else
	{
		MIX_LOG_ERROR( L"%s : %s",
			ActorNode::FAILED_ADD_CONSTRAINT,
			Mix::STR_OUTOFMEMORY );

		return False;
	}

	( *ppConstraint ) = pConstraint;

	return True;
}

void ActorNode::RemoveConstraint( Mix::Scene::IActorConstraint* pConstraint )
{
	if( pConstraint == NULL )
	{
		return;
	}

	ActorNode::ConstraintMap::iterator it = m_ConstraintMap.find( pConstraint->GetName() );
	if( it != m_ConstraintMap.end() )
	{
		MIX_RELEASE( it->second );
		m_ConstraintMap.erase( it );
	}
}

Int32 ActorNode::GetUserIndex( void )  const
{
	return m_UserIndex;
}

void ActorNode::SetUserIndex( Int32 index )
{
	m_UserIndex = index;
}

void* ActorNode::GetUserPtr( void ) const
{
	return m_pUserPtr;
}

void ActorNode::SetUserPtr( void* pData )
{
	m_pUserPtr = pData;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::INode
////////////////////////////////////////////////////////////////////////////////////////////////////

const Mix::Matrix4x4& ActorNode::GetLocalMatrix( void ) const
{
	return m_LocalMat;
}

void ActorNode::SetLocalMatrix( const Mix::Matrix4x4& mat )
{
	m_LocalMat = mat;

	if( m_pRevision != NULL )
	{
		m_pRevision->SetLocalTransform();
//		m_pRevision->Set( ActorRevision::LOCAL_MAT );
	}
}

const Mix::Matrix4x4& ActorNode::GetWorldMatrix( void ) const
{
	return m_WorldMat;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IRendererObject
////////////////////////////////////////////////////////////////////////////////////////////////////

Mix::Scene::IRendererObject::TYPE ActorNode::GetType( void ) const
{
	return Mix::Scene::IRendererObject::ACTOR_NODE;
}

Boolean ActorNode::IsRendering( void ) const
{
	return RendererObject::IsRendering();
}

}}}
