//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * スレッドヘッダ
 * @author Junpee
 */

#ifndef THREAD_H_
#define THREAD_H_

#include <Core/Thread/Runnable.h>

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * スレッド
 *
 * スレッドはマルチスレッド版のCランタイムライブラリを必要とします。ビルドできない
 * 場合はランタイムライブラリの設定がマルチスレッドになっているか確認をしてください。
 */
class Thread : public Runnable{
friend class LampCore;
public:
	/// 優先度
	enum Priority{
		/// タイムクリティカル
		priorityTimeCritical =	THREAD_PRIORITY_TIME_CRITICAL,
		/// とても高い
		priorityHighest =		THREAD_PRIORITY_HIGHEST,
		/// 高い
		priorityHigh =			THREAD_PRIORITY_ABOVE_NORMAL,
		/// 通常
		priorityNormal =		THREAD_PRIORITY_NORMAL,
		/// 低い
		priorityLow =			THREAD_PRIORITY_BELOW_NORMAL,
		/// とても低い
		priorityLowest =		THREAD_PRIORITY_LOWEST,
		/// アイドル
		priorityIdle =			THREAD_PRIORITY_IDLE,
	};

	//--------------------------------------------------------------------------
	// 初期化、終了処理
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 */
	Thread();

	/**
	 * コンストラクタ
	 * @param runnable 実行対象
	 */
	Thread(Runnable* runnable);

	/**
	 * コンストラクタ
	 * @param lockObject ロックオブジェクト
	 * @param deleteLockObject ロックオブジェクトをThreadが削除するならtrue
	 */
	Thread(LockObject* lockObject, bool deleteLockObject);

	/**
	 * コンストラクタ
	 * @param runnable 実行対象
	 * @param lockObject ロックオブジェクト
	 * @param deleteLockObject ロックオブジェクトをThreadが削除するならtrue
	 */
	Thread(Runnable* runnable, LockObject* lockObject, bool deleteLockObject);

	/**
	 * デストラクタ
	 */
	virtual ~Thread();

	//--------------------------------------------------------------------------
	// スレッドの操作
	//--------------------------------------------------------------------------
	/**
	 * スレッドを開始する
	 */
	virtual void start();

	/**
	 * スレッドをセットアップする
	 */
	virtual void setup();

	/**
	 * 実行
	 * @param thread 実行しているスレッド
	 *
	 * isStopRequested()がtrueを返す場合は速やかに処理を終了させる
	 */
	virtual void run(Thread* thread){}

	/**
	 * スレッドの終了を依頼する
	 */
	virtual void requestStop();

	/**
	 * スレッドの終了を依頼し、終了を待つ
	 */
	virtual void stop(){ stop(INFINITE); }

	/**
	 * スレッドの終了を依頼し、終了を待つ
	 * @param milliseconds タイムアウトまでのミリ秒を指定する
	 * @return 終了していればtrueを返す、falseならタイムアウト
	 */
	virtual bool stop(u_int milliseconds);

	/**
	 * スレッドの終了を待つ
	 */
	virtual void join(){ join(INFINITE); }

	/**
	 * スレッドの終了を待つ
	 * @param milliseconds タイムアウトまでのミリ秒を指定する
	 * @return 終了していればtrueを返す、falseならタイムアウト
	 */
	virtual bool join(u_int milliseconds);

	//--------------------------------------------------------------------------
	/**
	 * プライオリティの設定
	 */
	virtual void setPriority(Priority priority);

	/**
	 * プライオリティの取得
	 */
	virtual Priority getPriority();

	//--------------------------------------------------------------------------
	/**
	 * サスペンド
	 *
	 * ロックをかけるので自分自身のsuspendは呼べない
	 */
	virtual void suspend();

	/**
	 * レジューム
	 */
	virtual void resume();

	//--------------------------------------------------------------------------
	// メンバアクセサ
	//--------------------------------------------------------------------------
	/**
	 * スレッドハンドルの取得
	 * @return スレッドハンドル
	 */
	virtual HANDLE getThreadHandle() const{ return threadHandle_; }

	/**
	 * スレッドIDの取得
	 * @return スレッドID
	 */
	virtual u_int getThreadID() const{ return threadID_; }

	/**
	 * スレッドが終了しているか
	 * @return スレッドが終了していればtrue
	 */
	virtual bool isFinished() const{ return isFinished_; }

	/**
	 * スタックサイズの取得
	 * @return スタックサイズ
	 *
	 * このメソッドをオーバーライドすることによりスタックサイズを変更できます
	 */
	virtual u_int getStackSize(){ return 1024 * 1024; }

	//--------------------------------------------------------------------------
	// 静的関数
	//--------------------------------------------------------------------------
	/**
	 * カレントスレッドの休止
	 * @param milliseconds 休止時間をミリ秒で指定する
	 */
	static void sleep(u_int milliseconds){ ::Sleep(milliseconds); }

	/**
	 * カレントスレッドから制御を譲る
	 */
	static void yield(){ ::Sleep(0); }

	//--------------------------------------------------------------------------
	// 使用不可
	//--------------------------------------------------------------------------
	/**
	 * スレッドの実行ラッパ
	 *
	 * このメソッドはシステムから利用されるので決して呼び出さないで下さい
	 */
	virtual u_int executeWrapper();

	//--------------------------------------------------------------------------
protected:
	/**
	 * スレッドの作成
	 */
	virtual void createThread();

private:
	/**
	 * 初期化
	 */
	static void initialize();

	/**
	 * 後始末
	 */
	static void finalize();

	// 実行対象
	Runnable* runnable_;
	// スレッドハンドル
	HANDLE threadHandle_;
	// スレッドID
	u_int threadID_;
	// スレッドが終了しているか
	volatile bool isFinished_;

	// 不正なスレッドハンドル
	static const HANDLE invalidThreadHandle;
};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of THREAD_H_
//------------------------------------------------------------------------------
