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

#include "Mix/Dynamics/IManager.h"
#include "Mix/Dynamics/IWorld.h"
#include "Mix/Dynamics/IRigidBody.h"
#include "Mix/Dynamics/ISensor.h"

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

namespace Mix{ namespace Scene{ namespace Common{

////////////////////////////////////////////////////////////////////////////////////////////////////
// BasisGhost
////////////////////////////////////////////////////////////////////////////////////////////////////

const wchar_t* BasisGhost::FAILED_CREATE = L"儀僀僔僗僑乕僗僩偺嶌惉偵幐攕";

BasisGhost::~BasisGhost( void )
{
}

void BasisGhost::AttachDynamics( Mix::Dynamics::IWorld* pWorld, Mix::Dynamics::IObjectListener* pObjectListener )
{
	Mix::Scene::Common::DynamicsObject* pDynamicsObject = GetInternalDynamicsObjectPtr();
	MIX_ASSERT( pDynamicsObject != NULL );

	pDynamicsObject->Attach( pWorld, pObjectListener );
}

void BasisGhost::DetachDynamics( Mix::Dynamics::IWorld* pWorld )
{
	Mix::Scene::Common::DynamicsObject* pDynamicsObject = GetInternalDynamicsObjectPtr();
	MIX_ASSERT( pDynamicsObject != NULL );

	pDynamicsObject->Detach( pWorld );
}

Boolean BasisGhost::NeedsRefresh( void ) const
{
	return False;
}

void BasisGhost::Refresh( void )
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// CollideGhost
////////////////////////////////////////////////////////////////////////////////////////////////////

CollideGhost* CollideGhost::CreateInstance( void )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, CollideGhost );
}

CollideGhost::CollideGhost( void ) :
m_pCollider( NULL )
{
}

CollideGhost::~CollideGhost( void )
{
	if( m_pCollider != NULL )
	{
		m_pCollider->Dispose();
	}

	MIX_RELEASE( m_pCollider );
}

Boolean CollideGhost::Initialize( Mix::Dynamics::IShape* pShape, const wchar_t* pDebugName )
{
	MIX_ASSERT( pDebugName != NULL );
	MIX_ASSERT( m_pCollider == NULL );

	if( Mix::Dynamics::GetManagerPtr() == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : %s[%s] Type[Basis] Collide[仜]", Ghost::FAILED_ADD, Mix::Scene::STR_DISABLED_DYNAMICS, Mix::STR_DEBUGNAME, pDebugName );
		return False;
	}

	m_pCollider = Mix::Scene::Common::LibertyCollider::CreateInstance( this );
	if( m_pCollider != NULL )
	{
		if( m_pCollider->Initialize( pShape, pDebugName ) == False )
		{
			MIX_LOG_ERROR( L"%s : %s : Type[Basis] Name[%s] Collide[仜]", Ghost::FAILED_ADD, Mix::STR_INITERROR, pDebugName );
			return False;
		}
	}
	else
	{
		MIX_LOG_ERROR( L"%s : %s : Type[Basis] Name[%s] Collide[仜]", Ghost::FAILED_ADD, Mix::STR_OUTOFMEMORY, pDebugName );
		return False;
	}

	return True;
}

Mix::Scene::Common::DynamicsObject* CollideGhost::GetInternalDynamicsObjectPtr( void ) const
{
	return m_pCollider;
}

Mix::Dynamics::IObject* CollideGhost::GetInternalObjectPtr( void ) const
{
	MIX_ASSERT( m_pCollider != NULL );
	MIX_ASSERT( m_pCollider->GetInternalObjectPtr() != NULL );

	return m_pCollider->GetInternalObjectPtr();
}

Boolean CollideGhost::GetDynamicsObject( Mix::Scene::IDynamicsObject** ppDynamicsObject )
{
	if( ppDynamicsObject == NULL )
	{
		return False;
	}

	if( m_pCollider != NULL )
	{
		MIX_ADD_REF( m_pCollider );
		( *ppDynamicsObject ) = m_pCollider;
	}
	else
	{
		return False;
	}

	return True;
}

Mix::Quaternion CollideGhost::GetWorldRotation( void ) const
{
	MIX_ASSERT( m_pCollider != NULL );
	MIX_ASSERT( m_pCollider->GetInternalRigidBodyPtr() != NULL );

	return m_pCollider->GetInternalRigidBodyPtr()->GetWorldRotation();
}

void CollideGhost::SetWorldRotation( const Mix::Quaternion& rot )
{
	MIX_ASSERT( m_pCollider != NULL );
	MIX_ASSERT( m_pCollider->GetInternalRigidBodyPtr() != NULL );

	m_pCollider->GetInternalRigidBodyPtr()->SetWorldRotation( rot );
}

Mix::Vector3 CollideGhost::GetWorldPosition( void ) const
{
	MIX_ASSERT( m_pCollider != NULL );
	MIX_ASSERT( m_pCollider->GetInternalRigidBodyPtr() != NULL );

	return m_pCollider->GetInternalRigidBodyPtr()->GetWorldPosition();
}

void CollideGhost::SetWorldPosition( const Mix::Vector3& pos )
{
	m_pCollider->GetInternalRigidBodyPtr()->SetWorldPosition( pos );
}

Mix::Matrix4x4 CollideGhost::GetWorldMatrx( void ) const
{
	MIX_ASSERT( m_pCollider != NULL );
	MIX_ASSERT( m_pCollider->GetInternalRigidBodyPtr() != NULL );

	return m_pCollider->GetInternalRigidBodyPtr()->GetWorldMatrix();
}

void CollideGhost::SetWorldMatrix( const Mix::Matrix4x4& mat )
{
	MIX_ASSERT( m_pCollider != NULL );
	MIX_ASSERT( m_pCollider->GetInternalRigidBodyPtr() != NULL );

	Mix::Vector3 ws;
	Mix::Quaternion wr;
	Mix::Vector3 wt;

	mat.Decompose( ws, wr, wt );

	m_pCollider->GetInternalRigidBodyPtr()->SetWorldTransform( wr, wt );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// NoCollideGhost::InternalSensor
////////////////////////////////////////////////////////////////////////////////////////////////////

//僼傿儖僞乕
const UInt16 NoCollideGhost::InternalSensor::FILTER_GROUP	= Mix::Dynamics::OF_SENSOR;
const UInt16 NoCollideGhost::InternalSensor::FILTER_MASK	= Mix::Dynamics::OF_DEFAULT | Mix::Dynamics::OF_STATIC | Mix::Dynamics::OF_KINEMATIC;

NoCollideGhost::InternalSensor* NoCollideGhost::InternalSensor::CreateInstance( Mix::Scene::IRendererObject* pOwner, const wchar_t* pName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, NoCollideGhost::InternalSensor, pOwner, pName );
}

NoCollideGhost::InternalSensor::InternalSensor( Mix::Scene::IRendererObject* pOwner, const wchar_t* pName ) :
m_pOwner( NULL ),
m_Name( pName ),
m_pSensor( NULL )
{
	MIX_ASSERT( pOwner != NULL );
	m_pOwner = pOwner;
}

NoCollideGhost::InternalSensor::~InternalSensor( void )
{
	MIX_ASSERT( m_pOwner == NULL );
	MIX_RELEASE( m_pSensor );
}

Boolean NoCollideGhost::InternalSensor::Initialize( Mix::Dynamics::IShape* pShape )
{
	MIX_ASSERT( Mix::Dynamics::GetManagerPtr() != NULL );
	MIX_ASSERT( m_pSensor == NULL );

	if( Mix::Dynamics::GetManagerPtr()->CreateSensor( pShape, &m_pSensor, m_Name.GetConstPtr() ) == True )
	{
		m_pSensor->SetFilterGroup( InternalSensor::FILTER_GROUP );
		m_pSensor->SetFilterMask( InternalSensor::FILTER_MASK );

		DynamicsObject::Initialize( this );
	}
	else
	{
		return False;
	}

	return True;
}

void NoCollideGhost::InternalSensor::Dispose( void )
{
	m_pOwner = NULL;
}

Mix::Dynamics::IObject* NoCollideGhost::InternalSensor::GetInternalObjectPtr( void ) const
{
	return m_pSensor;
}

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

UInt16 NoCollideGhost::InternalSensor::GetFilterGroup( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetFilterGroup();
}

void NoCollideGhost::InternalSensor::SetFilterGroup( UInt16 filterGroup )
{
	MIX_ASSERT( m_pSensor != NULL );

	m_pSensor->SetFilterGroup( filterGroup );
}

UInt16 NoCollideGhost::InternalSensor::GetFilterMask( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetFilterMask();
}

void NoCollideGhost::InternalSensor::SetFilterMask( UInt16 filterMask )
{
	MIX_ASSERT( m_pSensor != NULL );

	m_pSensor->SetFilterMask( filterMask );
}

const Mix::Dynamics::MATERIAL& NoCollideGhost::InternalSensor::GetMaterial( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetMaterial();
}

void NoCollideGhost::InternalSensor::SetMaterial( const Mix::Dynamics::MATERIAL& material )
{
	MIX_ASSERT( m_pSensor != NULL );

	m_pSensor->SetMaterial( material );
}

Mix::Scene::IDynamicsObject::TYPE NoCollideGhost::InternalSensor::GetType( void ) const
{
	return Mix::Scene::IDynamicsObject::SIMPLE_SENSOR;
}

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

	return True;
}

Mix::Scene::IRendererObject* NoCollideGhost::InternalSensor::GetOwnerPtr( void ) const
{
	return m_pOwner;
}

Mix::Matrix4x4 NoCollideGhost::InternalSensor::GetWorldMatrix( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetWorldMatrix();
}

Mix::Quaternion NoCollideGhost::InternalSensor::GetWorldRotation( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetWorldRotation();
}

Mix::Vector3 NoCollideGhost::InternalSensor::GetWorldPosition( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetWorldPosition();
}

Boolean NoCollideGhost::InternalSensor::HasContactListener( void ) const
{
	return DynamicsObject::HasContactListener();
}

Boolean NoCollideGhost::InternalSensor::ContainsContactListener( Mix::Scene::IContactListener* pListener ) const
{
	return DynamicsObject::ContainsContactListener( pListener );
}

Boolean NoCollideGhost::InternalSensor::AddContactListener( Mix::Scene::IContactListener* pListener )
{
	return DynamicsObject::AddContactListener( pListener );
}

Boolean NoCollideGhost::InternalSensor::RemoveContactListener( Mix::Scene::IContactListener* pListener )
{
	return DynamicsObject::RemoveContactListener( pListener );
}

void NoCollideGhost::InternalSensor::ClearContactListener( void )
{
	DynamicsObject::ClearContactListener();
}

Int32 NoCollideGhost::InternalSensor::GetUserIndex( void )  const
{
	return DynamicsObject::GetUserIndex();
}

void NoCollideGhost::InternalSensor::SetUserIndex( Int32 index )
{
	DynamicsObject::SetUserIndex( index );
}

void* NoCollideGhost::InternalSensor::GetUserPtr( void ) const
{
	return DynamicsObject::GetUserPtr();
}

void NoCollideGhost::InternalSensor::SetUserPtr( void* ptr )
{
	DynamicsObject::SetUserPtr( ptr );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// NoCollideGhost
////////////////////////////////////////////////////////////////////////////////////////////////////

NoCollideGhost* NoCollideGhost::CreateInstance( void )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, NoCollideGhost );
}

NoCollideGhost::NoCollideGhost( void ) :
m_pSensor( NULL )
{
}

NoCollideGhost::~NoCollideGhost( void )
{
	if( m_pSensor != NULL )
	{
		m_pSensor->Dispose();
	}

	MIX_RELEASE( m_pSensor );
}

Boolean NoCollideGhost::Initialize( Mix::Dynamics::IShape* pShape, const wchar_t* pDebugName )
{
	MIX_ASSERT( pDebugName != NULL );
	MIX_ASSERT( m_pSensor == NULL );

	if( Mix::Dynamics::GetManagerPtr() == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : %s[%s] Type[Basis] Collide[亊]", Ghost::FAILED_ADD, Mix::Scene::STR_DISABLED_DYNAMICS, Mix::STR_DEBUGNAME, pDebugName );
		return False;
	}

	m_pSensor = NoCollideGhost::InternalSensor::CreateInstance( this, pDebugName );
	if( m_pSensor != NULL )
	{
		if( m_pSensor->Initialize( pShape ) == False )
		{
			MIX_LOG_ERROR( L"%s : %s : Type[Basis] Name[%s] Collide[亊]", Ghost::FAILED_ADD, Mix::STR_INITERROR, pDebugName );
			return False;
		}
	}
	else
	{
		MIX_LOG_ERROR( L"%s : %s : Type[Basis] Name[%s] Collide[亊]", Ghost::FAILED_ADD, Mix::STR_OUTOFMEMORY, pDebugName );
		return False;
	}

	return True;
}

Mix::Scene::Common::DynamicsObject* NoCollideGhost::GetInternalDynamicsObjectPtr( void ) const
{
	return m_pSensor;
}

Mix::Dynamics::IObject* NoCollideGhost::GetInternalObjectPtr( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );

	return m_pSensor->GetInternalObjectPtr();
}

Boolean NoCollideGhost::GetDynamicsObject( Mix::Scene::IDynamicsObject** ppDynamicsObject )
{
	if( ppDynamicsObject == NULL )
	{
		return False;
	}

	if( m_pSensor != NULL )
	{
		MIX_ADD_REF( m_pSensor );
		( *ppDynamicsObject ) = m_pSensor;
	}
	else
	{
		return False;
	}

	return True;
}

Mix::Quaternion NoCollideGhost::GetWorldRotation( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );
	MIX_ASSERT( m_pSensor->GetInternalObjectPtr() != NULL );

	return m_pSensor->GetInternalObjectPtr()->GetWorldRotation();
}

void NoCollideGhost::SetWorldRotation( const Mix::Quaternion& rot )
{
	MIX_ASSERT( m_pSensor != NULL );
	MIX_ASSERT( m_pSensor->GetInternalObjectPtr() != NULL );

	m_pSensor->GetInternalObjectPtr()->SetWorldRotation( rot );
}

Mix::Vector3 NoCollideGhost::GetWorldPosition( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );
	MIX_ASSERT( m_pSensor->GetInternalObjectPtr() != NULL );

	return m_pSensor->GetInternalObjectPtr()->GetWorldPosition();
}

void NoCollideGhost::SetWorldPosition( const Mix::Vector3& pos )
{
	m_pSensor->GetInternalObjectPtr()->SetWorldPosition( pos );
}

Mix::Matrix4x4 NoCollideGhost::GetWorldMatrx( void ) const
{
	MIX_ASSERT( m_pSensor != NULL );
	MIX_ASSERT( m_pSensor->GetInternalObjectPtr() != NULL );

	return m_pSensor->GetInternalObjectPtr()->GetWorldMatrix();
}

void NoCollideGhost::SetWorldMatrix( const Mix::Matrix4x4& mat )
{
	MIX_ASSERT( m_pSensor != NULL );
	MIX_ASSERT( m_pSensor->GetInternalObjectPtr() != NULL );

	Mix::Vector3 ws;
	Mix::Quaternion wr;
	Mix::Vector3 wt;

	mat.Decompose( ws, wr, wt );

	m_pSensor->GetInternalObjectPtr()->SetWorldTransform( wr, wt );
}

}}}
