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

#include "Mix/Tool/Win32/Core/Dynamics/Factory.h"
#include "Mix/Tool/Win32/Core/Dynamics/KinematicCharacter.h"
#include "Mix/Tool/CLR/Core/Dynamics/FlagsGenerator.h"
#include "Mix/Tool/CLR/Core/Dynamics/IdentifierGenerator.h"
#include "Mix/Tool/CLR/Core/Dynamics/PhysicsMaterial.h"

namespace Mix{ namespace Tool{ namespace Dynamics{

KinematicCharacter::KinematicCharacter( Mix::Tool::Win32::Dynamics::KinematicCharacter* _impl ) :
impl( _impl ),
m_bInternalImpl( false ),
m_PhysicsMaterial( nullptr )
{
}

KinematicCharacter::KinematicCharacter( void ) :
impl( Mix::Tool::Win32::Dynamics::Factory::CreateKinematicCharacter() ),
m_bInternalImpl( true ),
m_PhysicsMaterial( nullptr )
{
}

KinematicCharacter::~KinematicCharacter( void )
{
	if( m_bInternalImpl == true )
	{
		if( impl != NULL )
		{
			delete impl;
			impl = NULL;
		}
	}
	else
	{
		impl = NULL;
	}

	m_PhysicsMaterial = nullptr;
}

Mix::Tool::Win32::Dynamics::KinematicCharacter* KinematicCharacter::ImplW32KinematicCharacter::get( void )
{
	return impl;
}

Mix::Tool::Dynamics::PhysicsMaterial^ KinematicCharacter::PhysicsMaterial::get( void )
{
	return m_PhysicsMaterial;
}

void KinematicCharacter::PhysicsMaterial::set( Mix::Tool::Dynamics::PhysicsMaterial^ value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 直前の物理マテリアルのイベントハンドラーを解除
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_PhysicsMaterial != nullptr )
	{
		m_PhysicsMaterial->ValueChanged -= gcnew System::EventHandler( this, &KinematicCharacter::PhysicsMaterial_ValueChanged );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 物理マテリアルの値を設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Mix::Tool::Win32::Dynamics::MATERIAL w32Material;

	if( value != nullptr )
	{
		w32Material.id = value->Identifier->Value;
		w32Material.attr = value->Attributes->Value;
		w32Material.friction = value->Friction;
		w32Material.restitution = value->Restitution;
	}
	else
	{
		w32Material.id = Mix::Tool::Dynamics::PhysicsMaterial::DefaultIdentifier;
		w32Material.attr = Mix::Tool::Dynamics::PhysicsMaterial::DefaultAttributes;
		w32Material.friction = Mix::Tool::Dynamics::PhysicsMaterial::DefaultFriction;
		w32Material.restitution = Mix::Tool::Dynamics::PhysicsMaterial::DefaultRestitution;
	}

	impl->SetMaterial( w32Material );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 新規の物理マテリアルのイベントハンドラーを登録
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_PhysicsMaterial = value;

	if( m_PhysicsMaterial != nullptr )
	{
		m_PhysicsMaterial->ValueChanged += gcnew System::EventHandler( this, &KinematicCharacter::PhysicsMaterial_ValueChanged );
	}
}

float KinematicCharacter::Height::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetHeight();
}

void KinematicCharacter::Height::set( float value )
{
	if( impl != NULL )
	{
		impl->SetHeight( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

float KinematicCharacter::Radius::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetRadius();
}

void KinematicCharacter::Radius::set( float value )
{
	if( impl != NULL )
	{
		impl->SetRadius( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

float KinematicCharacter::Gravity::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetGravity();
}

void KinematicCharacter::Gravity::set( float value )
{
	if( impl != NULL )
	{
		impl->SetGravity( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

float KinematicCharacter::MaxFallSpeed::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetMaxFallSpeed();
}

void KinematicCharacter::MaxFallSpeed::set( float value )
{
	if( impl != NULL )
	{
		impl->SetMaxFallSpeed( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

float KinematicCharacter::InitJumpSpeed::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetInitJumpSpeed();
}

void KinematicCharacter::InitJumpSpeed::set( float value )
{
	if( impl != NULL )
	{
		impl->SetInitJumpSpeed( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

float KinematicCharacter::StepOffset::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetStepOffset();
}

void KinematicCharacter::StepOffset::set( float value )
{
	if( impl != NULL )
	{
		impl->SetStepOffset( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

float KinematicCharacter::SlopeLimit::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetSlopeLimit();
}

void KinematicCharacter::SlopeLimit::set( float value )
{
	if( impl != NULL )
	{
		impl->SetSlopeLimit( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

bool KinematicCharacter::IsGround::get( void )
{
	if( impl == NULL )
	{
		return true;
	}

	return impl->IsGround();
}

void KinematicCharacter::Jump( void )
{
	if( impl != NULL )
	{
		impl->Jump();
	}
}

void KinematicCharacter::PhysicsMaterial_ValueChanged( System::Object^ sender, System::EventArgs^ e )
{
	if( impl != NULL )
	{
		Mix::Tool::Dynamics::PhysicsMaterial^ physicsMaterial = safe_cast<Mix::Tool::Dynamics::PhysicsMaterial^>( sender );
		Mix::Tool::Win32::Dynamics::MATERIAL w32Material;

		w32Material.id = physicsMaterial->Identifier->Value;
		w32Material.attr = physicsMaterial->Attributes->Value;
		w32Material.friction = physicsMaterial->Friction;
		w32Material.restitution = physicsMaterial->Restitution;

		impl->SetMaterial( w32Material );
	}
}

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

}}}
