#pragma once

#include "CMediaSessionNative.h"
#include "Sound\refCSound.h"

namespace FDK
{
	public ref class CMediaSession
	{
	public:
		enum class EMediaSessionの状態
		{
			再生終了,		// 初期状態、または MESessionEnded イベント受信後。
			再生準備中,		// 非同期メソッド　IMFMediaSession::Start() 実行後。
			再生中,			// MESessionStarted イベント受信後。
			停止準備中,		// 非同期メソッド IMFMediaSession::Stop() 実行後。
			停止中,			// MESessionStopped イベント受信後。
			一時停止準備中,	// 非同期メソッド IMFMediaSession::Pause() 実行後。
			一時停止中		// MESessionPaused イベント受信後。
		};
		property EMediaSessionの状態 eMediaSessionの状態
		{
			EMediaSessionの状態 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

				switch( this->pMediaSessionNative->Status.Get() )
				{
				case CMediaSessionNative::CStatus::EStatus::再生終了:
					return EMediaSessionの状態::再生終了;

				case CMediaSessionNative::CStatus::EStatus::再生準備中:
					return EMediaSessionの状態::再生準備中;

				case CMediaSessionNative::CStatus::EStatus::再生中:
					return EMediaSessionの状態::再生中;

				case CMediaSessionNative::CStatus::EStatus::停止準備中:
					return EMediaSessionの状態::停止準備中;

				case CMediaSessionNative::CStatus::EStatus::停止中:
					return EMediaSessionの状態::停止中;

				case CMediaSessionNative::CStatus::EStatus::一時停止準備中:
					return EMediaSessionの状態::一時停止準備中;

				case CMediaSessionNative::CStatus::EStatus::一時停止中:
					return EMediaSessionの状態::一時停止中;

				default:
					return EMediaSessionの状態::再生終了;
				}
			}
		}
		property bool b再生中
		{
			bool get() 
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
				return this->pMediaSessionNative->b再生中である();
			}
		}
		property Size sz画像サイズ
		{
			Size get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

				SIZE size;
				this->pMediaSessionNative->t画像サイズを取得する( &size );
				return Size( size.cx, size.cy );
			}
		}
		property long n現在のグラフの再生位置ms
		{
			long get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

				UInt64 clock = this->pMediaSessionNative->n現在のクロックを返す();	// 100ns 単位。
				return (long)(clock / ( 10 * 1000 ));	// 100ns単位 → 1ms 単位にして返す。
			}
		}
		property UInt32 n透明度
		{
			void set( UInt32 val )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
				this->pMediaSessionNative->t透明度を設定する( val );
			}
		}
		property bool b加算合成
		{
			void set( bool val )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
				this->pMediaSessionNative->t加算合成する( val );
			}
		}

		CMediaSession();
		CMediaSession( IntPtr hWnd, DWORD dwMediaSessionイベント処理スレッドID, String^ stgファイル名, bool b音声あり, bool bループする );
		~CMediaSession();
		!CMediaSession();

		void t構築する( IntPtr hWnd, DWORD dwMediaSessionイベント処理スレッドID, String^ stgファイル名, bool b音声あり, bool bループする );
		void t再生する( UInt64 n再生開始位置100ns );
		void t再生する( UInt64 n再生開始位置100ns, CSound^ sound );	// sound は動画と同期して再生するサウンド。
		void t停止する();
		void t一時停止する();
		void t再生を再開する();
		void t再生処理が完了するまで待機する();

		void t次のサンプルを要求する();
		void t最新のサンプルを描画する();
		void t最新のサンプルを描画する( System::Drawing::Rectangle rc描画先 );
		void t最新のサンプルを描画する( int x, int y, int w, int h );

		static void t全インスタンスのEVRへデバイス変更通知を送る();				// スレッドセーフ
		static void t全インスタンスへ次のサンプルを要求する();					// スレッドセーフ
		static void t全インスタンスを停止する();								// スレッドセーフ

	private:
		CDisposed^ Disposed;
		CMediaSessionNative* pMediaSessionNative;

		void t動画の再生に同期してサウンドを再生する( Object^ state );
	};
}
