#include "Mix/Tool/CLR/Core/Dynamics/Design/Basic.h"

#include "Mix/Tool/Win32/Core/Dynamics/Factory.h"
#include "Mix/Tool/Win32/Core/Dynamics/BoxShape.h"
#include "Mix/Tool/Win32/Core/Dynamics/CapsuleShape.h"
#include "Mix/Tool/Win32/Core/Dynamics/SphereShape.h"
#include "Mix/Tool/Win32/Core/Dynamics/Design/Basic.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"
#include "Mix/Tool/CLR/Core/Dynamics/BoxShape.h"
#include "Mix/Tool/CLR/Core/Dynamics/CapsuleShape.h"
#include "Mix/Tool/CLR/Core/Dynamics/SphereShape.h"
#include "Mix/Tool/CLR/Core/Dynamics/Design/BoundingBox.h"

namespace Mix{ namespace Tool{ namespace Dynamics{ namespace Design{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Shape : Internal
////////////////////////////////////////////////////////////////////////////////////////////////////

Shape::Shape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox ) :
implBasic( NULL ),
hObject( NULL ),
hShape( NULL ),
m_BoundingBox( nullptr ),
m_Rot( nullptr ),
m_Pos( nullptr )
{
	if( _boundingBox == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"_boundingBox" );
	}

	m_BoundingBox = _boundingBox;
	m_Rot = m_BoundingBox->DegreeRotation;
	m_Pos = m_BoundingBox->Position;
}

Shape::Shape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox, Mix::Tool::Math::Vector^ _rot, Mix::Tool::Math::Vector^ _pos ) :
implBasic( NULL ),
hObject( NULL ),
hShape( NULL ),
m_BoundingBox( nullptr ),
m_Rot( nullptr ),
m_Pos( nullptr )
{
	if( _boundingBox == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"_boundingBox" );
	}

	m_BoundingBox = _boundingBox;
	m_Rot = ( _rot != nullptr )? _rot : m_BoundingBox->DegreeRotation;
	m_Pos = ( _pos != nullptr )? _pos : m_BoundingBox->Position;
}

Shape::~Shape( void )
{
	// 解放は OnRemoved で行う
}

void Shape::Win32Shape::set( Mix::Tool::Win32::Dynamics::Shape* value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		//シェイプコレクションに追加されていない状態でもシェイプのパラメータを変更できるようにするため、
		//例外は出さない
		return;
	}

	if( value == NULL )
	{
		throw gcnew System::ArgumentNullException( L"Win32Shape" );
	}

	if( hShape == NULL )
	{
		hShape = implBasic->Object_AddShape( hObject, value, D3DXVECTOR3( m_Rot->X, m_Rot->Y, m_Rot->Z ), D3DXVECTOR3( m_Pos->X, m_Pos->Y, m_Pos->Z ) );
		if( hShape == NULL )
		{
			throw gcnew System::Exception( L"Basic::Object_AddShape がエラーを返しました" );
		}
	}
	else
	{
		if( implBasic->Object_SetShape( hObject, hShape, value, D3DXVECTOR3( m_Rot->X, m_Rot->Y, m_Rot->Z ), D3DXVECTOR3( m_Pos->X, m_Pos->Y, m_Pos->Z ) ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_SetShape がエラーを返しました" );
		}
	}
}

HANDLE Shape::Win32Handle::get( void )
{
	return hShape;
}

void Shape::OnAdded( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic, HANDLE _hObject )
{
	if( _implBasic == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_implBasic" );
	}

	if( _hObject == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_hObject" );
	}

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

	if( hShape != NULL )
	{
		throw gcnew System::Exception( L"ハンドルが有効な状態で Shape::OnAdded が呼び出されました(BUG)" );
	}

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

	implBasic = _implBasic;
	hObject = _hObject;
	hShape = NULL;
}

void Shape::OnRemoved( void )
{
	if( ( implBasic != NULL ) &&
		( hObject != NULL ) &&
		( hShape != NULL ) )
	{
		if( implBasic->Object_RemoveShape( hObject, hShape ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_RemoveShape がエラーを返しました" );
		}
	}

	hShape = NULL;
	hObject = NULL;
	implBasic = NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Shape : Public
////////////////////////////////////////////////////////////////////////////////////////////////////

Mix::Tool::Dynamics::Design::BoundingBox^ Shape::BoundingBox::get( void )
{
	return m_BoundingBox;
}

void Shape::BoundingBox::set( Mix::Tool::Dynamics::Design::BoundingBox^ value )
{
	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"BoundingBox" );
	}

	m_BoundingBox = value;

	Reset();
}

Mix::Tool::Math::Vector^ Shape::Rotation::get( void )
{
	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		D3DXVECTOR3 win32Rot( 0.0f, 0.0f, 0.0f );

		if( implBasic->Object_GetShapeRotation( hObject, hShape, win32Rot ) == true )
		{
			m_Rot = gcnew Mix::Tool::Math::Vector( win32Rot.x, win32Rot.y, win32Rot.z, 1.0f );
		}
		else
		{
			throw gcnew System::Exception( L"Basic::Object_GetShapeRotation がエラーを返しました" );
		}
	}

	return m_Rot;
}

void Shape::Rotation::set( Mix::Tool::Math::Vector^ value )
{
	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"Rotation" );
	}

	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		if( implBasic->Object_SetShapeRotation( hObject, hShape, D3DXVECTOR3( value->X, value->Y, value->Z ) ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_GetShapeRotation がエラーを返しました" );
		}
	}

	m_Rot = value;
}

Mix::Tool::Math::Vector^ Shape::Position::get( void )
{
	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		D3DXVECTOR3 win32Pos( 0.0f, 0.0f, 0.0f );

		if( implBasic->Object_GetShapePosition( hObject, hShape, win32Pos ) == true )
		{
			m_Pos = gcnew Mix::Tool::Math::Vector( win32Pos.x, win32Pos.y, win32Pos.z, 1.0f );
		}
		else
		{
			throw gcnew System::Exception( L"Basic::Object_GetShapeRotation がエラーを返しました" );
		}
	}

	return m_Pos;
}

void Shape::Position::set( Mix::Tool::Math::Vector^ value )
{
	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"Position" );
	}

	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		if( implBasic->Object_SetShapePosition( hObject, hShape, D3DXVECTOR3( value->X, value->Y, value->Z ) ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_GetShapePosition がエラーを返しました" );
		}
	}

	m_Pos = value;
}

void Shape::Reset( void )
{
	m_Rot = m_BoundingBox->DegreeRotation;
	m_Pos = m_BoundingBox->Position;
}

void Shape::ResetRotation( void )
{
	m_Rot = m_BoundingBox->DegreeRotation;

	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		if( implBasic->Object_SetShapeRotation( hObject, hShape, D3DXVECTOR3( m_Rot->X, m_Rot->Y, m_Rot->Z ) ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_SetShapeRotation がエラーを返しました" );
		}
	}
}

void Shape::ResetPosition( void )
{
	m_Pos = m_BoundingBox->Position;

	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		if( implBasic->Object_SetShapePosition( hObject, hShape, D3DXVECTOR3( m_Pos->X, m_Pos->Y, m_Pos->Z ) ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_SetShapePosition がエラーを返しました" );
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// BoxShape
////////////////////////////////////////////////////////////////////////////////////////////////////

BoxShape::BoxShape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox ) : Mix::Tool::Dynamics::Design::Shape( _boundingBox ),
m_pShape( NULL )
{
	try
	{
		NewShape( this->BoundingBox->HalfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

BoxShape::BoxShape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox, Mix::Tool::Math::Vector^ _halfExtents, Mix::Tool::Math::Vector^ _rot, Mix::Tool::Math::Vector^ _pos ) : Mix::Tool::Dynamics::Design::Shape( _boundingBox, _rot, _pos ),
m_pShape( NULL )
{
	if( _halfExtents == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"_halfExtents" );
	}

	try
	{
		NewShape( _halfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

BoxShape::~BoxShape( void )
{
}

Mix::Tool::Math::Vector^ BoxShape::HalfExtents::get( void )
{
	const D3DXVECTOR3& he = m_pShape->GetHalfExtents();

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

void BoxShape::HalfExtents::set( Mix::Tool::Math::Vector^ value )
{
	try
	{
		NewShape( value );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void BoxShape::NewShape( Mix::Tool::Math::Vector^ he )
{
	Mix::Tool::Win32::Dynamics::BoxShape* pNewShape = Mix::Tool::Win32::Dynamics::Factory::CreateBoxShape( D3DXVECTOR3( he->X, he->Y, he->Z ) );

	if( pNewShape != NULL )
	{
		this->Win32Shape = pNewShape;

		MIX_DELETE( m_pShape );
		m_pShape = pNewShape;
	}
	else
	{
		throw gcnew System::OutOfMemoryException();
	}
}

void BoxShape::Reset( void )
{
	try
	{
		Mix::Tool::Dynamics::Design::Shape::Reset();
		NewShape( this->BoundingBox->HalfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void BoxShape::OnAdded( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic, HANDLE _hObject )
{
	Mix::Tool::Dynamics::Design::Shape::OnAdded( _implBasic, _hObject );

	this->Win32Shape = m_pShape;
}

void BoxShape::OnRemoved( void )
{
	Mix::Tool::Dynamics::Design::Shape::OnRemoved();

	MIX_DELETE( m_pShape );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// CapsuleShape
////////////////////////////////////////////////////////////////////////////////////////////////////

CapsuleShape::CapsuleShape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox ) : Mix::Tool::Dynamics::Design::Shape( _boundingBox ),
m_pShape( NULL )
{
	try
	{
		NewShape( BoundingBox->HalfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

CapsuleShape::CapsuleShape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox, Mix::Tool::Dynamics::Axis _axis, float _length, float _radius, Mix::Tool::Math::Vector^ _rot, Mix::Tool::Math::Vector^ _pos ) : Mix::Tool::Dynamics::Design::Shape( _boundingBox, _rot, _pos ),
m_pShape( NULL )
{
	try
	{
		NewShape( _axis, _length, _radius );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

CapsuleShape::~CapsuleShape( void )
{
}

Mix::Tool::Dynamics::Axis CapsuleShape::Axis::get( void )
{
	return CapsuleShape::ToCLRAxis( m_pShape->GetAxis() );
}

void CapsuleShape::Axis::set( Mix::Tool::Dynamics::Axis value )
{
	try
	{
		NewShape( value, m_pShape->GetLength(), m_pShape->GetRadius() );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

float CapsuleShape::Length::get( void )
{
	return m_pShape->GetLength();
}

void CapsuleShape::Length::set( float value )
{
	try
	{
		NewShape( CapsuleShape::ToCLRAxis( m_pShape->GetAxis() ), value, m_pShape->GetRadius() );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

float CapsuleShape::Radius::get( void )
{
	return m_pShape->GetRadius();
}

void CapsuleShape::Radius::set( float value )
{
	try
	{
		NewShape( CapsuleShape::ToCLRAxis( m_pShape->GetAxis() ), m_pShape->GetLength(), value );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void CapsuleShape::NewShape( Mix::Tool::Math::Vector^ he )
{
	if( he == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"he" );
	}

	try
	{
		NewShape( Mix::Tool::Win32::Dynamics::Factory::CreateCapsuleShape( D3DXVECTOR3( he->X, he->Y, he->Z ) ) );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void CapsuleShape::NewShape( Mix::Tool::Dynamics::Axis axis, float length, float radius )
{
	try
	{
		NewShape( Mix::Tool::Win32::Dynamics::Factory::CreateCapsuleShape( CapsuleShape::ToW32Axis( axis ), radius, length ) );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void CapsuleShape::NewShape( Mix::Tool::Win32::Dynamics::CapsuleShape* pNewShape )
{
	if( pNewShape != NULL )
	{
		this->Win32Shape = pNewShape;

		MIX_DELETE( m_pShape );
		m_pShape = pNewShape;
	}
	else
	{
		throw gcnew System::OutOfMemoryException();
	}
}

void CapsuleShape::Reset( void )
{
	try
	{
		Mix::Tool::Dynamics::Design::Shape::Reset();
		NewShape( BoundingBox->HalfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void CapsuleShape::OnAdded( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic, HANDLE _hObject )
{
	Mix::Tool::Dynamics::Design::Shape::OnAdded( _implBasic, _hObject );

	this->Win32Shape = m_pShape;
}

void CapsuleShape::OnRemoved( void )
{
	Mix::Tool::Dynamics::Design::Shape::OnRemoved();

	MIX_DELETE( m_pShape );
}

Mix::Tool::Win32::Dynamics::AXIS CapsuleShape::ToW32Axis( Mix::Tool::Dynamics::Axis axis )
{
	Mix::Tool::Win32::Dynamics::AXIS ret;

	switch( axis )
	{
	case Mix::Tool::Dynamics::Axis::X:
		ret = Mix::Tool::Win32::Dynamics::aX;
		break;
	case Mix::Tool::Dynamics::Axis::Y:
		ret = Mix::Tool::Win32::Dynamics::aY;
		break;
	case Mix::Tool::Dynamics::Axis::Z:
		ret = Mix::Tool::Win32::Dynamics::aZ;
		break;

	default:
		ret = Mix::Tool::Win32::Dynamics::aY;
		break;
	}

	return ret;
}

Mix::Tool::Dynamics::Axis CapsuleShape::ToCLRAxis( Mix::Tool::Win32::Dynamics::AXIS axis )
{
	Mix::Tool::Dynamics::Axis ret;

	switch( axis )
	{
	case Mix::Tool::Win32::Dynamics::aX:
		ret = Mix::Tool::Dynamics::Axis::X;
		break;
	case Mix::Tool::Win32::Dynamics::aY:
		ret = Mix::Tool::Dynamics::Axis::Y;
		break;
	case Mix::Tool::Win32::Dynamics::aZ:
		ret = Mix::Tool::Dynamics::Axis::Z;
		break;

	default:
		ret = Mix::Tool::Dynamics::Axis::Y;
		break;
	}

	return ret;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// SphereShape
////////////////////////////////////////////////////////////////////////////////////////////////////

SphereShape::SphereShape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox ) : Mix::Tool::Dynamics::Design::Shape( _boundingBox ),
m_pShape( NULL )
{
	try
	{
		NewShape( this->BoundingBox->HalfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

SphereShape::SphereShape( Mix::Tool::Dynamics::Design::BoundingBox^ _boundingBox, float _radius, Mix::Tool::Math::Vector^ _rot, Mix::Tool::Math::Vector^ _pos ) : Mix::Tool::Dynamics::Design::Shape( _boundingBox, _rot, _pos ),
m_pShape( NULL )
{
	try
	{
		NewShape( _radius );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

SphereShape::~SphereShape( void )
{
}

float SphereShape::Radius::get( void )
{
	return m_pShape->GetRadius();
}

void SphereShape::Radius::set( float value )
{
	try
	{
		NewShape( value );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void SphereShape::NewShape( Mix::Tool::Math::Vector^ he )
{
	try
	{
		NewShape( Mix::Tool::Win32::Dynamics::Factory::CreateSphereShape( D3DXVECTOR3( he->X, he->Y, he->Z ) ) );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void SphereShape::NewShape( float radius )
{
	try
	{
		NewShape( Mix::Tool::Win32::Dynamics::Factory::CreateSphereShape( radius ) );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void SphereShape::NewShape( Mix::Tool::Win32::Dynamics::SphereShape* pNewShape )
{
	if( pNewShape != NULL )
	{
		this->Win32Shape = pNewShape;

		MIX_DELETE( m_pShape );
		m_pShape = pNewShape;
	}
	else
	{
		throw gcnew System::OutOfMemoryException();
	}
}

void SphereShape::Reset( void )
{
	try
	{
		Mix::Tool::Dynamics::Design::Shape::Reset();
		NewShape( this->BoundingBox->HalfExtents );
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

void SphereShape::OnAdded( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic, HANDLE _hObject )
{
	Mix::Tool::Dynamics::Design::Shape::OnAdded( _implBasic, _hObject );

	this->Win32Shape = m_pShape;
}

void SphereShape::OnRemoved( void )
{
	Mix::Tool::Dynamics::Design::Shape::OnRemoved();

	MIX_DELETE( m_pShape );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ShapeCollection
////////////////////////////////////////////////////////////////////////////////////////////////////

ShapeCollection::ShapeCollection( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic, HANDLE _hObject ) :
implBasic( NULL ),
hObject( NULL ),
m_List( nullptr ),
m_Selected( nullptr )
{
	if( _implBasic == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_implBasic" );
	}

	if( _hObject == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_hObject" );
	}

	implBasic = _implBasic;
	hObject = _hObject;

	m_List = gcnew System::Collections::Generic::List<Mix::Tool::Dynamics::Design::Shape^>();
	if( m_List == nullptr )
	{
		throw gcnew System::OutOfMemoryException();
	}
}

ShapeCollection::~ShapeCollection( void )
{
	m_Selected = nullptr;

	if( implBasic != NULL )
	{
		for each ( Mix::Tool::Dynamics::Design::Shape^ shape in m_List )
		{
			if( shape != nullptr )
			{
				shape->OnRemoved();
				delete shape;
			}
		}

		m_List->Clear();

		implBasic = NULL;
	}
}

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

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

Mix::Tool::Dynamics::Design::Shape^ ShapeCollection::Selected::get( void )
{
	return m_Selected;
}

void ShapeCollection::Selected::set( Mix::Tool::Dynamics::Design::Shape^ value )
{
	if( implBasic == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( value != nullptr )
	{
		if( m_List->Contains( value ) == true )
		{
			if( implBasic->Object_ShapeSelected( hObject, value->Win32Handle ) == false )
			{
				throw gcnew System::Exception( L"Basic::Object_ShapeSelected がエラーを返しました" );
			}
		}
	}
	else
	{
		if( implBasic->Object_ShapeSelected( hObject, NULL ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_ShapeSelected がエラーを返しました" );
		}
	}

	m_Selected = value;
}

bool ShapeCollection::Add( Mix::Tool::Dynamics::Design::Shape^ shape )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( shape == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"shape" );
	}

	if( m_List->Contains( shape ) == true )
	{
		throw gcnew System::ArgumentException( L"追加しようとしたシェイプは既にリストに存在しています" );
	}

	/*
		リストに追加
	*/

	m_List->Add( shape );
	shape->OnAdded( implBasic, hObject );

	/*
		選択の処理
	*/

	if( m_List->Count == 1 )
	{
		m_Selected = m_List[0];

		if( implBasic->Object_ShapeSelected( hObject, m_Selected->Win32Handle ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_ShapeSelected( m_Selected->Win32Handle ) がエラーを返しました" );
		}
	}

	return true;
}

bool ShapeCollection::Remove( Mix::Tool::Dynamics::Design::Shape^ shape )
{
	if( shape == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"shape" );
	}

	if( m_List->Contains( shape ) == false )
	{
		throw gcnew System::ArgumentException( L"削除しようとしたシェイプはリストに存在しません" );
	}

	/*
		選択の処理
	*/

	if( m_Selected == shape )
	{
		int count = m_List->Count;

		if( count > 1 )
		{
			int index = m_List->IndexOf( shape );

			if( index == ( m_List->Count - 1 ) )
			{
				//最後の場合は一つ前のシェイプを選択
				m_Selected = m_List[index - 1];
			}
			else
			{
				//最後ではない場合は、一つ後のシェイプを選択
				m_Selected = m_List[index + 1];
			}

			if( implBasic->Object_ShapeSelected( hObject, m_Selected->Win32Handle ) == false )
			{
				throw gcnew System::Exception( L"Basic::Object_ShapeSelected( m_Selected->Win32Handle ) がエラーを返しました" );
			}
		}
		else
		{
			//最後の一つだった場合は選択を解除
			m_Selected = nullptr;

			if( implBasic->Object_ShapeSelected( hObject, NULL ) == false )
			{
				throw gcnew System::Exception( L"Basic::Object_ShapeSelected( NULL ) がエラーを返しました" );
			}
		}
	}

	/*
		リストから削除
	*/

	m_List->Remove( shape );
	shape->OnRemoved();

	return true;
}

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// BasicChild
////////////////////////////////////////////////////////////////////////////////////////////////////

BasicChild::BasicChild( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic, HANDLE _hObject ) :
implBasic( NULL ),
hObject( NULL ),
m_Shapes( nullptr ),
m_PhysicsMaterial( nullptr )
{
	if( _implBasic == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_implBasic" );
	}

	if( _hObject == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_hObject" );
	}

	implBasic = _implBasic;
	hObject = _hObject;

	m_Shapes = gcnew Mix::Tool::Dynamics::Design::ShapeCollection( _implBasic, _hObject );
	if( m_Shapes == nullptr )
	{
		throw gcnew System::OutOfMemoryException();
	}
}

BasicChild::~BasicChild( void )
{
	m_PhysicsMaterial = nullptr;

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

	if( ( implBasic != NULL ) &&
		( hObject != NULL ) )
	{
		implBasic->Object_Remove( hObject );
	}

	hObject = NULL;
	implBasic = NULL;
}

HANDLE BasicChild::Win32Handle::get( void )
{
	return hObject;
}

BasicChildType BasicChild::Type::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	Mix::Tool::Win32::Dynamics::Design::Basic::OBJECT_TYPE win32ObjType;
	BasicChildType type;

	if( implBasic->Object_GetType( hObject, win32ObjType ) == true )
	{
		switch( win32ObjType )
		{
		case Mix::Tool::Win32::Dynamics::Design::Basic::COLLIDER:
			type = BasicChildType::Collider;
			break;
		case Mix::Tool::Win32::Dynamics::Design::Basic::SENSOR:
			type = BasicChildType::Sensor;
			break;

		default:
			throw gcnew System::Exception( L"Basic::Object_GetType で取得した値はサポートされていません" );
			break;
		}
	}
	else
	{
		throw gcnew System::Exception( L"Basic::Object_GetType がエラーを返しました" );
	}

	return type;
}

System::String^ BasicChild::Name::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	std::wstring temp;

	if( implBasic->Object_GetName( hObject, temp ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_GetName がエラーを返しました" );
	}

	return gcnew System::String( temp.c_str() );
}

void BasicChild::Name::set( System::String^ value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	System::String^ safeValue = ( value != nullptr )? value : L"";

	if( this->Name->Equals( safeValue ) == false )
	{
		pin_ptr<const wchar_t> wpValue = PtrToStringChars( safeValue );

		if( implBasic->Object_SetName( hObject, wpValue ) == false )
		{
			throw gcnew System::Exception( L"Basic::Object_SetName がエラーを返しました" );
		}

		this->NameChanged( this, gcnew System::EventArgs() );
	}
}

Mix::Tool::Math::Vector^ BasicChild::CenterRotation::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	D3DXVECTOR3 rot;

	if( implBasic->Object_GetCenterRotation( hObject, rot ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_GetCenterRotation がエラーを返しました" );
	}

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

void BasicChild::CenterRotation::set( Mix::Tool::Math::Vector^ value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"CenterRotation" );
	}

	if( implBasic->Object_SetCenterRotation( hObject, D3DXVECTOR3( value->X, value->Y, value->Z ) ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_SetCenterRotation がエラーを返しました" );
	}
}

Mix::Tool::Math::Vector^ BasicChild::CenterPosition::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	D3DXVECTOR3 pos( 0.0f, 0.0f, 0.0f );

	if( implBasic->Object_GetCenterPosition( hObject, pos ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_GetCenterPosition がエラーを返しました" );
	}

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

void BasicChild::CenterPosition::set( Mix::Tool::Math::Vector^ value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"CenterPosition" );
	}

	if( implBasic->Object_SetCenterPosition( hObject, D3DXVECTOR3( value->X, value->Y, value->Z ) ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_GetCenterPosition がエラーを返しました" );
	}
}

Mix::Tool::Dynamics::Design::ShapeCollection^ BasicChild::Shapes::get( void )
{
	return m_Shapes;
}

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

void BasicChild::PhysicsMaterial::set( Mix::Tool::Dynamics::PhysicsMaterial^ value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

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

	if( m_PhysicsMaterial != nullptr )
	{
		m_PhysicsMaterial->ValueChanged -= gcnew System::EventHandler( this, &BasicChild::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;
	}

	implBasic->Object_SetMaterial( hObject, w32Material );

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

	m_PhysicsMaterial = value;

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

void BasicChild::PhysicsMaterial_ValueChanged( System::Object^ sender, System::EventArgs^ e )
{
	if( ( implBasic != NULL ) &&
		( hObject != 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;

		implBasic->Object_SetMaterial( hObject, w32Material );
	}
}

BasicChildStatus BasicChild::Status::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	Mix::Tool::Win32::Dynamics::Design::Basic::COLLIDER_TYPE win32Type;
	BasicChildStatus status;

	if( implBasic->Collider_GetType( hObject, win32Type ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_GetType がエラーを返しました" );
	}

	switch( win32Type )
	{
	case Mix::Tool::Win32::Dynamics::Design::Basic::DEFAULT:
		status = BasicChildStatus::Default;
		break;
	case Mix::Tool::Win32::Dynamics::Design::Basic::STATIC:
		status = BasicChildStatus::Static;
		break;
	case Mix::Tool::Win32::Dynamics::Design::Basic::KINEMATIC:
		status = BasicChildStatus::Kinematic;
		break;

	default:
		throw gcnew System::Exception( L"Basic::Collider_GetType で取得した値はサポートされていません" );
	}

	return status;
}

void BasicChild::Status::set( BasicChildStatus value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	Mix::Tool::Win32::Dynamics::Design::Basic::COLLIDER_TYPE win32Type;

	switch( value )
	{
	case BasicChildStatus::Default:
		win32Type = Mix::Tool::Win32::Dynamics::Design::Basic::DEFAULT;
		break;
	case BasicChildStatus::Static:
		win32Type = Mix::Tool::Win32::Dynamics::Design::Basic::STATIC;
		break;
	case BasicChildStatus::Kinematic:
		win32Type = Mix::Tool::Win32::Dynamics::Design::Basic::KINEMATIC;
		break;

	default:
		throw gcnew System::Exception( L"Type で指定された値はサポートされていません" );
		break;
	}

	if( implBasic->Collider_SetType( hObject, win32Type ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_SetType がエラーを返しました" );
	}
}

float BasicChild::Mass::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	float mass = 0.0f;

	if( implBasic->Collider_GetMass( hObject, mass ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_GetMass がエラーを返しました" );
	}

	return mass;
}

void BasicChild::Mass::set( float value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( implBasic->Collider_SetMass( hObject, max( 0.01f, value ) ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_SetMass がエラーを返しました" );
	}
}

bool BasicChild::AlwaysActive::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	bool state = false;

	if( implBasic->Collider_GetAlwaysActive( hObject, state ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_GetAlwaysActive がエラーを返しました" );
	}

	return state;
}

void BasicChild::AlwaysActive::set( bool value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( implBasic->Collider_SetAlwaysActive( hObject, value ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_SetAlwaysActive がエラーを返しました" );
	}
}

Mix::Tool::Dynamics::Design::RotationAxisFlags BasicChild::RotationAxisFlags::get( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	int srcFlags = 0;
	Mix::Tool::Dynamics::Design::RotationAxisFlags flags = Mix::Tool::Dynamics::Design::RotationAxisFlags::None;

	if( implBasic->Collider_GetRotationAxis( hObject, srcFlags ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_GetRotationAxis がエラーを返しました" );
	}

	if( MIX_TEST_BIT( srcFlags, Mix::Tool::Win32::Dynamics::Design::Basic::RA_X ) == Mix::Tool::Win32::Dynamics::Design::Basic::RA_X ) { flags = flags | Mix::Tool::Dynamics::Design::RotationAxisFlags::X; }
	if( MIX_TEST_BIT( srcFlags, Mix::Tool::Win32::Dynamics::Design::Basic::RA_Y ) == Mix::Tool::Win32::Dynamics::Design::Basic::RA_Y ) { flags = flags | Mix::Tool::Dynamics::Design::RotationAxisFlags::Y; }
	if( MIX_TEST_BIT( srcFlags, Mix::Tool::Win32::Dynamics::Design::Basic::RA_Z ) == Mix::Tool::Win32::Dynamics::Design::Basic::RA_Z ) { flags = flags | Mix::Tool::Dynamics::Design::RotationAxisFlags::Z; }

	return flags;
}

void BasicChild::RotationAxisFlags::set( Mix::Tool::Dynamics::Design::RotationAxisFlags value )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	int flags = 0;

	if( MIX_TEST_BIT( value, Mix::Tool::Dynamics::Design::RotationAxisFlags::X ) == Mix::Tool::Dynamics::Design::RotationAxisFlags::X ) { flags = flags | Mix::Tool::Win32::Dynamics::Design::Basic::RA_X; }
	if( MIX_TEST_BIT( value, Mix::Tool::Dynamics::Design::RotationAxisFlags::Y ) == Mix::Tool::Dynamics::Design::RotationAxisFlags::Y ) { flags = flags | Mix::Tool::Win32::Dynamics::Design::Basic::RA_Y; }
	if( MIX_TEST_BIT( value, Mix::Tool::Dynamics::Design::RotationAxisFlags::Z ) == Mix::Tool::Dynamics::Design::RotationAxisFlags::Z ) { flags = flags | Mix::Tool::Win32::Dynamics::Design::Basic::RA_Z; }

	if( implBasic->Collider_SetRotationAxis( hObject, flags ) == false )
	{
		throw gcnew System::Exception( L"Basic::Collider_SetRotationAxis がエラーを返しました" );
	}
}

void BasicChild::ResetCenterRotation( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( implBasic->Object_ResetCenterRotation( hObject ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_ResetCenterRotation がエラーを返しました" );
	}
}

void BasicChild::ResetCenterPosition( void )
{
	if( ( implBasic == NULL ) ||
		( hObject == NULL ) )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( implBasic->Object_ResetCenterPosition( hObject ) == false )
	{
		throw gcnew System::Exception( L"Basic::Object_ResetCenterPosition がエラーを返しました" );
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// BasicChildColelction
////////////////////////////////////////////////////////////////////////////////////////////////////

BasicChildCollection::BasicChildCollection( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic ) :
implBasic( _implBasic ),
m_List( gcnew System::Collections::Generic::List<Mix::Tool::Dynamics::Design::BasicChild^>() ),
m_Selected( nullptr )
{
	if( _implBasic == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"_implBasic" );
	}
}

BasicChildCollection::~BasicChildCollection( void )
{
	m_Selected = nullptr;

	if( implBasic != NULL )
	{
		for each ( BasicChild^ child in m_List )
		{
			delete child;
		}

		m_List->Clear();

		implBasic = NULL;
	}
}

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

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

Mix::Tool::Dynamics::Design::BasicChild^ BasicChildCollection::Selected::get( void )
{
	return m_Selected;
}

void BasicChildCollection::Selected::set( Mix::Tool::Dynamics::Design::BasicChild^ value )
{
	if( implBasic == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"value" );
	}

	if( m_List->Contains( value ) == true )
	{
		implBasic->Object_Selected( value->Win32Handle );
		m_Selected = value;
	}
	else
	{
		implBasic->Object_Selected( NULL );
		m_Selected = nullptr;
	}
}

bool BasicChildCollection::Addable( Mix::Tool::Dynamics::Design::BasicChildType type )
{
	if( implBasic == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( ( type == BasicChildType::Collider ) &&
		( implBasic->Object_GetColliderCount() > 0 ) )
	{
		return false;
	}

	return true;
}

Mix::Tool::Dynamics::Design::BasicChild^ BasicChildCollection::Add( Mix::Tool::Dynamics::Design::BasicChildType type )
{
	if( implBasic == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	Mix::Tool::Win32::Dynamics::Design::Basic::OBJECT_TYPE objType;
	HANDLE hObject;
	Mix::Tool::Dynamics::Design::BasicChild^ child;

	/*
		オブジェクトタイプを決定
	*/

	switch( type )
	{
	case Mix::Tool::Dynamics::Design::BasicChildType::Collider:
		objType = Mix::Tool::Win32::Dynamics::Design::Basic::COLLIDER;
		break;
	case Mix::Tool::Dynamics::Design::BasicChildType::Sensor:
		objType = Mix::Tool::Win32::Dynamics::Design::Basic::SENSOR;
		break;

	default:
		throw gcnew System::Exception( L"BasicChildCollection::Add でサポートされないタイプが指定されました" );
		break;
	}

	/*
		オブジェクトのハンドルを作成
	*/

	hObject = implBasic->Object_Add( objType );
	if( hObject == NULL )
	{
		throw gcnew System::Exception( L"Basic::Object_Add がエラーを返しました" );
	}

	/*
		チャイルドを追加
	*/

	child = gcnew Mix::Tool::Dynamics::Design::BasicChild( implBasic, hObject );
	if( child != nullptr )
	{
		m_List->Add( child );
	}
	else
	{
		implBasic->Object_Remove( hObject );
		throw gcnew System::OutOfMemoryException();
	}

	/*
		選択の処理
	*/

	if( m_List->Count == 1 )
	{
		m_Selected = m_List[0];

		implBasic->Object_Selected( m_Selected->Win32Handle );
	}

	return child;
}

void BasicChildCollection::Remove( Mix::Tool::Dynamics::Design::BasicChild^ child )
{
	if( implBasic == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( child == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"child" );
	}

	if( m_List->Contains( child ) == false )
	{
		throw gcnew System::Exception( L"リストに存在しないチャイルドを削除しようとしました" );
	}

	/*
		選択の処理
	*/

	if( m_Selected == child )
	{
		int count = m_List->Count;

		if( count > 1 )
		{
			int index = m_List->IndexOf( child );

			if( index == ( m_List->Count - 1 ) )
			{
				//最後の場合は一つ前のシェイプを選択
				m_Selected = m_List[index - 1];
			}
			else
			{
				//最後ではない場合は、一つ後のシェイプを選択
				m_Selected = m_List[index + 1];
			}

			//選択を設定
			implBasic->Object_Selected( m_Selected->Win32Handle );
		}
		else
		{
			//最後の一つだった場合は選択を解除
			m_Selected = nullptr;

			//選択を解除
			implBasic->Object_Selected( NULL );
		}
	}

	/*
		解放
	*/

	m_List->Remove( child );
	delete child;
}

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// Basic
////////////////////////////////////////////////////////////////////////////////////////////////////

Basic::Basic( Mix::Tool::Win32::Dynamics::Design::Basic* _implBasic ) :
m_Childs( gcnew Mix::Tool::Dynamics::Design::BasicChildCollection( _implBasic ) )
{
	if( _implBasic == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_implBasic" );
	}
}

Basic::~Basic( void )
{
	if( m_Childs != nullptr )
	{
		delete m_Childs;
	}
}

Mix::Tool::Dynamics::Design::BasicChildCollection^ Basic::Childs::get( void )
{
	return m_Childs;
}

}}}}
