#pragma once

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

namespace Mix{ namespace Plugin{ namespace Sound{
	class IDecoder;
}}}

namespace Mix{ namespace Sound{

	class BaseMediator;
	class WaveReader;

	class StreamingTask : public Mix::Sound::Task
	{
	private:
		//各種値
		enum VALUE
		{
			MAX_BLOCK = 3,	//バッファのブロック数
		};

		//ステート
		enum STATE
		{
			STATE_IDLE		= 0,	//通常処理
			STATE_STOPPED	= 1,	//停止後の後処理( 完了後、通常処理に戻る )
		};

		//ボイスコンテキストクラス
		class VoiceContext : public IXAudio2VoiceCallback
		{
		public:
			enum EVENTTYPE
			{
				BUFFERING	= 0,
				END			= 1,

				NONE		= 0xFFFFFFFF,
			};

		private:
			HANDLE m_hEvent[2];

		public:
			VoiceContext( void );
			~VoiceContext( void );

		public:
			void Reset( void );
			UInt32 Poll( void );

		protected:
			virtual void __stdcall OnStreamEnd( void );
			virtual void __stdcall OnVoiceProcessingPassEnd( void ){}
			virtual void __stdcall OnVoiceProcessingPassStart( UINT32 SamplesRequired ){}
			virtual void __stdcall OnBufferEnd( void* pBufferContext );
			virtual void __stdcall OnBufferStart( void* pBufferContext ){}
			virtual void __stdcall OnLoopEnd( void* pBufferContext ){}
			virtual void __stdcall OnVoiceError( void* pBufferContext, HRESULT Error ){}
		};

	protected:
		Mix::Sound::BaseMediator* m_pBaseMediator;
		Mix::Sound::WaveReader* m_pSource;
		Mix::Plugin::Sound::IDecoder* m_pDecoder;
		VoiceContext m_VoiceContext;
		UInt8* m_pBufferArray[MAX_BLOCK];
		IXAudio2SourceVoice* m_pVoice;
		UInt32 m_CurBlock;
		Boolean m_bLoop;
		UInt32 m_State;
		Int32 m_SuspendCount;

	private:
		Boolean ProcIdle( void );
		void ProcStopped( void );

		void ProcPlay( Boolean bLoop );
		void ProcStop( void );
		void ProcSuspend( void );
		void ProcResume( void );
		void ProcBuffering( void );
		void ProcTerminate( void );

	public:
		MIX_DECLARE_ALLOCATOR();

		StreamingTask( Mix::Sound::BaseMediator* pBaseMediator );
		~StreamingTask( void );

		Boolean Initialize( Mix::Sound::WaveReader* pSource, Mix::Plugin::Sound::IDecoder* pDecoder, IXAudio2SourceVoice* pVoice );
		IXAudio2VoiceCallback* GetVoiceCallbackPtr( void );

	public:
		virtual Boolean Process( void );
	};

}}
