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

namespace Mix{ namespace Tool{ namespace Graphics{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Motion::CurveCollection
////////////////////////////////////////////////////////////////////////////////////////////////////

Motion::CurveCollection::CurveCollection( Mix::Tool::Win32::Graphics::Motion* implMotion ) :
m_List( gcnew System::Collections::Generic::List<Mix::Tool::Graphics::MotionCurve^>() ),
m_IndexDic( gcnew System::Collections::Generic::Dictionary<System::String^,int>() )
{
	for( unsigned int i = 0; i < implMotion->GetCurveCount(); i++ )
	{
		Mix::Tool::Win32::Graphics::MotionCurve* implCurve = implMotion->GetCurve( i );

		m_List->Add( gcnew Mix::Tool::Graphics::MotionCurve( implCurve ) );
		m_IndexDic->Add( gcnew System::String( implCurve->GetLinkNodeName() ), ( int )i );
	}
}

Motion::CurveCollection::~CurveCollection( void )
{
	m_IndexDic->Clear();

	if( m_List->Count > 0 )
	{
		for each ( Mix::Tool::Graphics::MotionCurve^ motCurve in m_List )
		{
			delete motCurve;
		}

		m_List->Clear();
	}
}

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

Mix::Tool::Graphics::MotionCurve^ Motion::CurveCollection::default::get( int index )
{
	return m_List[index];
}

Mix::Tool::Graphics::MotionCurve^ Motion::CurveCollection::default::get( System::String^ name )
{
	if( m_IndexDic->ContainsKey( name ) == false )
	{
		return nullptr;
	}

	return m_List[m_IndexDic[name]];
}

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// Motion
////////////////////////////////////////////////////////////////////////////////////////////////////

Motion::Motion( Mix::Tool::Win32::Graphics::Motion* _impl ) :
impl( _impl ),
m_Curves( gcnew Motion::CurveCollection( _impl ) )
{
}

Motion::~Motion( void )
{
	if( m_Curves != nullptr )
	{
		delete m_Curves;
	}

	if( impl != NULL )
	{
		impl->Destroy();
		impl = NULL;
	}
}

System::String^ Motion::DefaultName::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return gcnew System::String( impl->GetDefaultName() );
}

System::String^ Motion::Name::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return gcnew System::String( impl->GetName() );
}

void Motion::Name::set( System::String^ value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	pin_ptr<const wchar_t> wpValue = PtrToStringChars( value );

	impl->SetName( wpValue );
}

bool Motion::Assigned::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return impl->IsAssigned();
}

bool Motion::Default::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return impl->GetDefault();
}

void Motion::Default::set( bool value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	impl->SetDefault( value );
}

int Motion::LastTime::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return static_cast<int>( impl->GetLastTime() );
}

float Motion::BlendRatio::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return impl->GetBlendRatio();
}

void Motion::BlendRatio::set( float value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	impl->SetBlendRatio( value );
}

int Motion::LoopStartTime::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return static_cast<int>( impl->GetLoopStartTime() );
}

void Motion::LoopStartTime::set( int value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	impl->SetLoopStartTime( static_cast<float>( value ) );
}

int Motion::LoopEndTime::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return static_cast<int>( impl->GetLoopEndTime() );
}

void Motion::LoopEndTime::set( int value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	impl->SetLoopEndTime( static_cast<float>( value ) );
}

bool Motion::Loop::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return impl->GetLoop();
}

void Motion::Loop::set( bool value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	impl->SetLoop( value );
}

float Motion::Speed::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return impl->GetSpeed();
}

void Motion::Speed::set( float value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	impl->SetSpeed( value );
}

int Motion::Time::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return impl->GetTime();
}

void Motion::Time::set( int value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	if( impl->IsAssigned() == false )
	{
		throw gcnew System::Exception( "未分類のモーションでこの操作は行えません" );
	}

	impl->SetTime( value );
}

System::String^ Motion::SaveFilePath::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	return gcnew System::String( impl->GetSaveFilePath() );
}

void Motion::SaveFilePath::set( System::String^ value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	pin_ptr<const wchar_t> wpValue = PtrToStringChars( value );

	impl->SetSaveFilePath( wpValue );
}

MotionState Motion::State::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	MotionState ret;

	switch( impl->GetState() )
	{
	case Mix::Tool::Win32::Graphics::MOTION_PLAY:
		ret = MotionState::Play;
		break;
	case Mix::Tool::Win32::Graphics::MOTION_PAUSE:
		ret = MotionState::Pause;
		break;
	case Mix::Tool::Win32::Graphics::MOTION_STOP:
		ret = MotionState::Stop;
		break;
	}

	return ret;
}

Motion::CurveCollection^ Motion::Curves::get( void )
{
	return m_Curves;
}

Mix::Tool::Graphics::RootTransformFlags Motion::RootTransform::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	unsigned int flags = impl->GetRootTransformFlags();
	RootTransformFlags ret = RootTransformFlags::Init;

	if( ( flags & Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION ) == Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION )
	{
		ret = ret | RootTransformFlags::Rotation;
	}

	if( ( flags & Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION_XZ ) == Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION_XZ )
	{
		ret = ret | RootTransformFlags::TranslationXZ;
	}
	if( ( flags & Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION_Y ) == Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION_Y )
	{
		ret = ret | RootTransformFlags::TranslationY;
	}

	return ret;
}

void Motion::RootTransform::set( Mix::Tool::Graphics::RootTransformFlags value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	unsigned int flags = 0;

	if( ( value & RootTransformFlags::Rotation ) == RootTransformFlags::Rotation )
	{
		flags |= Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION;
	}

	if( ( value & RootTransformFlags::TranslationXZ ) == RootTransformFlags::TranslationXZ )
	{
		flags |= Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION_XZ;
	}
	if( ( value & RootTransformFlags::TranslationY ) == RootTransformFlags::TranslationY )
	{
		flags |= Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION_Y;
	}

	impl->SetRootTransformFlags( flags );
	impl->UpdateRootTransform();
}

void Motion::Play( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	if( impl->IsAssigned() == false )
	{
		throw gcnew System::Exception( "未分類のモーションでこの操作は行えません" );
	}

	impl->Play();
}

void Motion::Pause( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	if( impl->IsAssigned() == false )
	{
		throw gcnew System::Exception( "未分類のモーションでこの操作は行えません" );
	}

	impl->Pause();
}

void Motion::Stop( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException( L"モーションが初期化されていないか、既に解放されているため、この操作は行えません" );
	}

	if( impl->IsAssigned() == false )
	{
		throw gcnew System::Exception( "未分類のモーションでこの操作は行えません" );
	}

	impl->Stop();
}

}}}
