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

namespace Mix{ namespace Tool{ namespace Graphics{

Model::Model( void ) :
implModel( NULL ),
m_RootNode( nullptr ),
m_SelectedNode( nullptr ),
m_SelectedMeshNode( nullptr ),
m_MeshNodeMap( gcnew System::Collections::Generic::Dictionary<unsigned int, Mix::Tool::Graphics::Node^>() )
{
}

Model::~Model( void )
{
	if( m_MeshNodeMap != nullptr )
	{
		m_MeshNodeMap->Clear();
		delete m_MeshNodeMap;
	}

	implModel = NULL;
}

System::String^ Model::ModelFilePath::get( void )
{
	return gcnew System::String( implModel->GetModelFilePath() );
}

void Model::ModelFilePath::set( System::String^ value )
{
	pin_ptr<const wchar_t> wpValue = PtrToStringChars( value );

	implModel->SetModelFilePath( wpValue );
}

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

Mix::Tool::Graphics::Node^ Model::RootNode::get( void )
{
	return m_RootNode;
}

Mix::Tool::Graphics::Node^ Model::SelectedNode::get( void )
{
	return m_SelectedNode;
}

void Model::SelectedNode::set( Mix::Tool::Graphics::Node^ value )
{
	m_SelectedNode = value;

	if( m_SelectedNode != nullptr )
	{
		if( Mix::Tool::Graphics::MeshNode::typeid->IsInstanceOfType( m_SelectedNode ) == true )
		{
			m_SelectedMeshNode = safe_cast<Mix::Tool::Graphics::MeshNode^>( m_SelectedNode );
		}
		else
		{
			m_SelectedMeshNode = nullptr;
		}

		implModel->SelectedNode( m_SelectedNode->implNode );
	}
	else
	{
		m_SelectedMeshNode = nullptr;
		implModel->SelectedNode( NULL );
	}
}

unsigned int Model::SelectedMeshKey::get( void )
{
	if( m_SelectedMeshNode == nullptr )
	{
		return 0;
	}

	return m_SelectedMeshNode->Key;
}

void Model::SelectedMeshKey::set( unsigned int value )
{
	if( m_MeshNodeMap->ContainsKey( value ) == true )
	{
		SelectedNode = m_MeshNodeMap[value];
	}
	else
	{
		SelectedNode = nullptr;
	}
}

void Model::InitializeNodeTree( void )
{
	if( implModel == NULL )
	{
		throw gcnew System::InvalidOperationException( L"内包モデル( implModel )が NULL です" );
	}

	if( implModel->GetRootNode() == NULL )
	{
		throw gcnew System::InvalidOperationException( L"内包モデル( implModel )にノードが存在しません" );
	}

	m_RootNode = BuildNodeTree( implModel->GetRootNode() );
}

void Model::ReleaseNodeTree( void )
{
	if( m_RootNode != nullptr )
	{
		delete m_RootNode;
		m_RootNode = nullptr;
	}
}

Mix::Tool::Win32::Graphics::Model::IMPORT_OPTION_TYPE Model::ToWin32ImportOption( Mix::Tool::Graphics::ModelImportOption opt )
{
	Mix::Tool::Win32::Graphics::Model::IMPORT_OPTION_TYPE ret;

	switch( opt )
	{
	case Mix::Tool::Graphics::ModelImportOption::Default:
		ret = Mix::Tool::Win32::Graphics::Model::IO_DEFAULT;
		break;
	case Mix::Tool::Graphics::ModelImportOption::FBX_Maya:
		ret = Mix::Tool::Win32::Graphics::Model::IO_FBX_MAYA;
		break;
	case Mix::Tool::Graphics::ModelImportOption::FBX_3DStudioMax:
		ret = Mix::Tool::Win32::Graphics::Model::IO_FBX_3D_STUDIO_MAX;
		break;

	default:
		throw gcnew System::Exception( L"サポートされていないモデルのインポートオプションを変換しようとしました" );
		break;
	}

	return ret;
}

Mix::Tool::Graphics::Node^ Model::BuildNodeTree( Mix::Tool::Win32::Graphics::Node* implNode )
{
	if( implNode == NULL )
	{
		throw gcnew System::ArgumentNullException( L"implNode" );
	}

	try
	{
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// ルートノードの作成
		////////////////////////////////////////////////////////////////////////////////////////////////////

		Mix::Tool::Graphics::Node^ rootNode = CreateNode( implNode );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 子を処理
		////////////////////////////////////////////////////////////////////////////////////////////////////

		for( int i = 0; i < implNode->GetChildCount(); i++ )
		{
			BuildNodeTree( rootNode, implNode->GetChildPtr( i ) );
		}

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

void Model::BuildNodeTree( Mix::Tool::Graphics::Node^ parentNode, Mix::Tool::Win32::Graphics::Node* implNode )
{
	if( parentNode == nullptr )
	{
		throw gcnew System::ArgumentNullException( L"parentNode" );
	}

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

	try
	{
		Mix::Tool::Graphics::Node^ node = CreateNode( implNode );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 親に子を追加
		////////////////////////////////////////////////////////////////////////////////////////////////////

		parentNode->Childs->Add( node );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 子を処理
		////////////////////////////////////////////////////////////////////////////////////////////////////

		for( int i = 0; i < implNode->GetChildCount(); i++ )
		{
			BuildNodeTree( node, implNode->GetChildPtr( i ) );
		}
	}
	catch( System::Exception^ )
	{
		throw;
	}
}

Mix::Tool::Graphics::Node^ Model::CreateNode( Mix::Tool::Win32::Graphics::Node* implNode )
{
	if( implNode == NULL )
	{
		throw gcnew System::ArgumentNullException( L"implNode" );
	}

	Mix::Tool::Graphics::Node^ node = nullptr;

	switch( implNode->GetAttribute() )
	{
	case Mix::Tool::Win32::Graphics::Node::EMPTY:
		node = gcnew Mix::Tool::Graphics::EmptyNode( implNode );
		break;
	case Mix::Tool::Win32::Graphics::Node::MESH:
		node = gcnew Mix::Tool::Graphics::MeshNode( implNode, MaterialSlots );
		if( implNode->GetMeshPtr()->GetKey() > 0 )
		{
			m_MeshNodeMap->Add( implNode->GetMeshPtr()->GetKey(), node );
		}
		break;
	case Mix::Tool::Win32::Graphics::Node::BONE:
		node = gcnew Mix::Tool::Graphics::BoneNode( implNode );
		break;

	default:
		node = gcnew Mix::Tool::Graphics::EmptyNode( implNode );
		break;
	}

	return node;
}

}}}
