#include "Mix/Private/Sound/SimpleController.h"
#include "Mix/Private/Sound/Manager.h"
#include "Mix/Memory/IBuffer.h"

namespace Mix{ namespace Sound{

SimpleController* SimpleController::CreateInstance( const Mix::Sound::SimpleController* pSrc, IXAudio2SourceVoice* pVoice )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SOUND, SimpleController, pSrc, pVoice );
}

SimpleController* SimpleController::CreateInstance( const wchar_t* fileName, const WAVEFORMATEX* pFormat, IXAudio2SourceVoice* pVoice, Mix::Memory::IBuffer* pBuffer )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SOUND, SimpleController, fileName, pFormat, pVoice, pBuffer );
}

SimpleController::SimpleController( const Mix::Sound::SimpleController* pSrc, IXAudio2SourceVoice* pVoice ) :
m_FilePath( pSrc->m_FilePath ),
m_pBuffer( NULL ),
m_pVoice( NULL ),
m_SuspendCount( 0 ),
m_Panpot( 0.0f )
{
	MIX_ASSERT( pSrc != NULL );
	MIX_ASSERT( pVoice != NULL );

	MIX_ADD_REF( pSrc->m_pBuffer );
	m_pBuffer = pSrc->m_pBuffer;

	m_pVoice = pVoice; //参照カウンタはインクリメント済み

	Mix::Memory::Copy( &m_Format, &( pSrc->m_Format ), sizeof( WAVEFORMATEX ) );

	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;
}

SimpleController::SimpleController( const wchar_t* filePath, const WAVEFORMATEX* pFormat, IXAudio2SourceVoice* pVoice, Mix::Memory::IBuffer* pBuffer ) :
m_FilePath( filePath ),
m_pVoice( pVoice ),
m_pBuffer( pBuffer ),
m_SuspendCount( 0 ),
m_Panpot( 0.0f )
{
	Mix::Memory::Copy( &m_Format, pFormat, sizeof( WAVEFORMATEX ) );

	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;
}

SimpleController::~SimpleController( void )
{
	if( m_pVoice != NULL )
	{
		m_pVoice->DestroyVoice();
	}

	MIX_RELEASE( m_pBuffer );
}

const WAVEFORMATEX* SimpleController::GetFormat( void ) const
{
	return &m_Format;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Sound::IController
////////////////////////////////////////////////////////////////////////////////////////////////////

Float32 SimpleController::GetVolume( void ) const
{
	if( m_pVoice == NULL )
	{
		return 0.0f;
	}

	Float32 volume;

	m_pVoice->GetVolume( &volume );

	return volume;
}

void SimpleController::SetVolume( Float32 volume )
{
	if( m_pVoice != NULL )
	{
		m_pVoice->SetVolume( volume );
	}
}

Float32 SimpleController::GetPanpot( void ) const
{
	if( m_pVoice == NULL )
	{
		return 0.0f;
	}

	return m_Panpot;
}

void SimpleController::SetPanpot( Float32 panpot )
{
	if( m_pVoice == NULL )
	{
		return;
	}

	Float32 cv[2];

	if( panpot >= 0.0f )
	{
		cv[0] = ( 1.0f - panpot );
		cv[1] = 1.0;
	}
	else
	{
		cv[0] = 1.0;
		cv[1] = ( 1.0f + panpot );
	}

	if( m_pVoice->SetChannelVolumes( 2, cv ) == S_OK )
	{
		m_Panpot = panpot;
	}
}

Boolean SimpleController::IsCloneable( void ) const
{
	return True;
}

Boolean SimpleController::Clone( Mix::Sound::IController** ppController )
{
	if( m_pVoice == NULL )
	{
		//すでに解放されている
		return False;
	}

	return Mix::Sound::GetInternalManagerPtr()->CloneSimpleController( this, ppController );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Sound::IDevice
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean SimpleController::IsPlaying( void )
{
	if( m_pVoice == NULL )
	{
		return False;
	}

	XAUDIO2_VOICE_STATE state;

	m_pVoice->GetState( &state );

	return ( state.BuffersQueued > 0 );
}

void SimpleController::Play( Boolean bLoop )
{
	if( m_pVoice == NULL )
	{
		return;
	}

	Stop();

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

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

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

void SimpleController::Stop( void )
{
	if( m_pVoice != NULL )
	{
		m_pVoice->Stop( 0 , XAUDIO2_COMMIT_NOW );
		m_pVoice->FlushSourceBuffers();
	}

	m_SuspendCount = 0;
}

void SimpleController::Suspend( void )
{
	if( m_pVoice == NULL )
	{
		return;
	}

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

void SimpleController::Resume( void )
{
	if( m_pVoice == NULL )
	{
		return;
	}

	if( --m_SuspendCount == 0 )
	{
		m_pVoice->Start();
	}
}

Boolean SimpleController::IsDisposed( void )
{
	return ( m_pVoice == NULL );
}

void SimpleController::Dispose( void )
{
	if( m_pVoice != NULL )
	{
		m_pVoice->DestroyVoice();
		m_pVoice = NULL;
	}

	m_FilePath = L"";
}

const wchar_t* SimpleController::GetFilePath( void ) const
{
	return m_FilePath.GetConstPtr();
}

}}
