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

#include "Mix/Tool/Win32/Core/Dynamics/Design/Actor.h"
#include "Mix/Tool/Win32/Core/Graphics/ObjectMesh.h"
#include "Mix/Tool/Win32/Core/Graphics/ObjectModel.h"

#include "Mix/Tool/CLR/Core/Dynamics/Design/Actor.h"
#include "Mix/Tool/CLR/Core/Graphics/MotionControllerCollection.h"
#include "Mix/Tool/CLR/Core/Graphics/RootTransform.h"

namespace Mix{ namespace Tool{ namespace Graphics{

////////////////////////////////////////////////////////////////////////////////////////////////////
// ObjectModel::ImportConfig
////////////////////////////////////////////////////////////////////////////////////////////////////

ObjectModel::ImportConfig::ImportConfig( void ) :
m_FilePath( gcnew System::String( L"" ) ),
m_Option( Mix::Tool::Graphics::ModelImportOption::Default ),
m_bSmooting( false ),
m_SmootingAngle( 45.0f ),
m_Scaling( 1.0f ),
m_Rotation( gcnew Mix::Tool::Math::Vector( 0.0f, 0.0f, 0.0f ) ),
m_Translation( gcnew Mix::Tool::Math::Vector( 0.0f, 0.0f, 0.0f ) ),
m_TimeModes( ObjectModel::TimeModes::Frames60 )
{
}

System::String^ ObjectModel::ImportConfig::FilePath::get( void )
{
	return gcnew System::String( m_FilePath->ToCharArray() );
}

void ObjectModel::ImportConfig::FilePath::set( System::String^ value )
{
	if( value != nullptr )
	{
		m_FilePath = gcnew System::String( value->ToCharArray() );
	}
	else
	{
		m_FilePath = gcnew System::String( L"" );
	}
}

Mix::Tool::Graphics::ModelImportOption ObjectModel::ImportConfig::Option::get( void )
{
	return m_Option;
}

void ObjectModel::ImportConfig::Option::set( Mix::Tool::Graphics::ModelImportOption value )
{
	m_Option = value;
}

float ObjectModel::ImportConfig::Scaling::get( void )
{
	return m_Scaling;
}

void ObjectModel::ImportConfig::Scaling::set( float value )
{
	m_Scaling = value;
}

Mix::Tool::Math::Vector^ ObjectModel::ImportConfig::Rotation::get( void )
{
	return gcnew Mix::Tool::Math::Vector( m_Rotation );
}

void ObjectModel::ImportConfig::Rotation::set( Mix::Tool::Math::Vector^ value )
{
	m_Rotation->X = value->X;
	m_Rotation->Y = value->Y;
	m_Rotation->Z = value->Z;
}

Mix::Tool::Math::Vector^ ObjectModel::ImportConfig::Translation::get( void )
{
	return gcnew Mix::Tool::Math::Vector( m_Translation );
}

void ObjectModel::ImportConfig::Translation::set( Mix::Tool::Math::Vector^ value )
{
	m_Translation->X = value->X;
	m_Translation->Y = value->Y;
	m_Translation->Z = value->Z;
}

bool ObjectModel::ImportConfig::Smooting::get( void )
{
	return m_bSmooting;
}

void ObjectModel::ImportConfig::Smooting::set( bool value )
{
	m_bSmooting = value;
}

float ObjectModel::ImportConfig::SmootingAngle::get( void )
{
	return m_SmootingAngle;
}

void ObjectModel::ImportConfig::SmootingAngle::set( float value )
{
	m_SmootingAngle = value;
}

ObjectModel::TimeModes ObjectModel::ImportConfig::TimeMode::get( void )
{
	return m_TimeModes;
}

void ObjectModel::ImportConfig::TimeMode::set( ObjectModel::TimeModes value )
{
	m_TimeModes = value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ObjectModel::InternalBoundingBox
////////////////////////////////////////////////////////////////////////////////////////////////////

ObjectModel::InternalBoundingBox::InternalBoundingBox( Mix::Tool::Win32::Graphics::BASE_SHAPE* _implBaseShape ) : BoundingBox( _implBaseShape )
{
}

ObjectModel::InternalBoundingBox::~InternalBoundingBox( void )
{
}

bool ObjectModel::InternalBoundingBox::IsAvailableDescend::get( void )
{
	return false;
}

Mix::Tool::Dynamics::Design::BoundingBox^ ObjectModel::InternalBoundingBox::Descend( int depth )
{
	throw gcnew System::InvalidOperationException( L"オブジェクトモデルでの操作は無効です" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ObjectModel::InternalBoundingBoxCollection
////////////////////////////////////////////////////////////////////////////////////////////////////

ObjectModel::InternalBoundingBoxCollection::InternalBoundingBoxCollection( void )
{
}

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

void ObjectModel::InternalBoundingBoxCollection::Initialize( Mix::Tool::Win32::Graphics::ObjectModel* _implObjModel )
{
	if( _implObjModel == NULL )
	{
		throw gcnew System::ArgumentNullException( L"_implObjModel" );
	}

	int count = _implObjModel->GetBaseShapeCount();

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// ObjectModel
////////////////////////////////////////////////////////////////////////////////////////////////////

ObjectModel::ObjectModel( void ) :
implObjectModel( new Mix::Tool::Win32::Graphics::ObjectModel() ),
m_UnassignedMotionCtrl( nullptr ),
m_MotionControllers( nullptr ),
m_RootTransform( nullptr ),
m_BoundingBoxes( nullptr ),
m_DynamicsDesigner( nullptr )
{
	if( implObjectModel == nullptr )
	{
		throw gcnew System::OutOfMemoryException();
	}

	implModel = implObjectModel;
	implDrawObject = implObjectModel;

	m_UnassignedMotionCtrl = gcnew Mix::Tool::Graphics::MotionController();
	m_MotionControllers = gcnew Mix::Tool::Graphics::MotionControllerCollection( implObjectModel );
	m_RootTransform = gcnew Mix::Tool::Graphics::RootTransform( implObjectModel );
	m_BoundingBoxes = gcnew ObjectModel::InternalBoundingBoxCollection();
	m_DynamicsDesigner = gcnew Mix::Tool::Dynamics::Design::Actor( implObjectModel->GetDynamicsActorDesignerPtr() );
}

ObjectModel::~ObjectModel( void )
{
	ReleaseNodeTree();

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

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

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

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

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

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

bool ObjectModel::Import( ObjectModel::ImportConfig^ config )
{
	if( implObjectModel == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	pin_ptr<const wchar_t> wpFilePath = PtrToStringChars( config->FilePath );
	Mix::Tool::Win32::Graphics::ObjectModel::IMPORT_CONFIG cfg;

	cfg.pFilePath = wpFilePath;

	cfg.opt = Model::ToWin32ImportOption( config->Option );

	cfg.scaling = config->Scaling;

	cfg.rotation.x = config->Rotation->X;
	cfg.rotation.y = config->Rotation->Y;
	cfg.rotation.z = config->Rotation->Z;

	cfg.translation.x = config->Translation->X;
	cfg.translation.y = config->Translation->Y;
	cfg.translation.z = config->Translation->Z;

	switch( config->TimeMode )
	{
	case ObjectModel::TimeModes::Frames30:
		cfg.motionTimeMode = Mix::Tool::Win32::Graphics::ObjectModel::TIME_MODE_FRAMES_30;
		break;

	case ObjectModel::TimeModes::Frames60:
		cfg.motionTimeMode = Mix::Tool::Win32::Graphics::ObjectModel::TIME_MODE_FRAMES_60;
		break;
	}

	cfg.bSmooting = config->Smooting;
	cfg.smootingAngle = config->SmootingAngle;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インポート
	////////////////////////////////////////////////////////////////////////////////////////////////////

	//インポート
	if( implObjectModel->Import( cfg ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルスロットコレクションを初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	DrawObject::InitializeMaterialSlotCollection();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノードツリーを初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Model::InitializeNodeTree();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// バウンディングボックスコレクションの初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_BoundingBoxes->Initialize( implObjectModel );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションの初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	//未割り当てのモーションコントローラー
	m_UnassignedMotionCtrl->Initialize( implObjectModel->GetUnassignedMotionController() );

	//割り当て済みのモーションコントローラー
	m_MotionControllers->Initialize();

	return true;
}

bool ObjectModel::ImportFinalize( void )
{
	return implObjectModel->ImportFinalize();
}

Mix::Tool::Graphics::MotionController^ ObjectModel::UnassignedMotionController::get( void )
{
	return m_UnassignedMotionCtrl;
}

Mix::Tool::Graphics::MotionControllerCollection^ ObjectModel::MotionControllers::get( void )
{
	return m_MotionControllers;
}

Mix::Tool::Graphics::RootTransform^ ObjectModel::RootTransform::get( void )
{
	return m_RootTransform;
}

void ObjectModel::ResetPose( void )
{
	if( implObjectModel == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	implObjectModel->ResetPose();
}

void ObjectModel::Jump( void )
{
	if( implObjectModel == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	implObjectModel->Jump();
}

bool ObjectModel::SaveMotions( void )
{
	if( implObjectModel == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implObjectModel->SaveMotions();
}

bool ObjectModel::SaveModel( void )
{
	if( implObjectModel == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return implObjectModel->SaveModel();
}

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

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

}}}
