#include "Mix/Private/Scene/Common/MotionController.h"

#include "Mix/Scene/IMotionListener.h"

#include "Mix/Private/Scene/Common/ActorModel.h"
#include "Mix/Private/Scene/Common/MotionMixer.h"
#include "Mix/Private/Scene/Common/RootMotionCurve.h"
#include "Mix/Private/Scene/Common/MotionCurve.h"
#include "Mix/Private/Scene/Common/Motion.h"
#include "Mix/Private/Scene/Common/MotionState.h"
#include "Mix/Private/Scene/Common/MotionDeformer.h"
#include "Mix/Private/Scene/Common/MotionEntryProcesser.h"

#include <queue>

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* MotionController::FAILED_CREATE = L"モーションコントローラーの作成に失敗";

////////////////////////////////////////////////////////////////////////////////////////////////////
// MotionController
////////////////////////////////////////////////////////////////////////////////////////////////////

MotionController* MotionController::CreateInstance(	Mix::Scene::Common::ActorModel* pModel,
													Mix::Scene::Common::MotionMixer* pMixer,
													const wchar_t* pName,
													UInt32 priority )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, MotionController, pModel, pMixer, pName, priority );
}

MotionController::MotionController(	Mix::Scene::Common::ActorModel* pModel,
									Mix::Scene::Common::MotionMixer* pMixer,
									const wchar_t* pName,
									UInt32 priority ) :
m_pModel( pModel ),
m_pMixer( pMixer ),
m_Name( pName ),
m_Priority( priority ),
m_Action( MotionController::ACTION_QUEUEING ),
m_TransitionFramesInv( 1.0f ),
m_TransitionFrame( 1.0f ),
m_TransitionRatio( 1.0f )
{
	for( UInt32 i = 0; i < MotionController::MOTION_MAX; i++ )
	{
		m_MotionTable[i] = NULL;
	}

#ifdef _DEBUG

	Mix::String debugName;

	debugName.Sprintf( L"%s/%s", pModel->GetName(), pName );
	m_CommandQueue.Initialize( MotionController::COMANND_DEF_CAPACITY, MotionController::COMANND_RESIZE_STEP, debugName.GetConstPtr() );

#else //_DEBUG

	m_CommandQueue.Initialize( MotionController::COMANND_DEF_CAPACITY, MotionController::COMANND_RESIZE_STEP );

#endif //_DEBUG
}

MotionController::~MotionController( void )
{
	for( MotionController::MotionMap::iterator it = m_MotionMap.begin(); it != m_MotionMap.end(); ++it )
	{
		MotionController::MOTION* pMotion = &( it->second );

		if( pMotion->pState != NULL )
		{
			pMotion->pState->Dispose();
		}

		MIX_RELEASE( pMotion->pInterface );
		MIX_RELEASE( pMotion->pState );
		MIX_RELEASE( pMotion->pDeformer );
		MIX_RELEASE( pMotion->pEntryProcesser );
		MIX_RELEASE( pMotion->pListener );
	}
}

const wchar_t* MotionController::GetName( void ) const
{
	return m_Name.GetConstPtr();
}

UInt32 MotionController::GetPriority( void ) const
{
	return m_Priority;
}

UInt32 MotionController::GetHandleCount( void ) const
{
	return MIX_UIT_TO_UI32( m_HandleMap.size() );
}

Mix::Scene::MOTION_HANDLE MotionController::GetHandleByIndex( UInt32 index ) const
{
	if( m_HandleMap.size() <= index )
	{
		return MOTION_HANDLE();
	}

	MotionController::HandleMap::const_iterator it_h = m_HandleMap.begin();

	for( UInt32 i = 0; i < index; i++ )
	{
		it_h++;
	}

	return it_h->second;
}

Mix::Scene::MOTION_HANDLE MotionController::GetHandleByName( const wchar_t* pName ) const
{
	if( ( pName == NULL ) ||
		( ::wcslen( pName ) == 0 ) )
	{
		return MOTION_HANDLE();
	}

	MotionController::HandleMap::const_iterator it_h = m_HandleMap.find( pName );
	if( it_h == m_HandleMap.end() )
	{
		return MOTION_HANDLE();
	}

	return it_h->second;
}

Mix::Scene::MOTION_HANDLE MotionController::Add( Mix::Scene::IMotion* pMotion )
{
	if( pMotion == NULL )
	{
		return NULL;
	}

	MotionController::HandleMap::iterator it = m_HandleMap.find( pMotion->GetName() );
	if( it != m_HandleMap.end() )
	{
		return NULL;
	}

	Mix::Scene::MOTION_HANDLE handle = ProcAdd( static_cast<Mix::Scene::Common::Motion*>( pMotion ) );
	if( handle != NULL )
	{
		MIX_ADD_REF( pMotion );
	}
	else
	{
		return NULL;
	}

	return handle;
}

Boolean MotionController::Remove( const Mix::Scene::MOTION_HANDLE& handle )
{
	MotionController::MotionMap::iterator it_m = m_MotionMap.find( handle );
	if( it_m == m_MotionMap.end() )
	{
		return False;
	}

	MotionController::HandleMap::iterator it_h = m_HandleMap.find( it_m->second.pInterface->GetName() );
	if( it_h == m_HandleMap.end() )
	{
		return False;
	}

	MotionController::MOTION* pMotion = &( it_m->second );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションテーブルからはずす
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( m_MotionTable[MotionController::MOTION_PREVIOUS] != NULL ) &&
		( m_MotionTable[MotionController::MOTION_PREVIOUS]->handle == handle ) )
	{
		m_MotionTable[MotionController::MOTION_PREVIOUS] = NULL;
	}
	else if(	( m_MotionTable[MotionController::MOTION_CURRENT] != NULL ) &&
				( m_MotionTable[MotionController::MOTION_CURRENT]->handle == handle ) )
	{
		m_MotionTable[MotionController::MOTION_PREVIOUS] = NULL;
		m_MotionTable[MotionController::MOTION_CURRENT] = NULL;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 解放
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pMotion->pState != NULL )
	{
		pMotion->pState->Dispose();
	}

	MIX_RELEASE( pMotion->pInterface );
	MIX_RELEASE( pMotion->pState );
	MIX_RELEASE( pMotion->pDeformer );
	MIX_RELEASE( pMotion->pEntryProcesser );
	MIX_RELEASE( pMotion->pListener );

	m_MotionMap.erase( it_m );
	m_HandleMap.erase( it_h );

	return True;
}

Boolean MotionController::Get( const Mix::Scene::MOTION_HANDLE& handle, Mix::Scene::IMotion** ppMotion )
{
	MotionController::MotionMap::iterator it_m = m_MotionMap.find( handle );
	if( it_m == m_MotionMap.end() )
	{
		return False;
	}

	MIX_ADD_REF( it_m->second.pInterface );
	( *ppMotion ) = it_m->second.pInterface;

	return True;
}

Boolean MotionController::GetState( const Mix::Scene::MOTION_HANDLE& handle, Mix::Scene::IMotionState** ppMotionState )
{
	if( ppMotionState == NULL )
	{
		return False;
	}

	MotionController::MotionMap::iterator it_m = m_MotionMap.find( handle );
	if( it_m == m_MotionMap.end() )
	{
		return False;
	}

	MotionState* pState = it_m->second.pState;

	MIX_ADD_REF( pState );
	( *ppMotionState ) = pState;

	return True;
}

void MotionController::SetListener( Mix::Scene::IMotionListener* pListener )
{
	MotionController::MotionMap::iterator it_begin = m_MotionMap.begin();
	MotionController::MotionMap::iterator it_end = m_MotionMap.end();
	MotionController::MotionMap::iterator it;

	MIX_ADD_REF( pListener );

	for( it = it_begin; it != it_end; ++it )
	{
		MotionController::MOTION* pMotion = &( it->second );

		MIX_RELEASE( pMotion->pListener );
		pMotion->pListener = pListener;

		pMotion->pEntryProcesser->SetListener( pListener );
	}
}

Boolean MotionController::SetListener( const Mix::Scene::MOTION_HANDLE& handle, Mix::Scene::IMotionListener* pListener )
{
	MotionController::MotionMap::iterator it = m_MotionMap.find( handle );
	if( it == m_MotionMap.end() )
	{
		return False;
	}

	MotionController::MOTION* pMotion = &( it->second );

	MIX_ADD_REF( pListener );
	MIX_RELEASE( pMotion->pListener );
	pMotion->pListener = pListener;

	pMotion->pEntryProcesser->SetListener( pListener );

	return True;
}

void MotionController::SendCommand( Mix::Scene::MOTION_COMMAND_EXECUTE_TYPE exeType, const Mix::Scene::MOTION_COMMAND& com )
{
	if( exeType != Mix::Scene::MOTION_CE_DEFAULT )
	{
		m_CommandQueue.Drain();
	}

	if( ( m_CommandQueue.GetCount() > 0 ) &&
		( m_CommandQueue.GetTail().handle == com.handle ) )
	{
		//最後と一緒だった場合は、上書き
		m_CommandQueue[m_CommandQueue.GetTailIndex()] = com;
	}
	else
	{
		m_CommandQueue.Enqueue( com );
	}

	if( exeType == Mix::Scene::MOTION_CE_FORCE )
	{
		m_Action = MotionController::ACTION_QUEUEING;
	}
}

UInt32 MotionController::GetCommandCount( void ) const
{
	return m_CommandQueue.GetCount();
}

void MotionController::OnRootTransform( Mix::ContainerT<Mix::Scene::Common::MOTION_ROOT_BLEND, Mix::Memory::SECTION_SCENE>& list )
{
	MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];
	if( pCurMotion == NULL )
	{
		return;
	}

	MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];

	if( ( ( pPreMotion != NULL ) && ( pPreMotion->pInterface->GetRootCurvePtr()->IsAvailable() == True ) ) ||
		( pCurMotion->pInterface->GetRootCurvePtr()->IsAvailable() == True ) )
	{
		Motion* pInterface;
		MotionState* pState;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 直前のモーション
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( pPreMotion != NULL )
		{
			pInterface = pPreMotion->pInterface;
			pState = pPreMotion->pState;

			pInterface->GetRootCurvePtr()->Execute(	pInterface->GetBlendRatio() * pState->GetBlendRatio(),
													pPreMotion->preFrame,
													pState->GetFrame(),
													list );
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 現在のモーション
		////////////////////////////////////////////////////////////////////////////////////////////////////

		pInterface = pCurMotion->pInterface;
		pState = pCurMotion->pState;

		pInterface->GetRootCurvePtr()->Execute(	pInterface->GetBlendRatio() * pState->GetBlendRatio() * m_TransitionRatio,
												pCurMotion->preFrame,
												pState->GetFrame(),
												list );
	}
}

void MotionController::OnBodyTransform( Mix::ContainerT<Mix::Scene::Common::MOTION_BODY_BLEND, Mix::Memory::SECTION_SCENE>& list )
{
	if( m_MotionTable[MotionController::MOTION_CURRENT] == NULL )
	{
		return;
	}

	MotionController::MOTION* pMotion;
	MotionState* pState;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 直前のモーション
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	pMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];

	if( pMotion != NULL )
	{
		pState = pMotion->pState;

		pMotion->pDeformer->Execute(	pMotion->pInterface->GetBlendRatio() * pState->GetBlendRatio(),
										pState->GetFrame(),
										list );
	}

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 現在のモーション
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	pMotion = m_MotionTable[MotionController::MOTION_CURRENT];
	pState = pMotion->pState;

	pMotion->pDeformer->Execute(	pMotion->pInterface->GetBlendRatio() * pState->GetBlendRatio() * m_TransitionRatio,
									pState->GetFrame(),
									list );
}

void MotionController::OnUpdate( Float32 dt )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// アクションの処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_Action == MotionController::ACTION_QUEUEING )
	{
		//コマンドのキューイング
		if( m_CommandQueue.GetCount() > 0 )
		{
			Mix::Scene::MOTION_COMMAND com = m_CommandQueue.Dequeue();

			if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_ACTIVATE ) == Mix::Scene::MOTION_CF_ACTIVATE )
			{
				//再生
				MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];

				if( ( pCurMotion == NULL ) ||
					( pCurMotion->handle != com.handle ) )
				{
					MotionController::MotionMap::iterator it = m_MotionMap.find( com.handle );
					if( it != m_MotionMap.end() )
					{
						MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];
						MotionController::MOTION* pNextMotion = &( it->second );

						if( ( pPreMotion != NULL ) &&
							( pPreMotion->handle == pNextMotion->handle ) )
						{
							//PREVIOUS と同じモーションを再生しようとしている場合( PREVIOUS の停止は行わない )

							//モーションテーブルの設定
							m_MotionTable[MotionController::MOTION_PREVIOUS] = pCurMotion;
							m_MotionTable[MotionController::MOTION_CURRENT] = pNextMotion;

							//モーション( CURRENT ) : ステートの設定
							if( pNextMotion->state == MotionController::MS_STOP )
							{
								pNextMotion->state = MotionController::MS_PLAY;
							}

							//モーション( CURRENT ) : ループの設定
							if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP ) == Mix::Scene::MOTION_CF_LOOP )
							{
								if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP_INHERIT ) != Mix::Scene::MOTION_CF_LOOP_INHERIT )
								{
									pNextMotion->pState->SetLoopCount( com.loopCount );
								}
							}
							else
							{
								pNextMotion->pState->SetLoopCount( 0 );
							}

							//モーション( CURRENT ) : フレームの設定
							if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME ) == Mix::Scene::MOTION_CF_FRAME )
							{
								if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME_INHERIT ) != Mix::Scene::MOTION_CF_FRAME_INHERIT )
								{
									pNextMotion->preFrame = com.frame;
									pNextMotion->pState->SetFrame( com.frame );
								}
							}
							else
							{
								pNextMotion->preFrame = -1.0f;
								pNextMotion->pState->SetFrame( 0.0f );
							}

							//トランジションの設定
							if( ( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_TRANSITION ) == Mix::Scene::MOTION_CF_TRANSITION ) &&
								( MIX_FLOAT_IS_ZERO( com.transitionTimeLength ) == False ) )
							{
								Float32 fps = pNextMotion->pInterface->GetFramesPerSec();

								if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_TRANSITION_INHERIT ) == Mix::Scene::MOTION_CF_TRANSITION_INHERIT )
								{
									//PREVIOUS を引き継ぐ
									Float32 ratio = MIX_FLOAT_SATURATE( 1.0f - m_TransitionRatio );
									Float32 elapsedTime = com.transitionTimeLength * ratio;

									m_TransitionFramesInv = MIX_FLOAT_RECIPROCAL( com.transitionTimeLength * fps );
									m_TransitionFrame = elapsedTime * fps;
									m_TransitionRatio = ratio;
								}
								else
								{
									//PREVIOUS を引き継がない
									m_TransitionFramesInv = MIX_FLOAT_RECIPROCAL( com.transitionTimeLength * fps );
									m_TransitionFrame = 0.0f;
									m_TransitionRatio = 0.0f;
								}
							}
							else
							{
								m_TransitionFramesInv = 1.0f;
								m_TransitionFrame = 1.0f;
								m_TransitionRatio = 1.0f;
							}

							//アクションの設定
							m_Action = MotionController::ACTION_FADEIN;
						}
						else
						{
							//PREVIOUS CURRENT とも違う新しいモーションを再生しようとしている場合

							//モーション( PREVIOUS ) の停止
							Stop( pPreMotion );

							//モーションテーブルの設定
							m_MotionTable[MotionController::MOTION_PREVIOUS] = pCurMotion;
							m_MotionTable[MotionController::MOTION_CURRENT] = pNextMotion;

							//モーション( CURRENT ) : ステートの設定
							pNextMotion->state = MotionController::MS_PLAY;

							//モーション( CURRENT ) : ループの設定
							if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP ) == Mix::Scene::MOTION_CF_LOOP )
							{
								pNextMotion->pState->SetLoopCount( com.loopCount );
							}
							else
							{
								pNextMotion->pState->SetLoopCount( 0 );
							}

							//モーション( CURRENT ) : フレームの設定
							if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME ) == Mix::Scene::MOTION_CF_FRAME )
							{
								pNextMotion->preFrame = com.frame;
								pNextMotion->pState->SetFrame( com.frame );
							}
							else
							{
								pNextMotion->preFrame = -1.0f;
								pNextMotion->pState->SetFrame( 0.0f );
							}

							//トランジションの設定
							if( ( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_TRANSITION ) == Mix::Scene::MOTION_CF_TRANSITION ) &&
								( MIX_FLOAT_IS_ZERO( com.transitionTimeLength ) == False ) )
							{
								m_TransitionFramesInv = MIX_FLOAT_RECIPROCAL( com.transitionTimeLength * pNextMotion->pInterface->GetFramesPerSec() );
								m_TransitionFrame = 0.0f;
								m_TransitionRatio = 0.0f;
							}
							else
							{
								m_TransitionFramesInv = 1.0f;
								m_TransitionFrame = 1.0f;
								m_TransitionRatio = 1.0f;
							}

							//アクションの設定
							m_Action = MotionController::ACTION_FADEIN;
						}
					}
				}
				else
				{
					//CURRENT と同じモーションを再生しようとしている場合
					//
					//無限ループではなく、最後のフレームに到達している状態で「ループ数」を引き継ぐ設定をしている場合は、
					//一度再生状態にはなるがすぐに停止状態になる。

					//モーション( CURRENT ) : ステートの設定
					if( pCurMotion->state == MotionController::MS_STOP )
					{
						pCurMotion->state = MotionController::MS_PLAY;
					}

					//モーション( CURRENT ) : ループの設定
					if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP ) == Mix::Scene::MOTION_CF_LOOP )
					{
						if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP_INHERIT ) != Mix::Scene::MOTION_CF_LOOP_INHERIT )
						{
							pCurMotion->pState->SetLoopCount( com.loopCount );
						}
					}
					else
					{
						pCurMotion->pState->SetLoopCount( 0 );
					}

					//モーション( CURRENT ) : フレームの設定
					if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME ) == Mix::Scene::MOTION_CF_FRAME )
					{
						if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME_INHERIT ) != Mix::Scene::MOTION_CF_FRAME_INHERIT )
						{
							pCurMotion->preFrame = com.frame;
							pCurMotion->pState->SetFrame( com.frame );
						}
					}
					else
					{
						pCurMotion->preFrame = -1.0f;
						pCurMotion->pState->SetFrame( 0.0f );
					}

					//トランジション : 設定
					if( ( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_TRANSITION ) == Mix::Scene::MOTION_CF_TRANSITION ) &&
						( MIX_FLOAT_IS_ZERO( com.transitionTimeLength ) == False ) )
					{
						Float32 fps = pCurMotion->pInterface->GetFramesPerSec();

						if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_TRANSITION_INHERIT ) == Mix::Scene::MOTION_CF_TRANSITION_INHERIT )
						{
							m_TransitionFramesInv = MIX_FLOAT_RECIPROCAL( com.transitionTimeLength * fps );
							m_TransitionFrame = com.transitionTimeLength * m_TransitionRatio * fps;
						}
						else
						{
							m_TransitionFramesInv = MIX_FLOAT_RECIPROCAL( com.transitionTimeLength * fps );
							m_TransitionFrame = 0.0f;
							m_TransitionRatio = 0.0f;
						}
					}
					else
					{
						m_TransitionFramesInv = 1.0f;
						m_TransitionFrame = 1.0f;
						m_TransitionRatio = 1.0f;
					}

					//アクションの設定
					m_Action = MotionController::ACTION_FADEIN;
				}
			}
			else
			{
				//停止
				MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];

				if( pCurMotion != NULL )
				{
					MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];

					//モーション( PREVIOUS ) の停止
					Stop( pPreMotion );

					//モーションテーブルの設定
					m_MotionTable[MotionController::MOTION_PREVIOUS] = NULL;

					//モーション( CURRENT ) : ループの設定
					if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP ) == Mix::Scene::MOTION_CF_LOOP )
					{
						pCurMotion->pState->SetLoopCount( com.loopCount );
					}

					//モーション( CURRENT ) : フレームの設定
					if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME ) == Mix::Scene::MOTION_CF_FRAME )
					{
						pCurMotion->preFrame = com.frame;
						pCurMotion->pState->SetFrame( com.frame );
					}

					//トランジションの設定
					if( ( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_TRANSITION ) == Mix::Scene::MOTION_CF_TRANSITION ) &&
						( MIX_FLOAT_IS_ZERO( com.transitionTimeLength ) == False ) )
					{
						Float32 fps = pCurMotion->pInterface->GetFramesPerSec();
						Float32 ratio = MIX_FLOAT_SATURATE( 1.0f - m_TransitionRatio );

						m_TransitionFramesInv = MIX_FLOAT_RECIPROCAL( com.transitionTimeLength * fps );
						m_TransitionFrame = com.transitionTimeLength * ratio * fps;
					}
					else
					{
						m_TransitionFramesInv = 1.0f;
						m_TransitionFrame = 1.0f;
						m_TransitionRatio = 0.0f;
					}

					//アクションの設定
					m_Action = MotionController::ACTION_FADEOUT;
				}
			}
		}
	}

	if( m_Action != MotionController::ACTION_QUEUEING )
	{
		//トランジション
		MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];
		if( pCurMotion != NULL )
		{
			Motion* pCurInterface = pCurMotion->pInterface;
			Float32 curFrameStep = pCurInterface->GetFramesPerSec() * dt * ( pCurInterface->GetSpeed() * pCurMotion->pState->GetSpeed() );

			if( m_Action == MotionController::ACTION_FADEIN )
			{
				MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];
				MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];

				MIX_ASSERT( pCurMotion != NULL );

				//フェードイン
				m_TransitionFrame += curFrameStep;
				m_TransitionRatio = m_TransitionFrame * m_TransitionFramesInv;

				if( m_TransitionRatio >= 1.0f )
				{
					//モーション( PREVIOUS ) の停止
					Stop( m_MotionTable[MotionController::MOTION_PREVIOUS] );

					//モーションテーブルの設定
					m_MotionTable[MotionController::MOTION_PREVIOUS] = NULL;

					m_TransitionRatio = 1.0f;
					m_Action = MotionController::ACTION_QUEUEING;
				}
				else
				{
					if( pPreMotion != NULL )
					{
						pPreMotion->pState->SetTransitionRatio( 1.0f - m_TransitionRatio );
					}
				}

				pCurMotion->pState->SetTransitionRatio( m_TransitionRatio );
			}
			else if( m_Action == MotionController::ACTION_FADEOUT )
			{
				MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];

				MIX_ASSERT( pCurMotion != NULL );

				//フェードアウト
				m_TransitionFrame += curFrameStep;
				m_TransitionRatio = 1.0f - ( m_TransitionFrame * m_TransitionFramesInv );

				if( m_TransitionRatio <= 0.0f )
				{
					//モーション( CURRENT ) の停止
					Stop( pCurMotion );

					//モーションテーブルの設定
					m_MotionTable[MotionController::MOTION_CURRENT] = NULL;

					m_TransitionRatio = 0.0f;
					m_Action = MotionController::ACTION_QUEUEING;
				}
				else
				{
					pCurMotion->pState->SetTransitionRatio( m_TransitionRatio );
				}
			}
		}
		else
		{
			m_Action = MotionController::ACTION_QUEUEING;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションの処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( UInt32 i = 0; i < MotionController::MOTION_MAX; i++ )
	{
		MotionController::MOTION* pMotion = m_MotionTable[i];
		if( pMotion == NULL )
		{
			continue;
		}

		if( pMotion->state == MotionController::MS_PLAY )
		{
			//エントリー通知のリセット
			pMotion->pEntryProcesser->ResetNotify();

			//再生開始の誘致
			if( pMotion->pListener != NULL )
			{
				pMotion->pListener->OnActivate( pMotion->pInterface, pMotion->handle, True );
			}

			pMotion->state = MotionController::MS_PLAYING;
		}
		else if( pMotion->state == MotionController::MS_PLAYING )
		{
			Motion* pInterface = pMotion->pInterface;
			MotionState* pState = pMotion->pState;
			Float32 frameStep = pInterface->GetFramesPerSec() * dt * ( pInterface->GetSpeed() * pMotion->pState->GetSpeed() );
			Float32 frame = pMotion->pState->GetFrame();
			UInt32 loopCount = pState->GetLoopCount();

			pMotion->preFrame = frame;
			frame += frameStep;

			if( loopCount > 0 )
			{
				Float32 startFrame = pInterface->GetLoopStartFrame();
				Float32 endFrame = pInterface->GetLoopEndFrame();

				if( endFrame < frame )
				{
					Float32 frameLength = endFrame - startFrame;

					//長い時間処理がブロックされてしまった際の対策
					if( MIX_FLOAT_IS_ZERO( frameLength ) == True )
					{
						frame = 0.0f;
					}
					else
					{
						do { frame -= frameLength; } while( endFrame < frame );
					}

					//ループ処理
					if( loopCount != Mix::Scene::MOTION_INFINITE_LOOP )
					{
						loopCount--;

						//ループカウントの設定
						pState->SetLoopCount( loopCount );
					}

					//エントリーの通知
					pMotion->pEntryProcesser->Notify( pMotion->preFrame, endFrame );
					pMotion->pEntryProcesser->ResetNotify();
					pMotion->pEntryProcesser->Notify( startFrame, frame );
				}
				else
				{
					//エントリーの通知
					pMotion->pEntryProcesser->Notify( pMotion->preFrame, frame );
				}
			}
			else
			{
				Float32 lastFrame = pInterface->GetLastFrame();

				//フレームの設定
				if( lastFrame < frame )
				{
					frame = lastFrame;

					Stop( pMotion );
				}

				//エントリーの通知
				pMotion->pEntryProcesser->Notify( pMotion->preFrame, frame );
			}

			//フレームの設定
			pMotion->pState->SetFrame( frame );
		}
	}
}

void MotionController::OnReset( void )
{
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// フェードの終了処理
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_Action != MotionController::ACTION_QUEUEING )
	{
		MIX_ASSERT( ( m_Action == MotionController::ACTION_FADEIN ) || ( m_Action == MotionController::ACTION_FADEOUT ) );

		//トランジション
		if( m_MotionTable[MotionController::MOTION_CURRENT] != NULL )
		{
			if( m_Action == MotionController::ACTION_FADEIN )
			{
				//フェードイン
				m_TransitionFrame = MIX_FLOAT_RECIPROCAL( m_TransitionFramesInv );
				m_TransitionRatio = 1.0f;

				//直前のモーション - 停止
				Stop( m_MotionTable[MotionController::MOTION_PREVIOUS] );
				m_MotionTable[MotionController::MOTION_PREVIOUS] = NULL;

				//現在のモーション - 再生
				m_MotionTable[MotionController::MOTION_CURRENT]->pState->SetTransitionRatio( 1.0f );
			}
			else if( m_Action == MotionController::ACTION_FADEOUT )
			{
				//フェードアウト
				m_TransitionFrame = MIX_FLOAT_RECIPROCAL( m_TransitionFramesInv );
				m_TransitionRatio = 0.0f;

				//現在のモーション - 停止
				Stop( m_MotionTable[MotionController::MOTION_CURRENT] );
				m_MotionTable[MotionController::MOTION_CURRENT] = NULL;
			}
		}

		m_Action = MotionController::ACTION_QUEUEING;
	}

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// キューイング
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	while( m_CommandQueue.IsEmpty() == False )
	{
		MIX_ASSERT( m_Action == MotionController::ACTION_QUEUEING );

		Mix::Scene::MOTION_COMMAND com = m_CommandQueue.Dequeue();
	
		if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_ACTIVATE ) == Mix::Scene::MOTION_CF_ACTIVATE )
		{
			//再生
			MotionController::MotionMap::iterator it = m_MotionMap.find( com.handle );

			if( it != m_MotionMap.end() )
			{
				MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];
				MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];
				MotionController::MOTION* pNextMotion = &( it->second );

				//直前のモーション - 停止
				Stop( pPreMotion );
				m_MotionTable[MotionController::MOTION_PREVIOUS] = pCurMotion;

				//現在のモーション - 再生
				m_MotionTable[MotionController::MOTION_CURRENT] = pNextMotion;

				//現在のモーション - ステートの設定
				pNextMotion->state = MotionController::MS_PLAY;

				//現在のモーション - ループの設定
				if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_LOOP ) == Mix::Scene::MOTION_CF_LOOP )
				{
					pNextMotion->pState->SetLoopCount( com.loopCount );
				}
				else
				{
					pNextMotion->pState->SetLoopCount( 0 );
				}

				//現在のモーション - フレームの設定
				if( MIX_TESTBIT( com.flags, Mix::Scene::MOTION_CF_FRAME ) == Mix::Scene::MOTION_CF_FRAME )
				{
					pNextMotion->preFrame = com.frame;
					pNextMotion->pState->SetFrame( com.frame );
				}
				else
				{
					pNextMotion->preFrame = -1.0f;
					pNextMotion->pState->SetFrame( 0.0f );
				}

				//現在のモーション - トランジションの設定
				m_TransitionFramesInv = 1.0f;
				m_TransitionFrame = 1.0f;
				m_TransitionRatio = 1.0f;

				//現在のモーション - エントリー通知のリセット
				pNextMotion->pEntryProcesser->ResetNotify();

				//現在のモーション - 再生開始の通知
				if( pNextMotion->pListener != NULL )
				{
					pNextMotion->pListener->OnActivate( pNextMotion->pInterface, pNextMotion->handle, True );
				}

				//現在のモーション - ステートの設定
				pNextMotion->state = MotionController::MS_PLAYING;
			}
		}
		else
		{
			//停止
			MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];

			if( pCurMotion != NULL )
			{
				MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];

				//直前のモーション - 停止
				Stop( pPreMotion );
				m_MotionTable[MotionController::MOTION_PREVIOUS] = NULL;

				//現在のモーション - 停止
				Stop( pCurMotion );
				m_MotionTable[MotionController::MOTION_CURRENT] = NULL;

				//トランジションの設定
				m_TransitionFramesInv = 1.0f;
				m_TransitionFrame = 1.0f;
				m_TransitionRatio = 0.0f;
			}
		}
	}
}

void MotionController::Stop( MotionController::MOTION* pMotion )
{
	if( ( pMotion == NULL ) ||
		( pMotion->state == MotionController::MS_STOP ) )
	{
		return;
	}

	//ステータスを停止状態へ
	pMotion->state = MotionController::MS_STOP;

	//再生終了の通知
	if( pMotion->pListener != NULL )
	{
		pMotion->pListener->OnActivate( pMotion->pInterface, pMotion->handle, False );
	}

	//パラメータのリセット
	pMotion->pState->SetFrame( 0.0f );
	pMotion->pState->SetLoopCount( 0 );
	pMotion->pState->SetTransitionRatio( 0.0f );
}

Boolean MotionController::AddMotion( Mix::Scene::Common::Motion* pMotion )
{
	MIX_ASSERT( pMotion != NULL );

#ifdef _DEBUG
	MotionController::HandleMap::iterator it_h = m_HandleMap.find( pMotion->GetName() );
	MIX_ASSERT( it_h == m_HandleMap.end() );
#endif //_DEBUG

	return ( ProcAdd( pMotion ) != NULL );
}

Boolean MotionController::CloneMotion( MotionController* pDstController, Boolean bShared, Boolean bDuplicateEntries )
{
	MotionController::MotionMap::iterator it_begin = m_MotionMap.begin();
	MotionController::MotionMap::iterator it_end = m_MotionMap.end();
	MotionController::MotionMap::iterator it;

	if( bShared == True )
	{
		for( it = it_begin; it != it_end; ++it )
		{
			Motion* pMotion = it->second.pInterface;

			MIX_ADD_REF( pMotion );
			pDstController->AddMotion( pMotion );
		}
	}
	else
	{
		for( it = it_begin; it != it_end; ++it )
		{
			Motion* pSrcMotion = it->second.pInterface;
			IMotion* pDstMotion = NULL;

			if( pSrcMotion->Clone( &pDstMotion, bDuplicateEntries ) == False )
			{
				return False;
			}

			if( pDstController->AddMotion( static_cast<Motion*>( pDstMotion ) ) == False )
			{
				MIX_RELEASE( pDstMotion );
				return False;
			}
		}
	}

	return True;
}

Mix::Scene::MOTION_HANDLE MotionController::ProcAdd( Mix::Scene::Common::Motion* pMotion )
{
	Mix::Scene::MOTION_HANDLE handle( this, pMotion );
	Mix::Scene::Common::MotionState* pState = Mix::Scene::Common::MotionState::CreateInstance( this, handle );
	Mix::Scene::Common::MotionEntryProcesser* pEntryProcesser = pMotion->AddEntryProcesser();

	if( ( pState == NULL ) ||
		( pEntryProcesser == NULL ) )
	{
		MIX_RELEASE( pState );
		MIX_RELEASE( pEntryProcesser );

		return NULL;
	}

	pEntryProcesser->SetHandle( handle );

	m_HandleMap.insert( MotionController::HandleMap::value_type( pMotion->GetName(), handle ) );
	m_MotionMap.insert( MotionController::MotionMap::value_type( handle, MotionController::MOTION( handle, pMotion, pState, pEntryProcesser ) ) );

	return handle;
}

UInt32 MotionController::GetCondition( const Mix::Scene::MOTION_HANDLE& handle ) const
{
	const MotionController::MOTION* pPreMotion = m_MotionTable[MotionController::MOTION_PREVIOUS];
	const MotionController::MOTION* pCurMotion = m_MotionTable[MotionController::MOTION_CURRENT];

	UInt32 ret = 0;
/*
	if( m_CommandQueue.IsScheduled( handle ) == True )
	{
		ret |= Mix::Scene::MOTION_COND_WATING;
	}
*/
	if( ( m_CommandQueue.GetCount() > 0 ) &&
		( m_CommandQueue.GetTail().handle == handle ) )
	{
		ret |= Mix::Scene::MOTION_COND_WATING;
	}

	if( ( pPreMotion != NULL ) &&
		( pPreMotion->handle == handle ) &&
		( pPreMotion->state != MotionController::MS_STOP ) )
	{
		ret |= Mix::Scene::MOTION_COND_ACTIVE;
	}
	else if(	( pCurMotion != NULL ) &&
				( pCurMotion->handle == handle ) &&
				( pCurMotion->state != MotionController::MS_STOP ) )
	{
		ret |= Mix::Scene::MOTION_COND_CUR_ACTIVE;
	}

	return ret;
}

Boolean MotionController::Finalize( void )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションのカーブを展開
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( MotionController::MotionMap::iterator it = m_MotionMap.begin(); it != m_MotionMap.end(); ++it )
	{
		MotionController::MOTION* pMotion = &( it->second );

		MotionDeformer* pDeformer = MotionDeformer::CreateInstance( m_pModel, pMotion->pInterface );
		if( pDeformer != NULL )
		{
			pMotion->pDeformer = pDeformer;
		}
		else
		{
			return False;
		}
	}

	return True;
}

void MotionController::Dispose( void )
{
	m_pModel = NULL;
	m_pMixer = NULL;
}

}}}
