#include "Mix/Private/Sound/SimpleEmitterTask.h"

#include "Mix/Private/Sound/EmitterMediator.h"
#include "Mix/Memory/IBuffer.h"

namespace Mix{ namespace Sound{

SimpleEmitterTask::SimpleEmitterTask( Mix::Sound::EmitterMediator* pMediator, Mix::Memory::IBuffer* pBuffer, IXAudio2SourceVoice* pVoice ) :
m_pMediator( pMediator ),
m_pBuffer( pBuffer ),
m_pVoice( pVoice )
{
	MIX_ADD_REF( m_pMediator );
	MIX_ADD_REF( pBuffer );

	m_Data.Flags = XAUDIO2_END_OF_STREAM;
	m_Data.AudioBytes = MIX_UIT_TO_UI32( m_pBuffer->GetSize() );
	m_Data.pAudioData = static_cast<const BYTE*>( m_pBuffer->GetConstPointer() );
	m_Data.PlayBegin = 0;
	m_Data.PlayLength = 0;
	m_Data.LoopBegin = XAUDIO2_NO_LOOP_REGION;
	m_Data.LoopLength = 0;
	m_Data.LoopCount = 0;
	m_Data.pContext = NULL;
}

SimpleEmitterTask::~SimpleEmitterTask( void )
{
	MIX_RELEASE( m_pMediator );

	if( m_pVoice != NULL )
	{
		m_pVoice->DestroyVoice();
	}

	MIX_RELEASE( m_pBuffer );
}

Boolean SimpleEmitterTask::Process( void )
{
	Boolean bContinue;
	Int16 eventType;
	Int16 eventOpt;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// イベントの処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	bContinue = True;

	if( m_pMediator->PopEvent( eventType, eventOpt ) == True )
	{
		switch( eventType )
		{
		case Mix::Sound::BaseMediator::EVENT_TYPE_PLAY:
			ProcPlay( ( eventOpt != 0 ) );
			break;

		case Mix::Sound::BaseMediator::EVENT_TYPE_STOP:
			ProcStop();
			break;

		case Mix::Sound::BaseMediator::EVENT_TYPE_SUSPEND:
			ProcSuspend();
			break;

		case Mix::Sound::BaseMediator::EVENT_TYPE_RESUME:
			ProcResume();
			break;

		case Mix::Sound::BaseMediator::EVENT_TYPE_TERMINATE:
			bContinue = False;
			break;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 再生状態の処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	ProcState();

	return bContinue;
}

void SimpleEmitterTask::ProcPlay( Boolean bLoop )
{
	ProcStop();

	m_Data.LoopCount = ( bLoop == True )? XAUDIO2_LOOP_INFINITE : 0;

	m_pMediator->ApplyDSPSettings( m_pVoice );

	if( m_pVoice->SubmitSourceBuffer( &m_Data ) != S_OK )
	{
		return;
	}

	if( m_pVoice->Start( 0, XAUDIO2_COMMIT_NOW ) != S_OK )
	{
		return;
	}
}

void SimpleEmitterTask::ProcStop( void )
{
	m_pVoice->Stop( 0 , XAUDIO2_COMMIT_NOW );
	m_pVoice->FlushSourceBuffers();

	m_SuspendCount = 0;
}

void SimpleEmitterTask::ProcSuspend( void )
{
	if( m_SuspendCount++ == 0 )
	{
		m_pVoice->Stop( 0 , XAUDIO2_COMMIT_NOW );
	}
}

void SimpleEmitterTask::ProcResume( void )
{
	if( --m_SuspendCount == 0 )
	{
		m_pVoice->Start();
	}
}

void SimpleEmitterTask::ProcState( void )
{
	XAUDIO2_VOICE_STATE state;

	m_pVoice->GetState( &state );

	if( state.BuffersQueued > 0 )
	{
		m_pMediator->ApplyDSPSettings( m_pVoice );
		m_pMediator->SetState( Mix::Sound::BaseMediator::STATE_PLAY );
	}
	else
	{
		m_pMediator->SetState( Mix::Sound::BaseMediator::STATE_STOP );
	}
}

}}
