#include "Mix/Tool/Win32/Core/Dynamics/Impl/StaticPlane.h"
#include "Mix/Tool/Win32/Core/Dynamics/Impl/World.h"

#include "btBulletCollisionCommon.h"
#include "btBulletDynamicsCommon.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{ namespace Impl{

StaticPlane::StaticPlane( void ) :
m_pWorld( NULL ),
m_pShape( NULL ),
m_pMotionState( NULL ),
m_pRigidBody( NULL ),
m_Group( FG_STATIC ),
m_GroupMask( FG_ALL )
{
}

StaticPlane::~StaticPlane( void )
{
	MIX_DELETE( m_pRigidBody );
	MIX_DELETE( m_pMotionState );
	MIX_DELETE( m_pShape );
}

bool StaticPlane::Initialize( void )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションステートの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pMotionState = new btDefaultMotionState();
	if( m_pMotionState == NULL )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// シェイプの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pShape = new btStaticPlaneShape( btVector3( 0.0f, 1.0f, 0.0f ), 0.0f );
	if( m_pShape != NULL )
	{
		m_pShape->setUserPointer( &m_Material );
	}
	else
	{
		MIX_DELETE( m_pMotionState );
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// リジッドボディの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pRigidBody = new btRigidBody( 0.0f, m_pMotionState, m_pShape );
	if( m_pRigidBody != NULL )
	{
		m_pRigidBody->setFriction( m_Material.friction );
		m_pRigidBody->setRestitution( m_Material.restitution );
		m_pRigidBody->setUserPointer( this );
	}
	else
	{
		MIX_DELETE( m_pMotionState );
		MIX_DELETE( m_pShape );
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return true;
}

void StaticPlane::SetWorldPtr( Mix::Tool::Win32::Dynamics::Impl::World* pWorld )
{
	m_pWorld = pWorld;
}

btRigidBody* StaticPlane::Bullet_GetRigidBodyPtr( void )
{
	return m_pRigidBody;
}

const Mix::Tool::Win32::Dynamics::MATERIAL& StaticPlane::GetMaterial( void ) const
{
	return m_Material;
}

void StaticPlane::SetMaterial( const Mix::Tool::Win32::Dynamics::MATERIAL& material )
{
	m_Material = material;

	m_pRigidBody->setFriction( m_Material.friction );
	m_pRigidBody->setRestitution( m_Material.restitution );
}

short StaticPlane::GetGroup( void ) const
{
	return m_Group;
}

void StaticPlane::SetGroup( short data )
{
	BeginRefresh();
	m_Group = data;
	EndRefresh();
}

short StaticPlane::GetGroupMask( void ) const
{
	return m_GroupMask;
}

void StaticPlane::SetGroupMask( short data )
{
	BeginRefresh();
	m_GroupMask = data;
	EndRefresh();
}

D3DXQUATERNION StaticPlane::GetWorldRotation( void ) const
{
	D3DXQUATERNION ret;

	if( m_pRigidBody != NULL )
	{
		btQuaternion rot = m_pRigidBody->getWorldTransform().getRotation();

		ret.x = rot.x();
		ret.y = rot.y();
		ret.z = rot.z();
		ret.w = rot.w();
	}
	else
	{
		D3DXQuaternionIdentity( &ret );
	}

	return ret;
}

void StaticPlane::SetWorldRotation( const D3DXQUATERNION& rot )
{
	if( m_pRigidBody != NULL )
	{
		btTransform worldTransform = m_pRigidBody->getWorldTransform();

		worldTransform.setRotation( btQuaternion( rot.x, rot.y, rot.z, rot.w ) );

		m_pRigidBody->setWorldTransform( worldTransform );
	}
}

D3DXVECTOR3 StaticPlane::GetWorldPosition( void ) const
{
	D3DXVECTOR3 ret;

	if( m_pRigidBody != NULL )
	{
		const btVector3& pos = m_pRigidBody->getWorldTransform().getOrigin();

		ret.x = pos.x();
		ret.y = pos.y();
		ret.z = pos.z();
	}
	else
	{
		ret.x = 0.0f;
		ret.y = 0.0f;
		ret.z = 0.0f;
	}

	return ret;
}

void StaticPlane::SetWorldPosition( const D3DXVECTOR3& pos )
{
	if( m_pRigidBody != NULL )
	{
		btTransform worldTransform = m_pRigidBody->getWorldTransform();

		worldTransform.setOrigin( btVector3( pos.x, pos.y, pos.z ) );

		m_pRigidBody->setWorldTransform( worldTransform );
	}
}

D3DXMATRIX StaticPlane::GetWorldMatrix( void ) const
{
	D3DXQUATERNION rot = GetWorldRotation();
	D3DXVECTOR3 pos = GetWorldPosition();
	D3DXMATRIX mat;

	D3DXMatrixRotationQuaternion( &mat, &rot );
	
	mat._41 = pos.x;
	mat._42 = pos.y;
	mat._43 = pos.z;
	mat._44 = 1.0f;

	return mat;
}

void StaticPlane::SetWorldMatrix( const D3DXMATRIX& mat )
{
	D3DXQUATERNION rot;
	D3DXVECTOR3 pos;

	Mix::Tool::Win32::Matrix_Decompose( mat, NULL, &rot, &pos );

	SetWorldTransform( rot, pos );
}

void StaticPlane::SetWorldTransform( const D3DXQUATERNION& rot, const D3DXVECTOR3& pos )
{
	if( m_pRigidBody != NULL )
	{
		btTransform worldTransform = m_pRigidBody->getWorldTransform();

		worldTransform.setRotation( btQuaternion( rot.x, rot.y, rot.z, rot.w ) );
		worldTransform.setOrigin( btVector3( pos.x, pos.y, pos.z ) );

		m_pRigidBody->setWorldTransform( worldTransform );
	}
}

bool StaticPlane::IsInWorld( void ) const
{
	return ( m_pWorld != NULL );
}

void StaticPlane::Draw( Mix::Tool::Win32::Graphics::LineHelper* pLineHelper, const D3DXVECTOR4& color )
{
}

void StaticPlane::BeginRefresh( void )
{
	if( m_pWorld != NULL )
	{
		m_pWorld->DetachCollisionObject( this, false );
	}
}

void StaticPlane::EndRefresh( void )
{
	if( m_pWorld != NULL )
	{
		m_pWorld->AttachCollisionObject( this, false );
	}
}

}}}}}
