//------------------------------------------------------------------------------
// 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
 */

#include "LampBasic.h"
#include "Input/Pad/PS2Pad.h"
#include "Input/Joystick/Joystick.h"

namespace Lamp{

//------------------------------------------------------------------------------
// 互換性チェック
bool PS2Pad::checkCompatibility(Joystick* joystick){
	// X軸、Y軸、Z軸、Z回転が必要
	// 互換パッドでこれ以外の割り振りが存在すればAxisMapに対応する
	if(!joystick->hasXAxis()){ return false; }
	if(!joystick->hasYAxis()){ return false; }
	if(!joystick->hasZAxis()){ return false; }
	if(!joystick->hasZRotation()){ return false; }
	// ボタンは12ボタン必要
	if(joystick->getButtonCount() < 12){ return false; }
	// 視点コントローラが一つ必要
	if(joystick->getPOVCount() < 1){
		// 16ボタンあればSmartJoypadと判定する
		if(joystick->getButtonCount() < 16){ return false; }
	}
	return true;
}
//------------------------------------------------------------------------------
// 生成、破棄
//------------------------------------------------------------------------------
// コンストラクタ
PS2Pad::PS2Pad(Joystick* joystick) : Pad(joystick){
	// 互換性チェック
	Assert(checkCompatibility(joystick_));
	// ボタンマップの初期化
	for(int i = 0; i < maxButtonCount; i++){ buttonMap_[i] = i; }
	// POVが無くボタンが16以上あればスマートジョイパッド判定
	isSmartJoypad_ = false;
	if((joystick_->getPOVCount() < 1) && (joystick->getButtonCount() >= 16)){
		isSmartJoypad_ = true;
		// スマートジョイパッド用にボタンマップを修正
		changeButtonMap(buttonStart, buttonSelect);
	}
}
//------------------------------------------------------------------------------
// デストラクタ
PS2Pad::~PS2Pad(){
}
//------------------------------------------------------------------------------
// ボタンマップ
//------------------------------------------------------------------------------
// ボタンマップの変更
void PS2Pad::changeButtonMap(Button button, int id){
	Assert((button >= 0) && (button < maxButtonCount));
	if(buttonMap_[button] == id){ return; }
	int destinationID = buttonMap_[button];
	for(int i = 0; i < maxButtonCount; i++){
		if(buttonMap_[i] == id){ buttonMap_[i] = destinationID; }
	}
	buttonMap_[button] = id;
}
//------------------------------------------------------------------------------
// 軸データの取得
//------------------------------------------------------------------------------
// 左X軸の取得
float PS2Pad::getLeftXAxis() const{
	return joystick_->getXAxis();
}
//------------------------------------------------------------------------------
// 左Y軸の取得
float PS2Pad::getLeftYAxis() const{
	return joystick_->getYAxis();
}
//------------------------------------------------------------------------------
// 右X軸の取得
float PS2Pad::getRightXAxis() const{
	if(isSmartJoypad_){ return joystick_->getZRotation(); }
	return joystick_->getZAxis();
}
//------------------------------------------------------------------------------
// 右Y軸の取得
float PS2Pad::getRightYAxis() const{
	if(isSmartJoypad_){ return joystick_->getZAxis(); }
	return joystick_->getZRotation();
}
//------------------------------------------------------------------------------
// 十字キーデータの取得
//------------------------------------------------------------------------------
// 上キーが押されているか
bool PS2Pad::upKeyPressed() const{
	if(isSmartJoypad_){ return buttonPressed(buttonPOVUp); }
	return povToUpKey(joystick_->getPOV(0));
}
//------------------------------------------------------------------------------
// 上キーが下がった
bool PS2Pad::upKeyDown() const{
	if(isSmartJoypad_){ return buttonDown(buttonPOVUp); }
	return (povToUpKey(joystick_->getPOV(0)) &&
		(!povToUpKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 上キーが上がった
bool PS2Pad::upKeyUp() const{
	if(isSmartJoypad_){ return buttonUp(buttonPOVUp); }
	return (!povToUpKey(joystick_->getPOV(0)) &&
		(povToUpKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 下キーが押されているか
bool PS2Pad::downKeyPressed() const{
	if(isSmartJoypad_){ return buttonPressed(buttonPOVDown); }
	return povToDownKey(joystick_->getPOV(0));
}
//------------------------------------------------------------------------------
// 下キーが下がった
bool PS2Pad::downKeyDown() const{
	if(isSmartJoypad_){ return buttonDown(buttonPOVDown); }
	return (povToDownKey(joystick_->getPOV(0)) &&
		(!povToDownKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 下キーが上がった
bool PS2Pad::downKeyUp() const{
	if(isSmartJoypad_){ return buttonUp(buttonPOVDown); }
	return (!povToDownKey(joystick_->getPOV(0)) &&
		(povToDownKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 左キーが押されているか
bool PS2Pad::leftKeyPressed() const{
	if(isSmartJoypad_){ return buttonPressed(buttonPOVLeft); }
	return povToLeftKey(joystick_->getPOV(0));
}
//------------------------------------------------------------------------------
// 左キーが下がった
bool PS2Pad::leftKeyDown() const{
	if(isSmartJoypad_){ return buttonDown(buttonPOVLeft); }
	return (povToLeftKey(joystick_->getPOV(0)) &&
		(!povToLeftKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 左キーが上がった
bool PS2Pad::leftKeyUp() const{
	if(isSmartJoypad_){ return buttonUp(buttonPOVLeft); }
	return (!povToLeftKey(joystick_->getPOV(0)) &&
		(povToLeftKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 右キーが押されているか
bool PS2Pad::rightKeyPressed() const{
	if(isSmartJoypad_){ return buttonPressed(buttonPOVRight); }
	return povToRightKey(joystick_->getPOV(0));
}
//------------------------------------------------------------------------------
// 右キーが下がった
bool PS2Pad::rightKeyDown() const{
	if(isSmartJoypad_){ return buttonDown(buttonPOVRight); }
	return (povToRightKey(joystick_->getPOV(0)) &&
		(!povToRightKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// 右キーが上がった
bool PS2Pad::rightKeyUp() const{
	if(isSmartJoypad_){ return buttonUp(buttonPOVRight); }
	return (!povToRightKey(joystick_->getPOV(0)) &&
		(povToRightKey(joystick_->getPrePOV(0))));
}
//------------------------------------------------------------------------------
// ボタンデータの取得
//------------------------------------------------------------------------------
// ボタンが押されているか
bool PS2Pad::buttonPressed(Button button) const{
	Assert((button >= 0) && (button < maxButtonCount));
	return joystick_->buttonPressed(buttonMap_[button]);
}
//------------------------------------------------------------------------------
// ボタンが下がった
bool PS2Pad::buttonDown(Button button) const{
	Assert((button >= 0) && (button < maxButtonCount));
	return joystick_->buttonDown(buttonMap_[button]);
}
//------------------------------------------------------------------------------
// ボタンが上がった
bool PS2Pad::buttonUp(Button button) const{
	Assert((button >= 0) && (button < maxButtonCount));
	return joystick_->buttonUp(buttonMap_[button]);
}
//------------------------------------------------------------------------------
// 文字列データ取得
//------------------------------------------------------------------------------
// ボタン文字列の取得
String PS2Pad::getButtonString(Button button){
	if(button == -1){ return "Unknown"; }
	Assert((button >= 0) && (button < maxButtonCount));
	String buttonString[] = {
		"Sankaku", "Maru", "Batu", "Sikaku",
		"L2", "R2", "L1", "R1", "Start", "Select", "L3", "R3",
	};
	return buttonString[button];
}
//------------------------------------------------------------------------------
// 文字列への変換
String PS2Pad::toString() const{
	String result, temp;
	result = Pad::toString();
	// 軸データ
	temp.format(" Axis ( %5.2f , %5.2f ) ( %5.2f , %5.2f )\n",
		getLeftXAxis(), getLeftYAxis(), getRightXAxis(), getRightYAxis());
	result += temp;
	// 十字キー
	result += "          Press Down   Up\n";
	temp.format(" UpKey        %d    %d    %d\n",
		upKeyPressed(), upKeyDown(), upKeyUp());
	result += temp;
	temp.format(" DownKey      %d    %d    %d\n",
		downKeyPressed(), downKeyDown(), downKeyUp());
	result += temp;
	temp.format(" LeftKey      %d    %d    %d\n",
		leftKeyPressed(), leftKeyDown(), leftKeyUp());
	result += temp;
	temp.format(" RightKey     %d    %d    %d\n",
		rightKeyPressed(), rightKeyDown(), rightKeyUp());
	result += temp;
	// ボタン
	temp.format(" Sankaku      %d    %d    %d\n",
		buttonPressed(buttonSankaku), buttonDown(buttonSankaku),
		buttonUp(buttonSankaku));
	result += temp;
	temp.format(" Maru         %d    %d    %d\n",
		buttonPressed(buttonMaru), buttonDown(buttonMaru),
		buttonUp(buttonMaru));
	result += temp;
	temp.format(" Batu         %d    %d    %d\n",
		buttonPressed(buttonBatu), buttonDown(buttonBatu),
		buttonUp(buttonBatu));
	result += temp;
	temp.format(" Sikaku       %d    %d    %d\n",
		buttonPressed(buttonSikaku), buttonDown(buttonSikaku),
		buttonUp(buttonSikaku));
	result += temp;
	temp.format(" L2           %d    %d    %d\n",
		buttonPressed(buttonL2), buttonDown(buttonL2),
		buttonUp(buttonL2));
	result += temp;
	temp.format(" R2           %d    %d    %d\n",
		buttonPressed(buttonR2), buttonDown(buttonR2),
		buttonUp(buttonR2));
	result += temp;
	temp.format(" L1           %d    %d    %d\n",
		buttonPressed(buttonL1), buttonDown(buttonL1),
		buttonUp(buttonL1));
	result += temp;
	temp.format(" R1           %d    %d    %d\n",
		buttonPressed(buttonR1), buttonDown(buttonR1),
		buttonUp(buttonR1));
	result += temp;
	temp.format(" Start        %d    %d    %d\n",
		buttonPressed(buttonStart), buttonDown(buttonStart),
		buttonUp(buttonStart));
	result += temp;
	temp.format(" Select       %d    %d    %d\n",
		buttonPressed(buttonSelect), buttonDown(buttonSelect),
		buttonUp(buttonSelect));
	result += temp;
	temp.format(" L3           %d    %d    %d\n",
		buttonPressed(buttonL3), buttonDown(buttonL3),
		buttonUp(buttonL3));
	result += temp;
	temp.format(" R3           %d    %d    %d\n",
		buttonPressed(buttonR3), buttonDown(buttonR3),
		buttonUp(buttonR3));
	result += temp;

	return result;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
