#include"CSoundCore.h"
#include"../../Auxiliary/Debug/CAssert.h"
#include"CSoundMessageImpl1.h"
#include"../../Auxiliary/Debug/CTrace.h"
#include"../../Auxiliary/Debug/CWarning.h"

//	サウンドスレッド側で呼ばれる関数

namespace Maid
{

bool CSoundCore::SOUNDINFO::IsVolumeChangeEnd( unt time )
{
	return EndTime <= time;
}

int CSoundCore::SOUNDINFO::CalcVolume( unt time )
{
	const int t_pos = time - BeginTime;
	const int t_len = EndTime - BeginTime;
	const int v_len = EndVolume - BeginVolume;

	if( t_len==0 ) { return EndVolume; }
	if( t_len<=t_pos ) { return EndVolume; }

	const int offset = v_len * t_pos / t_len;

	return BeginVolume + offset;
}


unt CSoundCore::ThreadFunction( volatile CThreadController::BRIGEDATA& brige )
{
	m_pDriver->Initialize(m_Format);

	unt OldTime = m_pTimer->Get();

	while( true )
	{
		if( brige.IsExit ) { break; }

		SOUNDMESSAGEQUE Mess;
		{	//	とりあえず溜まっているメッセージを拾う
			CThreadMutexLocker Lock(m_MessageMutex);
			Mess = m_MessageQue;
			m_MessageQue.clear();
		}

		//	メッセージを順番に処理
		for( int i=0; i<(int)Mess.size(); ++i )
		{
			SPSOUNDMESSAGE& pMess = Mess[i];
			ExecuteMessage( pMess );
		}

		const unt NowTime = m_pTimer->Get();
		const unt sa = NowTime - OldTime;
		static unt delta1000=0;

		OldTime = NowTime;

		if( sa!=0 )
		{
			//	バッファの更新作業
			for( int i=0; i<(int)m_SoundInfo.size(); ++i )
			{
				UpdateSoundInfo( m_SoundInfo[i], sa, NowTime );
			}
		}

		//	一仕事終わったのでしばし休憩
		m_pTimer->Sleep(10);
	}

	//	残っているメッセージを処理
	for( int i=0; i<(int)m_MessageQue.size(); ++i )
	{
		SPSOUNDMESSAGE& pMess = m_MessageQue[i];
		ExecuteMessage( pMess );
	}
	m_MessageQue.clear();

	m_pDriver->Finalize();

	return 0;
}

void CSoundCore::UpdateSoundInfo( SOUNDINFO& Info, unt delta, unt now )
{
	switch( Info.State )
	{
	case SOUNDINFO::STATE_EMPTY: { return; }break;
	case SOUNDINFO::STATE_STOP:
		{
			return ;
		}break;

	case SOUNDINFO::STATE_PLAY:
		{
			if( Info.IsVolumeChanging )
			{
				if( Info.IsVolumeChangeEnd(now) )
				{
				//	MAID_TRACE( "IsVolumeChangeEnd" << Info.EndVolume );
					Info.pBuffer->SetVolume(Info.EndVolume);
					Info.IsVolumeChanging = false;
				}else
				{
					const int vol = Info.CalcVolume(now);
				//	MAID_TRACE( "SetVolume" << vol );
					Info.pBuffer->SetVolume(vol);
				}
			}	
			
			if( !Info.pBuffer->IsPlay() )
			{
				Info.Status.PlayCount -= 1;

				if( Info.Status.PlayCount <= 0 )
				{
					Info.State = SOUNDINFO::STATE_STOP;
					Info.Status.IsPlay = false;
				}else
				{
					Info.pBuffer->Play();
				}
			}


		}break;


	case SOUNDINFO::STATE_DELETE:
		{
			if( Info.IsVolumeChangeEnd(now) )
			{
				Info.pBuffer.reset();
				Info.IsVolumeChanging = false;
				Info.State = SOUNDINFO::STATE_EMPTY;
				return ;
			}else
			{
				const int vol = Info.CalcVolume(now);
				Info.pBuffer->SetVolume(vol);
			}
		}break;
	}

	Info.pBuffer->Update(delta);
	Info.Status.Position = Info.pBuffer->GetPosition();

	if( Info.State==SOUNDINFO::TYPE_STREAM )
	{
		ISoundBufferPCM* p = static_cast<ISoundBufferPCM*>(Info.pBuffer.get());
		Info.Status.db = p->GetNowRatio();
	}
}



void CSoundCore::ExecuteMessage( const SPSOUNDMESSAGE& pMessage )
{
	using namespace SoundMessage;

	const Base::MESSAGE mess = pMessage->Message;
	SOUNDINFO& Info = m_SoundInfo[pMessage->ID];

	switch( mess )
	{
	default:
		{
			MAID_ASSERT( true, "メッセージが処理できません" );
		}break;

	case Base::LOAD_PCMSTATIC:
		{
			LoadPCMStatic* p = static_cast<LoadPCMStatic*>(pMessage.get());

		//	MAID_TRACE( "LOAD_PCMSTATIC begin" );
			SPSOUNDBUFFERPCMSTATIC pBuffer = m_pDriver->CreateBufferPCMStatic( *(p->pData), p->Format );
			Info.pBuffer = pBuffer;
			Info.State = SOUNDINFO::STATE_STOP;
			Info.Type = SOUNDINFO::TYPE_STATIC;
		//	MAID_TRACE( "LOAD_PCMSTATIC end" );
		}break;

	case Base::LOAD_PCMSTATICCLONE:
		{
			LoadPCMStaticClone* p = static_cast<LoadPCMStaticClone*>(pMessage.get());

			SOUNDINFO& dst = m_SoundInfo[p->SrcID];

		//	MAID_TRACE( "LOAD_PCMSTATIC begin" );
			SPSOUNDBUFFERPCMSTATIC pBuffer = m_pDriver->DuplicateSoundBuffer( static_cast<ISoundBufferPCMStatic &>(*(m_SoundInfo[p->SrcID].pBuffer)) );
			Info.pBuffer = pBuffer;
			Info.State = SOUNDINFO::STATE_STOP;
			Info.Type = SOUNDINFO::TYPE_STATIC;
		//	MAID_TRACE( "LOAD_PCMSTATIC end" );
		}break;

	case Base::LOAD_PCMSTREAM:
		{
			LoadPCMStream* p = static_cast<LoadPCMStream*>(pMessage.get());

		//	MAID_TRACE( "LOAD_PCMSTREAM begin" << pMessage->ID << " "  );
			SPSOUNDBUFFERPCMSTREAM pBuffer = m_pDriver->CreateBufferPCMStream( p->pDecoder );

			Info.pBuffer = pBuffer;
			Info.State = SOUNDINFO::STATE_STOP;
			Info.Type  = SOUNDINFO::TYPE_STREAM;
		//	MAID_TRACE( "LOAD_PCMSTREAM end" );

		}break;

	case Base::PLAY:
		{
			Play* p = static_cast<Play*>(pMessage.get());

			if( Info.Status.PlayCount==0 ) { break; }

			const int vol = Info.CalcVolume(m_pTimer->Get());

			Info.pBuffer->SetVolume( vol );
			Info.pBuffer->Play();
			Info.State = SOUNDINFO::STATE_PLAY;
		//	MAID_TRACE( "PLAY" << vol << " " << pMessage->ID << " ");
		}break;

	case Base::STOP:
		{
			Stop* p = static_cast<Stop*>(pMessage.get());
			Info.pBuffer->Stop();
			Info.Status.IsPlay = false;
			Info.State = SOUNDINFO::STATE_STOP;
		}break;

	case Base::DELETEBUFFER:
		{
			DeleteBuffer* p = static_cast<DeleteBuffer*>(pMessage.get());

			Info.BeginTime = m_pTimer->Get();
			Info.EndTime   = Info.BeginTime + 20;

			Info.BeginVolume = Info.pBuffer->GetVolume();
			Info.EndVolume   = ISoundBuffer::VOLUME_MIN;
			Info.State = SOUNDINFO::STATE_DELETE;
		}break;

	case Base::SETPOSITION:
		{
			SetPosition* p = static_cast<SetPosition*>(pMessage.get());
			const int miri  = p->Position;

			Info.pBuffer->SetPosition( miri );
		}break;

	case Base::SETLOOPPOSITION:
		{
			SetLoopPosition* p = static_cast<SetLoopPosition*>(pMessage.get());
			const int miri  = p->Position;

			Info.pBuffer->SetPosition( miri );
		}break;

	case Base::SETVOLUME:
		{
			SetVolume* p = static_cast<SetVolume*>(pMessage.get());

			Info.BeginTime = m_pTimer->Get();
			Info.EndTime   = Info.BeginTime + p->Time;

			Info.BeginVolume = Info.pBuffer->GetVolume();
			Info.EndVolume   = p->Volume;

		//	MAID_TRACE( "SETVOLUME" << pMessage->ID << " " << Info.BeginVolume << " " << Info.EndVolume << " " << p->Time );
			Info.IsVolumeChanging = true;
		}break;

	case Base::SETPLAYCOUNT:
		{
			SetPlayCount* p = static_cast<SetPlayCount*>(pMessage.get());

			if( p->Count==BUFFERSTATUS::PLAYLOOP )
			{
				Info.pBuffer->SetLoopState(true);
			}else
			{
				Info.pBuffer->SetLoopState(false);
			}

			Info.Status.PlayCount = p->Count;
		}break;

	case Base::GETSOUNDINFO:
		{
			CThreadMutexLocker Lock(m_SoundInfoMutex);

			m_CapsText = m_pDriver->DeviceCapsStringOut();
			if( m_CapsText.empty() ) { m_CapsText = MAIDTEXT("Unkwon"); }

		}break;
	}
}


}


