#include "Mix/Tool/CLR/Core/Dynamics/World.h"

#include "Mix/Tool/Win32/Core/Dynamics/Factory.h"
#include "Mix/Tool/Win32/Core/Dynamics/World.h"
#include "Mix/Tool/CLR/Core/Dynamics/CollisionObject.h"

namespace Mix{ namespace Tool{ namespace Dynamics{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Picker
////////////////////////////////////////////////////////////////////////////////////////////////////

Picker::Picker( Mix::Tool::Win32::Dynamics::World* _impl ) :
impl( _impl )
{
}

Picker::~Picker( void )
{
	impl = NULL;
}

void Picker::Catch( Mix::Tool::Math::Vector^ eyePos, Mix::Tool::Math::Vector^ fromWorldPos, Mix::Tool::Math::Vector^ toWorldPos )
{
	if( impl != NULL )
	{
		impl->Picker_Catch( D3DXVECTOR3( eyePos->X, eyePos->Y, eyePos->Z ),
							D3DXVECTOR3( fromWorldPos->X, fromWorldPos->Y, fromWorldPos->Z ),
							D3DXVECTOR3( toWorldPos->X, toWorldPos->Y, toWorldPos->Z ) );
	}
}

void Picker::Update( Mix::Tool::Math::Vector^ eyePos, Mix::Tool::Math::Vector^ toWorldPos )
{
	if( impl != NULL )
	{
		impl->Picker_Update(	D3DXVECTOR3( eyePos->X, eyePos->Y, eyePos->Z ),
								D3DXVECTOR3( toWorldPos->X, toWorldPos->Y, toWorldPos->Z ) );
	}
}

void Picker::Release( void )
{
	if( impl != NULL )
	{
		impl->Picker_Release();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// CollisionObjectCollection
////////////////////////////////////////////////////////////////////////////////////////////////////

CollisionObjectCollection::CollisionObjectCollection( Mix::Tool::Win32::Dynamics::World* _impl ) :
impl( _impl ),
m_List( gcnew System::Collections::Generic::List<Mix::Tool::Dynamics::CollisionObject^>() )
{
	if( _impl == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_impl" );
	}
}

CollisionObjectCollection::~CollisionObjectCollection( void )
{
	if( m_List->Count > 0 )
	{
		if( impl != NULL )
		{
			for each ( Mix::Tool::Dynamics::CollisionObject^ collObj in m_List )
			{
				impl->RemoveCollisionObject( collObj->Impl );
			}
		}

		for each ( Mix::Tool::Dynamics::CollisionObject^ collObj in m_List )
		{
			delete collObj;
		}

		m_List->Clear();
	}

	impl = NULL;
}

int CollisionObjectCollection::Count::get( void )
{
	return m_List->Count;
}

Mix::Tool::Dynamics::CollisionObject^ CollisionObjectCollection::default::get( int index )
{
	try
	{
		return m_List[index];
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

bool CollisionObjectCollection::Add( Mix::Tool::Dynamics::CollisionObject^ collObj )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( impl->AddCollisionObject( collObj->Impl ) == true )
	{
		if( m_List->Contains( collObj ) == true )
		{
			throw gcnew System::Exception( L"プログラミングバグ( CollisionObjectCollection::Add )" );
		}

		m_List->Add( collObj );
	}
	else
	{
		return false;
	}

	return true;
}

bool CollisionObjectCollection::Remove( Mix::Tool::Dynamics::CollisionObject^ collObj )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( impl->RemoveCollisionObject( collObj->Impl ) == true )
	{
		if( m_List->Contains( collObj ) == false )
		{
			throw gcnew System::Exception( L"プログラミングバグ( CollisionObjectCollection::Remove )" );
		}

		m_List->Remove( collObj );
	}
	else
	{
		return false;
	}

	return true;
}

System::Collections::IEnumerator^ CollisionObjectCollection::GetEnumerator( void )
{
	return m_List->GetEnumerator();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// World
////////////////////////////////////////////////////////////////////////////////////////////////////

World::World( void ) :
impl( Mix::Tool::Win32::Dynamics::Factory::CreateWorld() )
{
	m_CollObjCollection = gcnew Mix::Tool::Dynamics::CollisionObjectCollection( impl );
	m_Picker = gcnew Mix::Tool::Dynamics::Picker( impl );
}

World::~World( void )
{
	if( m_CollObjCollection != nullptr )
	{
		delete m_CollObjCollection;
	}

	if( m_Picker != nullptr )
	{
		delete m_Picker;
	}

	if( impl != NULL )
	{
		delete impl;
	}
}

Mix::Tool::Math::Vector^ World::Gravity::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	D3DXVECTOR3 gravity = impl->GetGravity();

	return gcnew Mix::Tool::Math::Vector( gravity.x, gravity.y, gravity.z, 1.0f );
}

void World::Gravity::set( Mix::Tool::Math::Vector^ value )
{
	if( impl != NULL )
	{
		impl->SetGravity( D3DXVECTOR3( value->X, value->Y, value->Z ) );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

Mix::Tool::Dynamics::CollisionObjectCollection^ World::CollisionObjects::get( void )
{
	return m_CollObjCollection;
}

Mix::Tool::Dynamics::Picker^ World::Picker::get( void )
{
	return m_Picker;
}

void World::Update( float dt )
{
	if( impl != NULL )
	{
		impl->Update( dt );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

Mix::Tool::Win32::Dynamics::World* World::Impl::get( void )
{
	return impl;
}

}}}
