//------------------------------------------------------------------------------
// 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 INPUT_DEVICE_H_
#define INPUT_DEVICE_H_

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * 入力デバイス
 */
class InputDevice{
public:
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 * @param exclusive 排他モードならtrue
	 */
	InputDevice(bool exclusive) : inputDevice_(NULL), windowHandle_(NULL),
		exclusive_(exclusive), foreground_(true), initialized_(false){}

	/**
	 * デストラクタ
	 */
	virtual ~InputDevice(){
		SafeRelease(inputDevice_);
	}

	/**
	 * 初期化
	 * @param inputDevice 入力デバイス
	 * @param windowHandle ウィンドウハンドル
	 * @return 成功すればtrue
	 */
	virtual bool initialize(
		DirectInputDevice* inputDevice, HWND windowHandle){
		Assert(inputDevice != NULL);
		inputDevice_ = inputDevice;
		windowHandle_ = windowHandle;
		// デバイスインスタンスの取得
		instance_.dwSize = sizeof(DIDEVICEINSTANCE);
		if(DirectXFailed(inputDevice->GetDeviceInfo(&instance_))){
			ErrorOut("InputDevice::initialize() "
				"GetDeviceInfo()に失敗しました。");
			return false;
		}
		// デバイス能力の取得
		capabilities_.dwSize = sizeof(DIDEVCAPS);
		if(DirectXFailed(inputDevice->GetCapabilities(&capabilities_))){
			ErrorOut("InputDevice::initialize() "
				"GetCapabilities()に失敗しました。");
			return false;
		}
		initialized_ = true;
		return true;
	}

	//--------------------------------------------------------------------------
	/**
	 * アクセス権の取得
	 * @return アクセス権の取得に成功すればtrue
	 */
	virtual bool acquire(){
		Assert(initialized_);
		HRESULT result = inputDevice_->Acquire();
		if(DirectXSucceeded(result)){ return true; }
		if(result != DIERR_OTHERAPPHASPRIO){
			ErrorOut("InputDevice::acquire() Acquire()に失敗しました。");
		}
		return false;
	}

	/**
	 * アクセス権の解放
	 */
	virtual void unacquire(){
		Assert(initialized_);
		inputDevice_->Unacquire();
	}

	//--------------------------------------------------------------------------
	/**
	 * ポーリング
	 * @return ポーリングが正常であればtrue
	 */
	virtual bool polling(){
		if(isPolled()){ inputDevice_->Poll(); }
		return true;
	}

	//--------------------------------------------------------------------------
	/**
	 * 協調レベルの設定
	 * @param exclusive 排他モードならtrue
	 * @param foreground フォアグラウンドモードならtrue
	 * @return 成功すればtrue
	 */
	virtual bool setCooperativeLevel(bool exclusive, bool foreground){
		if(inputDevice_ != NULL){
			// フラグ作成
			u_int flag = DISCL_NOWINKEY;
			if(exclusive){ flag |= DISCL_EXCLUSIVE; }
			else{ flag |= DISCL_NONEXCLUSIVE; }
			if(foreground){ flag |= DISCL_FOREGROUND; }
			else{ flag |= DISCL_BACKGROUND; }
			unacquire();
			if(DirectXFailed(inputDevice_->SetCooperativeLevel(
				windowHandle_,flag))){
				ErrorOut("InputDevice::setCooperativeLevel() "
					"SetCooperativeLevel()に失敗しました。");
				return false;
			}
			acquire();
		}
		exclusive_ = exclusive;
		foreground_ = foreground;
		return true;
	}

	/**
	 * 排他モードか
	 * @return 排他モードならtrue
	 */
	virtual bool isExclusive() const{ return exclusive_; }

	/**
	 * フォアグラウンドモードか
	 * @return フォアグラウンドモードならtrue、バックグラウンドモードならfalse
	 */
	virtual bool isForeground() const{ return foreground_; }

	//--------------------------------------------------------------------------
	/**
	 * プロダクト名の取得
	 * @return プロダクト名
	 */
	virtual String getProductName() const{
		return String(instance_.tszProductName);
	}

	/**
	 * インスタンス名の取得
	 * @return インスタンス名
	 */
	virtual String getInstanceName() const{
		return String(instance_.tszInstanceName);
	}

	/**
	 * 軸数の取得
	 * @return 軸数
	 */
	virtual int getAxisCount() const{ return capabilities_.dwAxes; }

	/**
	 * ボタン数の取得
	 * @return ボタン数
	 */
	virtual int getButtonCount() const{ return capabilities_.dwButtons; }

	/**
	 * 視点コントローラ数の取得
	 * @return 視点コントローラ数
	 */
	virtual int getPOVCount() const{ return capabilities_.dwPOVs; }

	/**
	 * デバイスがアタッチされているか
	 * @return デバイスがアタッチされていればtrue
	 */
	virtual bool isAttached() const{
		return ((capabilities_.dwFlags & DIDC_ATTACHED) != 0);
	}

	/**
	 * ポーリングが必要か
	 * @return ポーリングが必要ならtrue
	 */
	virtual bool isPolled() const{
		return ((capabilities_.dwFlags & DIDC_POLLEDDATAFORMAT) != 0);
	}

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

	/**
	 * 入力デバイス文字列の取得
	 * @return 入力デバイス文字列
	 */
	virtual String getInputDeviceString() const{
		Assert(initialized_);
		String result;
		result.format("ProductName = %s\nInstanceName = %s\n"
			"軸数 = %d  ボタン数 = %d  視点コントローラ = %d\n"
			"アタッチ = %d  ポーリング = %d\n",
			getProductName().getBytes(), getInstanceName().getBytes(),
			getAxisCount(), getButtonCount(), getPOVCount(),
			isAttached(), isPolled());
		return result;
	}

	//--------------------------------------------------------------------------
protected:
	/**
	 * 排他モードの設定
	 * @param exclusive 排他モードならtrue
	 */
	virtual void setExclusive(bool exclusive){ exclusive_ = exclusive; }

	/**
	 * フォアグラウンドモードの設定
	 * @param foreground フォアグラウンドモードならtrue
	 * バックグラウンドモードならfalse
	 */
	virtual void setForeground(bool foreground){ foreground_ = foreground; }

	/// 入力デバイス
	DirectInputDevice* inputDevice_;
	/// ウィンドウハンドル
	HWND windowHandle_;

	//--------------------------------------------------------------------------
private:
	// コピーコンストラクタの隠蔽
	InputDevice(const InputDevice& copy);

	// 代入コピーの隠蔽
	void operator =(const InputDevice& copy);

	/// デバイスのインスタンス
	DIDEVICEINSTANCE instance_;
	/// デバイスの能力
	DIDEVCAPS capabilities_;
	/// 排他モードフラグ
	bool exclusive_;
	/// フォアグラウンドモードフラグ
	bool foreground_;
	/// 初期化フラグ
	bool initialized_;

};

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