module y4d_input.virtualkey;

//----------------------------------------------------------------------------
//	キー入力統合クラス
//----------------------------------------------------------------------------
private import y4d_input.keyinputbase;
private import ytl.vector;

/// 統合キー入力クラス。CKeyBaseの派生クラスを利用して、それらをひとまとめにして管理できる。
/**
	たとえば、キーボードの↑キーと、テンキーの８キー、
	ジョイスティックの↑入力を、一つの仮想キーとして登録することによって、
	それらのどれか一つが入力されているかを、関数をひとつ呼び出すだけで
	判定できるようになる。

	実際に Key1,Key2,Key3,Key4 は、
	このクラスの応用事例なので、そちらも参照すること。

	全体的な流れは、キーデバイスの登録→仮想キーの設定としておいて、
	InputしたのちisPress/isPushで判定します。
*/
class VirtualKey : public KeyInputBase {
public:
	///	仮想キーの最大個数。88鍵（＾＾；
	const int VIRTUAL_KEY_MAX = 88;

	///	キーデバイスの登録
	/**	キーデバイスとは、KeyInputBaseの派生クラスのインスタンス。
		具体的にはKeyInput,JoyStick,MidiInputのインスタンスが
		挙げられる。入力したいキーデバイスをまず登録する。
		そしてInputを呼び出すことによって、それらのGetStateが呼び出される。
	*/
	void	clearDevice()				///	デバイスのクリア
	{	aDevice = new vector!(KeyInputBase); }

	void	addDevice(KeyInputBase device)	///	デバイスの登録
	{	aDevice.push_back(device); }

	void	delDevice(KeyInputBase device)	///	デバイスの削除
	{
		for(int i=0;i<aDevice.size();++i)
			if (aDevice[i] is device)
				aDevice.erase(i);
	}

	KeyInputBase getDevice(int n)			///	ｎ番目に登録したデバイスの取得
	/**
		この関数を使えばｎ番目（０から始まる）のaddDeviceしたデバイスを
		取得できる。）
	*/
	{	return aDevice[n]; }

	///	仮想キーのリセット
	void	clearKeyList()
	{
		foreach(inout vector!(KeyInfo) e;keylist)
			e = new vector!(KeyInfo);
	}

	///	仮想キーの追加
	/**
		vkeyは、仮想キー番号。これは0～VIRTUAL_KEY_MAX-1
		(現在88とdefineされている)番まで登録可能。

		<PRE>
		vkey	  = 登録したい仮想キーの番号
		nDeviceNo = 登録したデバイス番号(登録順に0,1,2..。
			これはgetDeviceで取得できるデバイスと同じ)
		key 	  = nDeviceNoで指定されたデバイスのkey番号
		</PRE>
	*/
	void	addKey(int vkey,int nDeviceNo,int key)
	{
		KeyInfo k = new KeyInfo(nDeviceNo,key);
		keylist[vkey].push_back(k);
	}

	///	仮想キーの削除
	void	delKey(int vkey,int nDeviceNo,int key)
	/**
		vkeyは、仮想キー番号。これは0～VIRTUAL_KEY_MAX-1
		(現在88とdefineされている)番まで使用可能。

		addKeyで指定したときのパラメータを指定して登録を解除できる。
	*/
	{
		for(int i=0;i<keylist[vkey].size();++i)
			if (keylist[vkey][i].deviceNo_ == nDeviceNo
				&& keylist[vkey][i].keyNo_ == key) {
				keylist[vkey].erase(i);
				break;
			}
	}

	///	----	overriden from KeyInputBase	 ------

	///	n番目の仮想キーが前回のupdate以降に押されてたか
	bool	isPush(int nKey) {
		foreach(KeyInfo k;keylist[nKey]){
			if (aDevice[k.deviceNo_].isPush(k.keyNo_)) return true;
		}
		return false;
	}

	///	n番目の仮想キーが現在押されているか(updateを呼び出さないと更新されない)
	bool	isPress(int nKey) {
		foreach(KeyInfo k;keylist[nKey]){
			if (aDevice[k.deviceNo_].isPress(k.keyNo_)) return true;
		}
		return false;
	}

	///	デバイス名"VirtualKeyInput"が返る
	char[]	getDeviceName() { return cast(char[]) "VirtualKeyInput"; }

	///	仮想キーの最大数(VIRTUAL_KEY_MAXの値)
	int		getButtonNum() { return keylist.length; }

	///	デバイスの追加情報(現在nullが返る)
	void*	getInfo() { return null; }

	///　登録しておいたすべてのデバイスのupdateを呼び出す
	void	update() { foreach(KeyInputBase e;aDevice) e.update(); }
	void	updateMark() { foreach(KeyInputBase e;aDevice) e.updateMark(); }

	this() { clearDevice(); clearKeyList(); }

private:
	class KeyInfo {
		int		deviceNo_;
		int		keyNo_;
		this(int deviceNo,int keyNo) { deviceNo_ = deviceNo; keyNo_=keyNo; }
	};
	vector!(KeyInfo) keylist[VIRTUAL_KEY_MAX];	//	入力リスト
	vector!(KeyInputBase) aDevice;	//	入力キーデバイスリスト
};

