//------------------------------------------------------------------------------
// 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
 * Lamp入力ヘッダ
 * @author Junpee
 */

#ifndef LAMP_INPUT_H_
#define LAMP_INPUT_H_

#include <Core/Container/ArrayList.h>

namespace Lamp{

class BufferedInput;
class Keyboard;
class KeyboardDevice;
class Mouse;
class MouseDevice;
class Joystick;
class JoystickDevice;
class BinaryWriter;
class BinaryReader;

//------------------------------------------------------------------------------
/**
 * Lamp入力
 */
class LampInput{
friend class LampCore;
public:
	/// 入力モード
	enum InputMode{
		modePolling,
		modeBuffering,
	};

	//--------------------------------------------------------------------------
	// 初期化、後始末
	//--------------------------------------------------------------------------
	/**
	 * 初期化
	 * @param instanceHandle インスタンスハンドル
	 * @param windowHandle ウィンドウハンドル
	 * @param inputMode 入力モード
	 * @return 初期化に成功すればtrue
	 */
	static bool initialize(HINSTANCE instanceHandle, HWND windowHandle,
		InputMode inputMode = modeBuffering);

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

	/**
	 * クリア
	 * 現在の入力をクリアします
	 */
	static void clear();

	/**
	 * バッファクリア
	 * バッファと現在の入力をクリアします
	 */
	static void bufferClear();

	//--------------------------------------------------------------------------
	// 入力モード
	//--------------------------------------------------------------------------
	/**
	 * 入力モードの設定
	 * @param inputMode 入力モード
	 */
	static void setInputMode(InputMode inputMode);

	/**
	 * 入力モードの取得
	 * @return 入力モード
	 */
	static InputMode getInputMode(){ return inputMode_; }

	//--------------------------------------------------------------------------
	// ポーリング入力
	//--------------------------------------------------------------------------
	/**
	 * ポーリング
	 * @return ポーリングが正常であればtrue
	 */
	static bool polling();

	//--------------------------------------------------------------------------
	// バッファ入力
	//--------------------------------------------------------------------------
	/**
	 * 入力があるか
	 * @return 入力があればtrue
	 */
	static bool hasMoreInput();

	/**
	 * 入力を待つ
	 */
	static void waitForInput();

	/**
	 * 次の入力
	 */
	static void nextInput();

	/**
	 * 入力数の取得
	 * @return 入力数
	 */
	static int getInputCount();

	//--------------------------------------------------------------------------
	// ログ取得
	//--------------------------------------------------------------------------
	/**
	 * ログ取得の開始
	 * @param filePath ファイルパス
	 */
	static void startLogging(const String& filePath = "LampInputLog.log");

	/**
	 * ログ取得の開始
	 * @param binaryWriter バイナリライタ
	 */
	static void startLogging(BinaryWriter* binaryWriter);

	/**
	 * ログ取得の終了
	 */
	static void endLogging();

	/**
	 * ログ取得中かどうか
	 * @return ログ取得中ならtrue
	 */
	static bool isLogging(){ return isLogging_; }

	//--------------------------------------------------------------------------
	// ログ再生
	//--------------------------------------------------------------------------
	/**
	 * ログ再生の開始
	 * @param filePath ファイルパス
	 */
	static void playLog(const String& filePath = "LampInputLog.log");

	/**
	 * ログ再生の開始
	 * @param binaryReader バイナリリーダ
	 */
	static void playLog(BinaryReader* binaryReader);

	/**
	 * ログ再生の停止
	 */
	static void stopLog();

	/**
	 * ログ再生中かどうか
	 * @return ログ再生中ならtrue
	 */
	static bool isLogPlaying(){ return isLogPlaying_; }

	//--------------------------------------------------------------------------
	// 各種デバイス
	//--------------------------------------------------------------------------
	/**
	 * キーボードの取得
	 * @return キーボード
	 */
	static Keyboard* getKeyboard(){ return keyboard_; }

	/**
	 * キーボードデバイスの取得
	 * @return キーボードデバイス
	 */
	static KeyboardDevice* getKeyboardDevice(){ return keyboardDevice_; }

	//--------------------------------------------------------------------------
	/**
	 * マウスの取得
	 * @return マウス
	 */
	static Mouse* getMouse(){ return mouse_; }

	/**
	 * マウスデバイスの取得
	 * @return マウスデバイス
	 */
	static MouseDevice* getMouseDevice(){ return mouseDevice_; }

	//--------------------------------------------------------------------------
	/**
	 * ジョイスティック数の取得
	 * @return ジョイスティック数
	 */
	static int getJoystickCount(){ return joysticks_.getCount(); }

	/**
	 * ジョイスティックの取得
	 * @param index ジョイスティックインデックス
	 * @return ジョイスティック
	 */
	static Joystick* getJoystick(int index){ return joysticks_[index]; }

	/**
	 * ジョイスティックデバイス数の取得
	 * @return ジョイスティックデバイス数
	 */
	static int getJoystickDeviceCount(){ return joystickDevices_.getCount(); }

	/**
	 * ジョイスティックデバイスの取得
	 * @param index ジョイスティックデバイスインデックス
	 * @return ジョイスティックデバイス
	 */
	static JoystickDevice* getJoystickDevice(int index){
		return joystickDevices_[index];
	}

	//--------------------------------------------------------------------------
	/**
	 * ジョイスティックの列挙コールバック
	 *
	 * ユーザはこのメソッドを呼び出さないで下さい
	 * @param instance デバイスインスタンス
	 * @param userData ユーザデータ
	 * @return 列挙継続フラグ
	 */
	static int __stdcall joystickEnumeration(
		const DIDEVICEINSTANCE* instance, void* userData);

private:
	//--------------------------------------------------------------------------
	/**
	 * ウィンドウプロシージャ
	 * @param windowHandle ウィンドウハンドル
	 * @param message メッセージ
	 * @param wParam wメッセージパラメータ
	 * @param lParam lメッセージパラメータ
	 * @return メッセージを処理し、それ以上の処理が必要無いならば0以外を返す。
	 */
	static LRESULT windowProcedure(
		HWND windowHandle, u_int message, WPARAM wParam, LPARAM lParam);

	//--------------------------------------------------------------------------
	// デバイスポーリング
	static bool devicePolling();
	// ログポーリング
	static void logPolling();
	// ログの書き出し
	static void writeLog();

	// バッファ入力初期化
	static void initializeBufferInput();
	// バッファ入力後始末
	static void finalizeBufferInput();
	// コンストラクタの隠蔽
	LampInput();

	// ウィンドウハンドル
	static HWND windowHandle_;
	// DirectInput
	static DirectInput* directInput_;
	// 入力モード
	static InputMode inputMode_;
	// バッファ入力
	static BufferedInput* bufferedInput_;

	// ログライタ
	static BinaryWriter* logWriter_;
	// バイナリファイルライタ
	static BinaryWriter* binaryFileWriter_;
	// ログリーダ
	static BinaryReader* logReader_;
	// バイナリファイルリーダ
	static BinaryReader* binaryFileReader_;

	// キーボード
	static Keyboard* keyboard_;
	// キーボードデバイス
	static KeyboardDevice* keyboardDevice_;
	// マウス
	static Mouse* mouse_;
	// マウスデバイス
	static MouseDevice* mouseDevice_;
	// ジョイスティック
	static ArrayList<Joystick*> joysticks_;
	// ジョイスティックデバイス
	static ArrayList<JoystickDevice*> joystickDevices_;

	// 初期化フラグ
	static bool isInitialized_;
	// ログ取得中フラグ
	static bool isLogging_;
	// ログ再生中フラグ
	static bool isLogPlaying_;
};

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