#pragma once

namespace FDK
{
	// タイマの抽象クラス。
	// このクラスを継承し、override したクラスを作成することで、任意のクロックを持つタイマを作成できる。
	public ref class CTimerBase
	{
	public:
		static const Int64 n未使用 = -1;

		CTimerBase()
		{
			this->Disposed = gcnew CDisposed();

			this->lock値 = gcnew Object();

			lock l( this->lock値 );

			this->n一時停止システム時刻ms = 0;
			this->n更新システム時刻ms = 0;
			this->n停止数 =0;
			this->_n前回リセットした時のシステム時刻ms = n未使用;
		}
		virtual ~CTimerBase()
		{
			if( this->Disposed->bDispose済みまたは処理中である )
				return;		// 例外は発出させない。

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


			SAFE_REF_DELETE( this->lock値 );
			
			//GC::SuppressFinalize( this );   --> コンパイラが勝手にやる
		}

		// 派生クラスではこれを override する。
		virtual property Int64 nシステム時刻ms
		{
			Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );
				return n未使用;
			}
		}

		property Int64 n現在時刻ms
		{
			Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

				lock l( this->lock値 );

				if( 0 < this->n停止数 )
					return ( this->n一時停止システム時刻ms - this->n前回リセットした時のシステム時刻ms );

				return ( this->n更新システム時刻ms - this->n前回リセットした時のシステム時刻ms );
			}
			void set( Int64 value )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

				if( 0 < this->n停止数 )
					this->n前回リセットした時のシステム時刻ms = this->n一時停止システム時刻ms - value;
				else
					this->n前回リセットした時のシステム時刻ms = this->n更新システム時刻ms - value;
			}
		}
		property Int64 nリアルタイム現在時刻ms
		{
			Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

				lock l( this->lock値 );

				if( 0 < this->n停止数 )
					return ( this->n一時停止システム時刻ms - this->n前回リセットした時のシステム時刻ms );

				return ( this->nシステム時刻ms - this->n前回リセットした時のシステム時刻ms );
			}
		}
		property Int64 n前回リセットした時のシステム時刻ms
		{
			Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

				lock l( this->lock値 );
				return this->_n前回リセットした時のシステム時刻ms;
			}
		protected:
			void set( Int64 value )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

				lock l( this->lock値 );
				this->_n前回リセットした時のシステム時刻ms = value; 
			}
		}
		
		void tリセット()
		{
			this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

			this->t更新();

			lock l( this->lock値 );

			this->n前回リセットした時のシステム時刻ms = this->n更新システム時刻ms;
			this->n一時停止システム時刻ms = this->n更新システム時刻ms;
			this->n停止数 = 0;
		}
		void t一時停止()
		{
			this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

			lock l( this->lock値 );

			if( 0 == this->n停止数 )
				this->n一時停止システム時刻ms = this->n更新システム時刻ms;

			this->n停止数++;
		}
		void t更新()
		{
			this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

			lock l( this->lock値 );
			this->n更新システム時刻ms = this->nシステム時刻ms;
		}
		void t再開()
		{
			this->Disposed->tDispose済みまたは実行中なら例外発生( "CTimerBase" );

			lock l( this->lock値 );

			if( 0 < this->n停止数 )
			{
				this->n停止数--;
				if( 0 == this->n停止数 )
				{
					l.release();
					this->t更新();
					l.acquire();

					this->n前回リセットした時のシステム時刻ms += this->n更新システム時刻ms - this->n一時停止システム時刻ms;
				}
			}
		}

	protected:
		Int64 n一時停止システム時刻ms;
		Int64 n更新システム時刻ms;
		int n停止数;

	private:
		CDisposed^ Disposed;
		Int64 _n前回リセットした時のシステム時刻ms;
		Object^ lock値;		// 上記4つの値のロック用
	};
}
