#include "Mix/Private/Scene/Common/MotionEntryProcesser.h"
#include "Mix/Scene/IMotionListener.h"
#include "Mix/Private/Scene/Common/Motion.h"

namespace Mix{ namespace Scene{ namespace Common{

MotionEntryProcesser* MotionEntryProcesser::CreateInstance( void )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, MotionEntryProcesser );
}

MotionEntryProcesser::MotionEntryProcesser( void ) :
m_pSubject( NULL ),
m_Handle( NULL ),
m_pListener( NULL )
{
}

MotionEntryProcesser::~MotionEntryProcesser( void )
{
	if( m_pSubject != NULL )
	{
		m_pSubject->RemoveEntryProcesser( this );
	}

	MIX_RELEASE( m_pListener );
}

void MotionEntryProcesser::SetSubjectPtr( Mix::Scene::Common::Motion* pSubject )
{
	m_pSubject = pSubject;
}

void MotionEntryProcesser::Build( const Mix::Scene::MOTION_ENTRY_DESC* entries, UIntT count )
{
	m_EntryList.clear();

	if( ( entries == NULL ) &&
		( count == 0 ) )
	{
		return;
	}

	MIX_ASSERT( ( entries != NULL ) && ( count > 0 ) );

	const Mix::Scene::MOTION_ENTRY_DESC* pEntry = &( entries[0] );
	const Mix::Scene::MOTION_ENTRY_DESC* pEntryEnd = pEntry + count;

	m_EntryList.reserve( count );

	while( pEntry != pEntryEnd )
	{
		m_EntryList.push_back( MotionEntryProcesser::ENTRY( pEntry ) );
		pEntry++;
	}
}

void MotionEntryProcesser::SetHandle( const Mix::Scene::MOTION_HANDLE& handle )
{
	m_Handle = handle;
}

void MotionEntryProcesser::SetListener( Mix::Scene::IMotionListener* pListener )
{
	MIX_RELEASE( m_pListener );

	MIX_ADD_REF( pListener );
	m_pListener = pListener;
}

void MotionEntryProcesser::ResetNotify( void )
{
	if( m_EntryList.size() == 0 )
	{
		return;
	}

	MotionEntryProcesser::ENTRY* pEntry = &( m_EntryList[0] );
	MotionEntryProcesser::ENTRY* pEntryEnd = pEntry + m_EntryList.size();

	while( pEntry != pEntryEnd )
	{
		pEntry->bNotified = False;
		pEntry++;
	}
}

void MotionEntryProcesser::Notify( Float32 startFrame, Float32 endFrame )
{
	if( ( m_pSubject == NULL ) ||
		( m_Handle == NULL ) ||
		( m_pListener == NULL ) ||
		( m_EntryList.size() == 0 ) )
	{
		return;
	}

	MotionEntryProcesser::ENTRY* pEntry = &( m_EntryList[0] );
	MotionEntryProcesser::ENTRY* pEntryEnd = pEntry + m_EntryList.size();

	while( pEntry != pEntryEnd )
	{
		const Mix::Scene::MOTION_ENTRY_DESC* pDesc = pEntry->pDesc;

		if( ( pDesc->endFrame >= startFrame ) &&
			( pDesc->startFrame <= endFrame ) )
		{
			if( pEntry->bNotified == False )
			{
				m_pListener->OnEntry( m_pSubject, m_Handle, *pDesc, endFrame );
				pEntry->bNotified = !pDesc->bAlways;
			}
		}
		else
		{
			pEntry->bNotified = False;
		}

		pEntry++;
	}
}

}}}
