#include "Mix/Private/Scene/Common/MotionCurve.h"
#include "Mix/IO/IReader.h"

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* MotionCurve::FAILED_CREATE = L"モーションカーブの作成に失敗";

MotionCurve* MotionCurve::CreateInstance( Mix::IO::IReader* pReader, const wchar_t* pNameLabel, const wchar_t* pName )
{
	MotionCurve::MOT_CURV_DESC desc;
	MotionCurve* pInterface = NULL;
	UInt32 readSize;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ヘッダ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pReader->Read( &desc, sizeof( desc ) ) != sizeof( desc ) )
	{
		MIX_LOG_ERROR( L"%s : %s(0) : %s[%s]", MotionCurve::FAILED_CREATE, Mix::STR_ILLEGALFORMAT, pNameLabel, pName );
		return NULL;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インターフェースの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pInterface = MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, MotionCurve );
	if( pInterface == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : %s[%s]", MotionCurve::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pNameLabel, pName );
		return NULL;
	}

	pInterface->m_LinkNodeName = desc.linkNodeName;
	pInterface->m_ScalingKeyList.resize( desc.scalingKeyNum );
	pInterface->m_RotationKeyList.resize( desc.rotationKeyNum );
	pInterface->m_TranslationKeyList.resize( desc.translationKeyNum );

	MIX_ASSERT( pInterface->m_ScalingKeyList.size() == desc.scalingKeyNum );
	MIX_ASSERT( pInterface->m_RotationKeyList.size() == desc.rotationKeyNum );
	MIX_ASSERT( pInterface->m_TranslationKeyList.size() == desc.translationKeyNum );

	//スケーリング
	if( pInterface->m_ScalingKeyList.size() > 0 )
	{
		readSize = MIX_UIT_TO_UI32( sizeof( Mix::Scene::Common::MOTION_VECTOR_KEY ) * pInterface->m_ScalingKeyList.size() );
		if( pReader->Read( &( pInterface->m_ScalingKeyList[0] ), readSize ) != readSize )
		{
			MIX_LOG_ERROR( L"%s : %s(1) : %s[%s]", MotionCurve::FAILED_CREATE, Mix::STR_ILLEGALFORMAT, pNameLabel, pName );
			return NULL;
		}
	}

	//ローテーション
	if( pInterface->m_RotationKeyList.size() > 0 )
	{
		readSize = MIX_UIT_TO_UI32( sizeof( Mix::Scene::Common::MOTION_QUATERNION_KEY ) * pInterface->m_RotationKeyList.size() );
		if( pReader->Read( &( pInterface->m_RotationKeyList[0] ), readSize ) != readSize )
		{
			MIX_LOG_ERROR( L"%s : %s(2) : %s[%s]", MotionCurve::FAILED_CREATE, Mix::STR_ILLEGALFORMAT, pNameLabel, pName );
			return NULL;
		}
	}

	//トランスレーション
	if( pInterface->m_TranslationKeyList.size() > 0 )
	{
		readSize = MIX_UIT_TO_UI32( sizeof( Mix::Scene::Common::MOTION_VECTOR_KEY ) * pInterface->m_TranslationKeyList.size() );
		if( pReader->Read( &( pInterface->m_TranslationKeyList[0] ), readSize ) != readSize )
		{
			MIX_LOG_ERROR( L"%s : %s(2) : %s[%s]", MotionCurve::FAILED_CREATE, Mix::STR_ILLEGALFORMAT, pNameLabel, pName );
			return NULL;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return pInterface;
}

MotionCurve::MotionCurve( void ) :
m_LinkNodeName( L"" )
{
}

MotionCurve::~MotionCurve( void )
{
}

const wchar_t* MotionCurve::GetLinkNodeName( void ) const
{
	return m_LinkNodeName.GetConstPtr();
}

Mix::Vector3 MotionCurve::GetScaling( float time )
{
	if( m_ScalingKeyList.size() == 0 )
	{
		return Mix::Vector3( 1.0f, 1.0f, 1.0f );
	}

	const Mix::Scene::Common::MOTION_VECTOR_KEY& firstKey = m_ScalingKeyList.front();
	const Mix::Scene::Common::MOTION_VECTOR_KEY& lastKey = m_ScalingKeyList.back();

	if( firstKey.time >= time )
	{
		return firstKey.value;
	}
	else if( lastKey.time <= time )
	{
		return lastKey.value;
	}

	Mix::Scene::Common::MotionVectorKeyList::iterator it = std::upper_bound( m_ScalingKeyList.begin(), m_ScalingKeyList.end(), time, Mix::Scene::Common::MOTION_VECTOR_KEY() );
	if( ( *it ).time == time )
	{
		return ( *it ).value;
	}

	const Mix::Scene::Common::MOTION_VECTOR_KEY& prevKey = ( *( it - 1 ) );
	const Mix::Scene::Common::MOTION_VECTOR_KEY& nextKey = ( *it );
	const Mix::Vector3& prevValue = prevKey.value;
	const Mix::Vector3& nextValue = nextKey.value;

	Float32 rate = MIX_FLOAT_DIV( ( time - prevKey.time ), ( nextKey.time - prevKey.time ) );

	return prevValue + ( ( nextValue - prevValue ) * rate );
}

Mix::Quaternion MotionCurve::GetRotation( float time )
{
	if( m_RotationKeyList.size() == 0 )
	{
		return Mix::Quaternion();
	}

	const Mix::Scene::Common::MOTION_QUATERNION_KEY& firstKey = m_RotationKeyList.front();
	const Mix::Scene::Common::MOTION_QUATERNION_KEY& lastKey = m_RotationKeyList.back();

	if( firstKey.time >= time )
	{
		return firstKey.value;
	}
	else if( lastKey.time <= time )
	{
		return lastKey.value;
	}

	Mix::Scene::Common::MotionQuaternionKeyList::iterator it = std::upper_bound( m_RotationKeyList.begin(), m_RotationKeyList.end(), time, Mix::Scene::Common::MOTION_QUATERNION_KEY() );
	if( ( *it ).time == time )
	{
		return ( *it ).value;
	}

	const Mix::Scene::Common::MOTION_QUATERNION_KEY& prevKey = ( *( it - 1 ) );
	const Mix::Scene::Common::MOTION_QUATERNION_KEY& nextKey = ( *it );
	const Mix::Quaternion& prevValue = prevKey.value;
	const Mix::Quaternion& nextValue = nextKey.value;

	Float32 rate = MIX_FLOAT_DIV( ( time - prevKey.time ), ( nextKey.time - prevKey.time ) );

	return Mix::Quaternion::Slerp( prevValue, nextValue, rate );
}

Mix::Vector3 MotionCurve::GetTranslation( float time )
{
	if( m_TranslationKeyList.size() == 0 )
	{
		return Mix::Vector3( 0.0f, 0.0f, 0.0f );
	}

	const Mix::Scene::Common::MOTION_VECTOR_KEY& firstKey = m_TranslationKeyList.front();
	const Mix::Scene::Common::MOTION_VECTOR_KEY& lastKey = m_TranslationKeyList.back();

	if( firstKey.time >= time )
	{
		return firstKey.value;
	}
	else if( lastKey.time <= time )
	{
		return lastKey.value;
	}

	Mix::Scene::Common::MotionVectorKeyList::iterator it = std::upper_bound( m_TranslationKeyList.begin(), m_TranslationKeyList.end(), time, Mix::Scene::Common::MOTION_VECTOR_KEY() );
	if( ( *it ).time == time )
	{
		return ( *it ).value;
	}

	const Mix::Scene::Common::MOTION_VECTOR_KEY& prevKey = ( *( it - 1 ) );
	const Mix::Scene::Common::MOTION_VECTOR_KEY& nextKey = ( *it );
	const Mix::Vector3& prevValue = prevKey.value;
	const Mix::Vector3& nextValue = nextKey.value;

	Float32 rate = MIX_FLOAT_DIV( ( time - prevKey.time ), ( nextKey.time - prevKey.time ) );

	return prevValue + ( ( nextValue - prevValue ) * rate );
}

}}}
