#include "Mix/Tool/CLR/Core/Graphics/Node.h"

#include "Mix/Tool/Win32/Core/Graphics/Mesh.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"

namespace Mix{ namespace Tool{ namespace Graphics{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Node::ChildCollection
////////////////////////////////////////////////////////////////////////////////////////////////////

Node::ChildCollection::ChildCollection( void ) :
m_List( gcnew System::Collections::Generic::List<Node^>() )
{
}

Node::ChildCollection::~ChildCollection( void )
{
	if( m_List->Count > 0 )
	{
		for each ( Mix::Tool::Graphics::Node^ node in m_List )
		{
			delete node;
		}

		m_List->Clear();
	}
}

void Node::ChildCollection::Add( Mix::Tool::Graphics::Node^ node )
{
	m_List->Add( node );
}

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

Mix::Tool::Graphics::Node^ Node::ChildCollection::default::get( int index )
{
	try
	{
		return m_List[index];
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

int Node::ChildCollection::IndexOfName( System::String^ name )
{
	int count = m_List->Count;

	for( int i = 0; i < count; i++ )
	{
		if( m_List[i]->Name->Equals( name ) == true )
		{
			return i;
		}
	}

	return -1;
}

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// Node::InternalBoundingBox
////////////////////////////////////////////////////////////////////////////////////////////////////

Node::InternalBoundingBox::InternalBoundingBox( Mix::Tool::Win32::Graphics::Node* _implNode, int depth ) : Mix::Tool::Dynamics::Design::BoundingBox( depth ),
implNode( _implNode ),
m_bAvailableDescend( false )
{
}

Node::InternalBoundingBox::InternalBoundingBox(	Mix::Tool::Win32::Graphics::BASE_SHAPE* _implBaseShape,
												Mix::Tool::Win32::Graphics::Node* _implNode,
												bool bAvailableDescend ) : Mix::Tool::Dynamics::Design::BoundingBox( _implBaseShape ),
implNode( _implNode ),
m_bAvailableDescend( bAvailableDescend )
{
}

Node::InternalBoundingBox::~InternalBoundingBox( void )
{
	implNode = NULL;
}

bool Node::InternalBoundingBox::IsAvailableDescend::get( void )
{
	return m_bAvailableDescend;
}

Mix::Tool::Dynamics::Design::BoundingBox^ Node::InternalBoundingBox::Descend( int depth )
{
	if( implNode == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( ( m_bAvailableDescend == false ) ||
		( ( m_bAvailableDescend == true ) && ( depth <= 0 ) ) )
	{
		return this;
	}

	try
	{
		Node::InternalBoundingBox^ convex = gcnew Node::InternalBoundingBox( implNode, depth );

		convex->Impl->name = implBoundingBox->name;
		convex->Impl->obb = implNode->GetObb( depth, false );

		return convex;
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Node::BoundingBoxCollection
////////////////////////////////////////////////////////////////////////////////////////////////////

Node::InternalBoundingBoxCollection::InternalBoundingBoxCollection( Mix::Tool::Win32::Graphics::Node* _implNode )
{
	if( _implNode == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_implNode" );
	}

	int count = _implNode->GetBaseShapeCount();

	for( int i = 0; i < count; i++ )
	{
		m_List->Add( gcnew Node::InternalBoundingBox( _implNode->GetBaseShapePtr( i ), _implNode, ( i == 0 ) ) );
	}
}

Node::InternalBoundingBoxCollection::~InternalBoundingBoxCollection( void )
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Node
////////////////////////////////////////////////////////////////////////////////////////////////////

Node::Node( Mix::Tool::Win32::Graphics::Node* _implNode ) :
implNode( _implNode ),
m_BoundingBoxes( gcnew Node::InternalBoundingBoxCollection( _implNode ) ),
m_DynamicsPartDesigner( nullptr ),
m_Childs( gcnew Node::ChildCollection() )
{
	Mix::Tool::Win32::Dynamics::Design::Part* implDynamicsDesigner = _implNode->GetDynamicsPartDesignerPtr();
	if( implDynamicsDesigner != NULL )
	{
		m_DynamicsPartDesigner = gcnew Mix::Tool::Dynamics::Design::Part( implDynamicsDesigner );
	}
}

Node::~Node( void )
{
	if( m_DynamicsPartDesigner != nullptr )
	{
		delete m_DynamicsPartDesigner;
	}

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

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

	implNode = NULL;
}

System::String^ Node::Name::get( void )
{
	return gcnew System::String( implNode->GetName() );
}

Node::ChildCollection^ Node::Childs::get( void )
{
	return m_Childs;
}

Mix::Tool::Dynamics::Design::BoundingBoxCollection^ Node::BoundingBoxes::get( void )
{
	return m_BoundingBoxes;
}

Mix::Tool::Dynamics::Design::Basic^ Node::DynamicsDesigner::get( void )
{
	return m_DynamicsPartDesigner;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// EmptyNode
////////////////////////////////////////////////////////////////////////////////////////////////////

EmptyNode::EmptyNode( Mix::Tool::Win32::Graphics::Node* _implNode ) : Node( _implNode )
{
}

EmptyNode::~EmptyNode( void )
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// MeshNode
////////////////////////////////////////////////////////////////////////////////////////////////////

MeshNode::MeshNode( Mix::Tool::Win32::Graphics::Node* _implNode, Mix::Tool::Graphics::MaterialSlotCollection^ ownerMaterialSlotCollection ) : Node( _implNode ),
implMesh( _implNode->GetMeshPtr() ),
m_MaterialSlotCollection( gcnew Mix::Tool::Graphics::MaterialSlotCollection() )
{
	if( implMesh != NULL )
	{
		try
		{
			for( unsigned int i = 0; i < implMesh->GetSubsetCount(); i++ )
			{
				unsigned int materialIndex = implMesh->GetMaterialSlotIndexBySubsetIndex( i );
				Mix::Tool::Graphics::MaterialSlot^ materialSlot = ownerMaterialSlotCollection[materialIndex];

				if( m_MaterialSlotCollection->ContainsNyName( materialSlot->Name ) == false )
				{
					m_MaterialSlotCollection->Add( materialSlot );
				}
			}
		}
		catch( System::Exception^ )
		{
			throw;
		}
	}
	else
	{
		throw gcnew System::ArgumentException( L"メッシュを所持していないノードはメッシュノードとして作成できません" );
	}
}

MeshNode::~MeshNode( void )
{
	if( m_MaterialSlotCollection != nullptr )
	{
		//Dispose してしまうと 描画オブジェクトのマテリアルを解放してしまうので、Clear で空にする
		m_MaterialSlotCollection->Clear();
	}

	implMesh = NULL;
}

Mix::Tool::Graphics::MaterialSlotCollection^ MeshNode::MaterialSlots::get( void )
{
	return m_MaterialSlotCollection;
}

unsigned int MeshNode::Key::get( void )
{
	if( implMesh == nullptr )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implMesh->GetKey();
}

unsigned int MeshNode::VertexCount::get( void )
{
	if( implMesh == nullptr )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implMesh->GetVertexCount();
}

unsigned int MeshNode::IndexCount::get( void )
{
	if( implMesh == nullptr )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implMesh->GetIndexCount();
}

unsigned int MeshNode::PolygonCount::get( void )
{
	if( implMesh == nullptr )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implMesh->GetPolygonCount();
}

bool MeshNode::Visible::get( void )
{
	if( implMesh == nullptr )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implMesh->GetVisible();
}

void MeshNode::Visible::set( bool value )
{
	if( implMesh != nullptr )
	{
		implMesh->SetVisible( value );
	}
	else
	{
		throw gcnew System::InvalidOperationException();
	}
}

Mix::Tool::Win32::Graphics::Mesh* MeshNode::ImplMesh::get( void )
{
	return implMesh;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// BoneNode
////////////////////////////////////////////////////////////////////////////////////////////////////

BoneNode::BoneNode( Mix::Tool::Win32::Graphics::Node* _implNode ) : Node( _implNode )
{
}

BoneNode::~BoneNode( void )
{
}

}}}
