//------------------------------------------------------------------------------
// 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
 * PS2互換パッドヘッダ
 * @author Junpee
 */

#ifndef PS2_PAD_H_
#define PS2_PAD_H_

#include <Input/Pad/Pad.h>

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * PS2互換パッド
 *
 * 主にELECOM、LOASのPS2コントローラ変換ケーブルを使用した場合に対応している。
 * FFXI互換を謳っているUSBパッドはボタン並びが違っている模様。
 * SmartJoypadにも対応、Z軸、Z回転の扱いが逆になり、十字キーをボタンで認識している。
 */
class PS2Pad : public Pad{
public:
	/**
	 * 互換性チェック
	 * @param joystick 互換性をチェックするジョイスティック
	 * @return 互換性があればtrueを返す
	 */
	static bool checkCompatibility(Joystick* joystick);

	/// ボタン
	enum Button{
		button0 = 0,
		button1,
		button2,
		button3,
		buttonL2,
		buttonR2,
		buttonL1,
		buttonR1,
		buttonStart,
		buttonSelect,
		buttonL3,
		buttonR3,
		buttonPOVUp,
		buttonPOVRight,
		buttonPOVDown,
		buttonPOVLeft,
		maxButtonCount,
		buttonUnknown = -1,
		buttonSankaku = 0,
		buttonMaru = 1,
		buttonBatu = 2,
		buttonSikaku = 3,
	};

	//--------------------------------------------------------------------------
	// 生成、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 * @param joystick 使用するジョイスティック
	 */
	PS2Pad(Joystick* joystick);

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

	//--------------------------------------------------------------------------
	// ボタンマップ
	//--------------------------------------------------------------------------
	/**
	 * ボタンマップの変更
	 * @param button ボタンマップを変更するボタン
	 * @param id 変更するボタンID
	 */
	virtual void changeButtonMap(Button button, int id);

	/**
	 * ボタンマップの取得
	 * @param button ボタンマップを取得するボタン
	 * @return ボタンID
	 */
	virtual int getButtonMap(const Button button){
		Assert((button >= 0) && (button < maxButtonCount));
		return buttonMap_[button];
	}

	//--------------------------------------------------------------------------
	// 軸データの取得
	//--------------------------------------------------------------------------
	/**
	 * 左軸の取得
	 * @return 左軸
	 */
	virtual Point2f getLeftAxis() const{
		return Point2f(getLeftXAxis(), getLeftYAxis());
	}

	/**
	 * 左X軸の取得
	 * @return 左X軸
	 */
	virtual float getLeftXAxis() const;

	/**
	 * 左Y軸の取得
	 * @return 左Y軸
	 */
	virtual float getLeftYAxis() const;

	//--------------------------------------------------------------------------
	/**
	 * 右軸の取得
	 * @return 右軸
	 */
	virtual Point2f getRightAxis() const{
		return Point2f(getRightXAxis(), getRightYAxis());
	}

	/**
	 * 右X軸の取得
	 * @return 右X軸
	 */
	virtual float getRightXAxis() const;

	/**
	 * 右Y軸の取得
	 * @return 右Y軸
	 */
	virtual float getRightYAxis() const;

	//--------------------------------------------------------------------------
	// 十字キーデータの取得
	//--------------------------------------------------------------------------
	/**
	 * 上キーが押されているか
	 * @return 上キーが押されていればtrue
	 */
	virtual bool upKeyPressed() const;

	/**
	 * 上キーが下がった
	 * @return 上キーが下がったならばtrue
	 */
	virtual bool upKeyDown() const;

	/**
	 * 上キーが上がった
	 * @return 上キーが上がったならばtrue
	 */
	virtual bool upKeyUp() const;

	//--------------------------------------------------------------------------
	/**
	 * 下キーが押されているか
	 * @return 下キーが押されていればtrue
	 */
	virtual bool downKeyPressed() const;

	/**
	 * 下キーが下がった
	 * @return 下キーが下がったならばtrue
	 */
	virtual bool downKeyDown() const;

	/**
	 * 下キーが上がった
	 * @return 下キーが上がったならばtrue
	 */
	virtual bool downKeyUp() const;

	//--------------------------------------------------------------------------
	/**
	 * 左キーが押されているか
	 * @return 左キーが押されていればtrue
	 */
	virtual bool leftKeyPressed() const;

	/**
	 * 左キーが下がった
	 * @return 左キーが下がったならばtrue
	 */
	virtual bool leftKeyDown() const;

	/**
	 * 左キーが上がった
	 * @return 左キーが上がったならばtrue
	 */
	virtual bool leftKeyUp() const;

	//--------------------------------------------------------------------------
	/**
	 * 右キーが押されているか
	 * @return 右キーが押されていればtrue
	 */
	virtual bool rightKeyPressed() const;

	/**
	 * 右キーが下がった
	 * @return 右キーが下がったならばtrue
	 */
	virtual bool rightKeyDown() const;

	/**
	 * 右キーが上がった
	 * @return 右キーが上がったならばtrue
	 */
	virtual bool rightKeyUp() const;

	//--------------------------------------------------------------------------
	// ボタンデータの取得
	//--------------------------------------------------------------------------
	/**
	 * ボタンが押されているか
	 * @param button ボタン
	 * @return ボタンが押されていればtrue
	 */
	virtual bool buttonPressed(Button button) const;

	/**
	 * ボタンが下がった
	 * @param button ボタン
	 * @return ボタンが下がったならばtrue
	 */
	virtual bool buttonDown(Button button) const;

	/**
	 * ボタンが上がった
	 * @param button ボタン
	 * @return ボタンが上がったならばtrue
	 */
	virtual bool buttonUp(Button button) const;

	//--------------------------------------------------------------------------
	// 文字列データ取得
	//--------------------------------------------------------------------------
	/**
	 * ボタン文字列の取得
	 * @param button ボタン
	 * @return ボタン文字列
	 */
	static String getButtonString(Button button);

	/**
	 * 文字列への変換
	 * @return 文字列
	 */
	virtual String toString() const;

protected:
	//--------------------------------------------------------------------------
	/**
	 * 視点コントローラ値から上キーへの変換
	 * @param pov 視点コントローラ値
	 * @return 上キーが押されていればtrue
	 */
	inline bool povToUpKey(int pov) const{
		if(((pov & 0xffff) == 0xffff)){ return false; }
		return ((pov >= (deg45 * 7)) && (pov <= (deg45 * 8))) ||
			((pov >= 0) && (pov <= deg45));
	}

	/**
	 * 視点コントローラ値から下キーへの変換
	 * @param pov 視点コントローラ値
	 * @return 下キーが押されていればtrue
	 */
	inline bool povToDownKey(int pov) const{
		if(((pov & 0xffff) == 0xffff)){ return false; }
		return ((pov >= (deg45 * 3)) && (pov <= (deg45 * 5)));
	}

	/**
	 * 視点コントローラ値から左キーへの変換
	 * @param pov 視点コントローラ値
	 * @return 左キーが押されていればtrue
	 */
	inline bool povToLeftKey(int pov) const{
		if(((pov & 0xffff) == 0xffff)){ return false; }
		return ((pov >= (deg45 * 5)) && (pov <= (deg45 * 7)));
	}

	/**
	 * 視点コントローラ値から右キーへの変換
	 * @param pov 視点コントローラ値
	 * @return 右キーが押されていればtrue
	 */
	inline bool povToRightKey(int pov) const{
		if(((pov & 0xffff) == 0xffff)){ return false; }
		return ((pov >= (deg45)) && (pov <= (deg45 * 3)));
	}

	//--------------------------------------------------------------------------
	/// ボタンマップ
	int buttonMap_[maxButtonCount];
	/// スマートジョイパッドフラグ
	bool isSmartJoypad_;

	/// 視点コントローラにおける45度
	static const int deg45 = 4500;

private:

};

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