#include "Stdafx.h"
#include "refCMediaSession.h"
#include "Sound\refCSound.h"

namespace FDK
{
//public:
	CMediaSession::CMediaSession()
	{
		this->Disposed = gcnew CDisposed();
		this->pMediaSessionNative = new CMediaSessionNative();
	}
	CMediaSession::CMediaSession( IntPtr hWnd, DWORD dwMediaSessionイベント処理スレッドID, String^ stgファイル名, bool b音声あり, bool bループする )
	{
		this->Disposed = gcnew CDisposed();
		this->pMediaSessionNative = new CMediaSessionNative();
		this->t構築する( hWnd, dwMediaSessionイベント処理スレッドID, stgファイル名, b音声あり, bループする );
	}
	CMediaSession::~CMediaSession()
	{
		if( this->Disposed->bDispose済みまたは処理中である )
			return;		// 例外は発出しない。

		if( !this->Disposed->t開始を宣言する() )
			return;		// 例外は発出しない。


		// ファイナライザを呼び出して Unmanaged リソースを解放したのち、ファイナライザの呼び出しを抑制する。
		this->!CMediaSession();
		
		//GC::SuppressFinalize( this );   --> コンパイラが勝手にやる
	}
	CMediaSession::!CMediaSession()
	{
		// Unmanaged リソースを解放する。ディスポーザが呼び出されていればファイナライザは呼び出されないようコンパイラが調整する。
		SAFE_DELETE( this->pMediaSessionNative );
	}

	void CMediaSession::t構築する( IntPtr hWnd, DWORD dwMediaSessionイベント処理スレッドID, String^ stgファイル名, bool b音声あり, bool bループする )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

		pin_ptr<const wchar_t> fileName = ::PtrToStringChars( stgファイル名 );
		this->pMediaSessionNative->t構築する( static_cast<HWND>( hWnd.ToPointer() ), dwMediaSessionイベント処理スレッドID, fileName, b音声あり, bループする );
	}
	void CMediaSession::t再生する( UInt64 n再生開始位置100ns )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
		this->pMediaSessionNative->t再生する( n再生開始位置100ns );
	}
	void CMediaSession::t再生する( UInt64 n再生開始位置100ns, CSound^ sound )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

		ThreadPool::QueueUserWorkItem( gcnew WaitCallback( this, &CMediaSession::t動画の再生に同期してサウンドを再生する ), sound );
		this->pMediaSessionNative->t再生する( n再生開始位置100ns );
	}
	void CMediaSession::t停止する()
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
		this->pMediaSessionNative->t停止する();
	}
	void CMediaSession::t一時停止する()
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
		this->pMediaSessionNative->t一時停止する();
	}
	void CMediaSession::t再生を再開する()
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
		this->pMediaSessionNative->t再生を再開する();
	}
	void CMediaSession::t再生処理が完了するまで待機する()
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
		this->pMediaSessionNative->t再生処理が完了するまで待機する();
	}

	void CMediaSession::t次のサンプルを要求する()
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );
		this->pMediaSessionNative->t次のサンプルを要求する();
	}
	void CMediaSession::t最新のサンプルを描画する()
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

		if( EMediaSessionの状態::再生中 != this->eMediaSessionの状態 )
			return;

		SIZE size;
		this->pMediaSessionNative->t画像サイズを取得する( &size );

		RECT rc;
		rc.left = 0;
		rc.right = size.cx;
		rc.top = 0;
		rc.bottom = size.cy;

		this->pMediaSessionNative->t最新のサンプルを描画する( &rc );
	}
	void CMediaSession::t最新のサンプルを描画する( System::Drawing::Rectangle rc描画先 )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

		if( EMediaSessionの状態::再生中 != this->eMediaSessionの状態 )
			return;

		RECT rc;
		rc.left = rc描画先.Left;
		rc.right = rc描画先.Right;
		rc.top = rc描画先.Top;
		rc.bottom = rc描画先.Bottom;

		this->pMediaSessionNative->t最新のサンプルを描画する( &rc );
	}
	void CMediaSession::t最新のサンプルを描画する( int x, int y, int w, int h )
	{
		this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );

		if( EMediaSessionの状態::再生中 != this->eMediaSessionの状態 )
			return;

		RECT rc;
		rc.left = x;
		rc.right = x + w;
		rc.top = y;
		rc.bottom = y + h;

		this->pMediaSessionNative->t最新のサンプルを描画する( &rc );
	}

//public static:
	void CMediaSession::t全インスタンスのEVRへデバイス変更通知を送る()
	{
		//this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );		static なのでノーチェック
		CMediaSessionNative::AllInstances::tEVRへデバイス変更通知を送る();
	}
	void CMediaSession::t全インスタンスへ次のサンプルを要求する()
	{
		//this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );		static なのでノーチェック
		CMediaSessionNative::AllInstances::t次のサンプルを要求する();
	}
	void CMediaSession::t全インスタンスを停止する()
	{
		//this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );		static なのでノーチェック
		CMediaSessionNative::AllInstances::t停止する();
	}

//private:
	void CMediaSession::t動画の再生に同期してサウンドを再生する( Object^ state )
	{
		//this->Disposed->tDispose済みまたは実行中なら例外発生( "CMediaSession" );		private なのでノーチェック

		this->pMediaSessionNative->t再生処理が完了するまで待機する();
		
		// 指定があれば、サウンドを再生開始する。

		if( nullptr != state )
		{
			CSound^ sound = dynamic_cast<CSound^>( state );
			sound->t先頭から再生する();
		}
	}
}
