#include "Mix/Private/Dynamics/CompoundShape.h"

#include "Mix/Graphics/Utility/IPerspectiveRenderer.h"

namespace Mix{ namespace Dynamics{

CompoundShape* CompoundShape::CreateInstance( void )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_DYNAMICS, CompoundShape );
}

CompoundShape::CompoundShape( void ) :
m_pObject( NULL )
{
}

CompoundShape::~CompoundShape( void )
{
	for( CompoundShape::ChildList::iterator it = m_ChildList.begin(); it != m_ChildList.end(); ++it )
	{
		m_pObject->removeChildShape( dynamic_cast<Mix::Dynamics::Shape*>( ( *it ) )->Bullet_GetCollisionShapePtr() );
		MIX_RELEASE( ( *it ) );
	}

	MIX_LIB_DELETE( m_pObject );
}

Boolean CompoundShape::Initialize( void )
{
	m_pObject = MIX_LIB_NEW btCompoundShape();
	if( m_pObject != NULL )
	{
		Shape::Bullet_SetCollisionShape( m_pObject );
	}
	else
	{
		return False;
	}

	return True;
}

btConvexShape* CompoundShape::Bullet_GetConvexShapePtr( void ) const
{
	return NULL;
}

Boolean CompoundShape::AddChild( Mix::Dynamics::IShape* pShape, const Mix::Quaternion& rot, const Mix::Vector3& pos )
{
	if( pShape == NULL )
	{
		return False;
	}

	btTransform tr;

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

	m_pObject->addChildShape( tr, dynamic_cast<Mix::Dynamics::Shape*>( pShape )->Bullet_GetCollisionShapePtr() );

	MIX_ADD_REF( pShape );
	m_ChildList.push_back( pShape );

	return True;
}

UInt32 CompoundShape::RemoveChild( Mix::Dynamics::IShape* pShape )
{
	if( pShape == NULL )
	{
		return 0;
	}

	UInt32 last = MIX_UIT_TO_UI32( m_ChildList.size() - 1 );
	UInt32 removeCount = 0;

	for( UInt32 i = last; i >= 0 ; i-- )
	{
		if( m_ChildList[i] == pShape )
		{
			if( RemoveChildByIndex( i ) == True )
			{
				removeCount++;
			}
		}
	}

	return removeCount;
}

Boolean CompoundShape::RemoveChildByIndex( UInt32 index )
{
	if( m_ChildList.size() <= index )
	{
		return False;
	}

	//btCompoundShape の削除処理は 指定されたインデックスの要素と最後の要素を入れ替えて、最後をポップする

	UIntT lastIndex = m_ChildList.size() - 1;
	Mix::Dynamics::IShape* pLastShape = m_ChildList[lastIndex];
	Mix::Dynamics::IShape* pShape = m_ChildList[index];

	m_pObject->removeChildShapeByIndex( index );

	m_ChildList[index] = pLastShape;
	m_ChildList[lastIndex] = pShape;
	m_ChildList.pop_back();

	MIX_RELEASE( pShape );

	return True;
}

Boolean CompoundShape::GetChildByIndex( UInt32 index, Mix::Dynamics::IShape** ppShape )
{
	if( m_ChildList.size() <= index )
	{
		return NULL;
	}

	Mix::Dynamics::IShape* pShape = m_ChildList[index];
	MIX_ADD_REF( pShape );
	( *ppShape ) = pShape;

	return True;
}

Mix::Dynamics::IShape* CompoundShape::GetChildPtrByIndex( UInt32 index ) const
{
	if( m_ChildList.size() <= index )
	{
		return NULL;
	}

	return m_ChildList[index];
}

Boolean CompoundShape::GetChildTransformByIndex( UInt32 index, Mix::Quaternion& rot, Mix::Vector3& pos )
{
	if( m_ChildList.size() <= index )
	{
		return False;
	}

	const btTransform& tr = m_pObject->getChildTransform( index );
	btQuaternion trRot = tr.getRotation();
	const btVector3& trPos = tr.getOrigin();

	rot.x = trRot.x();
	rot.y = trRot.y();
	rot.z = trRot.z();
	rot.w = trRot.w();

	pos.x = trPos.x();
	pos.y = trPos.y();
	pos.z = trPos.z();

	return True;
}

Boolean CompoundShape::SetChildTransformByIndex( UInt32 index, const Mix::Quaternion& rot, const Mix::Vector3& pos )
{
	if( m_ChildList.size() <= index )
	{
		return False;
	}

	btTransform tr;

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

	m_pObject->updateChildTransform( index, tr );

	return True;
}

UInt32 CompoundShape::GetChildCount( void ) const
{
	return MIX_UIT_TO_UI32( m_ChildList.size() );
}

Mix::Dynamics::IShape::TYPE CompoundShape::GetType( void ) const
{
	return Mix::Dynamics::IShape::COMPOUND;
}

Float32 CompoundShape::GetMargin( void ) const
{
	return Shape::Bullet_GetMargin();
}

void CompoundShape::SetMargin( Float32 margin )
{
	Shape::Bullet_SetMargin( margin );
}

void CompoundShape::DebugDraw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer )
{
	if( pPerspectiveRenderer != NULL )
	{
		Mix::Matrix4x4 preMat = pPerspectiveRenderer->GetMatrix();

		Int32 count =  MIX_UIT_TO_I32( m_ChildList.size() );

		for( Int32 i = 0; i < count; i++ )
		{
			const btTransform& tr = m_pObject->getChildTransform( i );
			btQuaternion rot = tr.getRotation();
			const btVector3& pos = tr.getOrigin();

			Mix::Matrix4x4 mat( Mix::Quaternion( rot.x(), rot.y(), rot.z(), rot.w() ), Mix::Vector3( pos.x(), pos.y(), pos.z() ) );

			pPerspectiveRenderer->SetMatrix( mat * preMat );
			m_ChildList[i]->DebugDraw( pPerspectiveRenderer );
		}

		pPerspectiveRenderer->SetMatrix( preMat );
	}
}

}}
