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

#include "LampBasic.h"
#include "Input/Joystick/JoystickDevice.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
JoystickDevice::JoystickDevice() : InputDevice(true), povCount_(0),
	sliderCount_(0), hasXAxis_(false), hasYAxis_(false), hasZAxis_(false),
	hasXRotation_(false), hasYRotation_(false), hasZRotation_(false){
}
//------------------------------------------------------------------------------
// デストラクタ
JoystickDevice::~JoystickDevice(){
}
//------------------------------------------------------------------------------
// 初期化
bool JoystickDevice::initialize(DirectInputDevice* inputDevice, HWND windowHandle){
	if(!InputDevice::initialize(inputDevice, windowHandle)){ return false; }
	// データフォーマットの指定
	if(DirectXFailed(inputDevice->SetDataFormat(&c_dfDIJoystick2))){
		ErrorOut("JoystickDevice::initialize() "
			"ジョイスティックデバイスのデータフォーマット指定に失敗しました。");
		return false;
	}
	// デバイスオブジェクトの列挙
	if(DirectXFailed(inputDevice->EnumObjects(
		joystickObjectEnumeration, this, DIDFT_ALL))){
		ErrorOut("JoystickDevice::initialize() "
			"ジョイスティックデバイスオブジェクトの列挙に失敗しました。");
		return false;
	}
	// 優先度の指定
	if(!setCooperativeLevel(isExclusive(), isForeground())){ return false; }
	return true;
}
//------------------------------------------------------------------------------
// ジョイスティックオブジェクトの列挙コールバック
int __stdcall JoystickDevice::joystickObjectEnumeration(
	const DIDEVICEOBJECTINSTANCE* instance, void* userData){
	JoystickDevice* joystickDevice = (JoystickDevice* )userData;
	if(!joystickDevice->checkJoystickObject(instance)){ return DIENUM_STOP; }
	return DIENUM_CONTINUE;
}
//------------------------------------------------------------------------------
// ジョイスティックオブジェクトのチェック
bool JoystickDevice::checkJoystickObject(
	const DIDEVICEOBJECTINSTANCE* instance){
	// 軸の範囲を設定する
	if((instance->dwType & DIDFT_AXIS) != 0){
		DIPROPRANGE range;
		range.diph.dwSize = sizeof(DIPROPRANGE);
		range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
		range.diph.dwHow = DIPH_BYID;
		range.diph.dwObj = instance->dwType;
		range.lMin = minAxisValue;
		range.lMax = maxAxisValue;
		if(DirectXFailed(inputDevice_->SetProperty(DIPROP_RANGE, &range.diph))){
			ErrorOut("JoystickDevice::initialize() "
				"ジョイスティックの軸範囲設定に失敗しました。");
			return false;
		}
	}
	// スライダ以外の軸にデッドゾーンと飽和ゾーン設定
	if(((instance->dwType & DIDFT_AXIS) != 0) &&
		(instance->guidType != GUID_Slider)){
		DIPROPDWORD property;
		property.diph.dwSize = sizeof(DIPROPDWORD);
		property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
		property.diph.dwHow = DIPH_BYID;
		property.diph.dwObj = instance->dwType;
		property.dwData = deadZone_;
		if(DirectXFailed(inputDevice_->SetProperty(
			DIPROP_DEADZONE, &property.diph))){
			ErrorOut("JoystickDevice::initialize() "
				"ジョイスティックのデッドゾーン設定に失敗しました。");
			return false;
		}
		property.dwData = saturationZone_;
		if(DirectXFailed(inputDevice_->SetProperty(
			DIPROP_SATURATION, &property.diph))){
			ErrorOut("JoystickDevice::initialize() "
				"ジョイスティックの飽和ゾーン設定に失敗しました。");
			return false;
		}
	}
	// X軸を持っているか
	if(instance->guidType == GUID_XAxis){ hasXAxis_ = true; }
	// Y軸を持っているか
	if(instance->guidType == GUID_YAxis){ hasYAxis_ = true; }
	// Z軸を持っているか
	if(instance->guidType == GUID_ZAxis){ hasZAxis_ = true; }
	// X回転を持っているか
	if(instance->guidType == GUID_RxAxis){ hasXRotation_ = true; }
	// Y回転を持っているか
	if(instance->guidType == GUID_RyAxis){ hasYRotation_ = true; }
	// Z回転を持っているか
	if(instance->guidType == GUID_RzAxis){ hasZRotation_ = true; }
	// 視点コントローラか
	if(instance->guidType == GUID_POV){ povCount_++; }
	// スライダか
	if(instance->guidType == GUID_Slider){ sliderCount_++; }
	return true;
}
//------------------------------------------------------------------------------
// ポーリング
bool JoystickDevice::polling(){
	InputDevice::polling();
	// ジョイスティックデバイスステート取得
	DIJOYSTATE2 state;
	HRESULT result = inputDevice_->GetDeviceState(
		sizeof(DIJOYSTATE2), &state);
	if(DirectXSucceeded(result)){
		// とりあえずDIJOYSTATEの範囲でステート取得
		joystickState_.setXAxis(state.lX);
		joystickState_.setYAxis(state.lY);
		joystickState_.setZAxis(state.lZ);
		joystickState_.setXRotation(state.lRx);
		joystickState_.setYRotation(state.lRy);
		joystickState_.setZRotation(state.lRz);
		for(int i = 0; i < maxPOVCount; i++){
			joystickState_.setPOV(i, state.rgdwPOV[i]);
		}
		for(int i = 0; i < maxSliderCount; i++){
			joystickState_.setSlider(i, state.rglSlider[i]);
		}
		for(int i = 0; i < maxButtonCount; i++){
			joystickState_.setButtonPressed(i,
				((state.rgbButtons[i] & 0x80) != 0));
		}
		return true;
	}else{
		// エラーなら入力無し
		joystickState_.clear();
		// 深刻なエラーでないかチェック
		if((result != DIERR_INPUTLOST) && (result != DIERR_NOTACQUIRED)){
			ErrorOut("GetDeviceState()に失敗しました。");
		}else{
			// デバイス再取得
			acquire();
		}
	}
	return false;
}
//------------------------------------------------------------------------------
// 文字列への変換
String JoystickDevice::toString() const{
	String result = getInputDeviceString();
	String joystickString;
	joystickString.format("Axis ( %d %d %d ) Rotation ( %d %d %d )  "
		"POV %d  Slider %d\n",
		hasXAxis(), hasYAxis(), hasZAxis(),
		hasXRotation(), hasYRotation(), hasZRotation(),
		getPOVCount(), getSliderCount());
	result += joystickString;
	result += joystickState_.toString();
	return result;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
