module yamalib.input.multimouse;

private import y4d_input.mouse;

/**
	複数のマウスインスタンスを一つに見せかけるための機構<br>
	複数仮想マウスに集約できない処理については、インスタンス生成時に指定した、
	プライマリマウスを対象とし、処理を行う
*/
public class MultiMouse : MouseInput {
	///	マウスカーソルを表示する
	void show() {
		m_primaryMouse.show();
	}

	///	マウスカーソルを非表示にする
	void hide() {
		m_primaryMouse.hide();
	}
	
	bool isHide() {
		return m_primaryMouse.isHide();
	}

	///	マウスの位置取得
	/**
		マウスが画面外にあるときは最後に取得した値が返ります。
		すなわち、画面サイズが640×480ならば、xは0～639,yは0～479までの
		値しか返らないことが保証されます。
	*/
	void getPos(out int x,out int y){
		m_primaryMouse.getPos(x,y);
	}

	///	マウスの位置を設定
	/**
		SDLのマウスの位置設定イベントが発生する。
	*/
	void setPos(uint x,uint y) {
		m_primaryMouse.setPos(x,y);
	}

	///	ボタンが押し下げられているかを判定する関数
	bool isPress(MouseInput.button e) {
		if ( m_primaryMouse.isPress(e) ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isPress(e) ) {
					return true;
				}
			}
		}
		return false;
	}

	/** これを設定すると n 回 update が呼び出されるまで入力を無視する */
	void setGuardTime(int n) {
		m_primaryMouse.setGuardTime(n);
	}

	/**  左ボタンが押し下げられているか */
	bool isLButtonDown() {
		if ( m_primaryMouse.isLButtonDown() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isLButtonDown() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**  左ボタンが押しあげられたか */
	bool isLButtonUp() {
		if ( m_primaryMouse.isLButtonUp() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isLButtonUp() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/// 左ボタンがダブルクリックされたか
	bool isLButtonDClick() {
		if ( m_primaryMouse.isLButtonDClick() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isLButtonDClick() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**  右ボタンが押し下げられているか */
	bool isRButtonDown() {
		if ( m_primaryMouse.isRButtonDown() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isRButtonDown() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**  右ボタンが押しあげられたか */
	bool isRButtonUp() {
		if ( m_primaryMouse.isRButtonUp() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isRButtonUp() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/// 右ボタンがダブルクリックされたか
	bool isRButtonDClick() {
		if ( m_primaryMouse.isRButtonDClick() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isRButtonDClick() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**  中ボタンが押し下げられているか */
	bool isMButtonDwon() {
		if ( m_primaryMouse.isMButtonDwon() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isMButtonDwon() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/**  中ボタンが押しあげられたか */
	bool isMButtonUp() {
		if ( m_primaryMouse.isMButtonUp() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isMButtonUp() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/// 中ボタンがダブルクリックされたか
	bool isMButtonDClick() {
		if ( m_primaryMouse.isMButtonDClick() ) {
			return true;
		} else {
			foreach(MouseInput mouse; m_optionalMouse) {
				if ( mouse.isMButtonDClick() ) {
					return true;
				}
			}
		}
		return false;
	}
	
	/// 押し続けているフレーム数を返す
	uint getKeepingTimeL() {
		return m_primaryMouse.getKeepingTimeL();
	}

	/// 押し続けているフレーム数を返す
	uint getKeepingTimeM() {
		return m_primaryMouse.getKeepingTimeM();
	}

	/// 押し続けているフレーム数を返す
	uint getKeepingTimeR() {
		return m_primaryMouse.getKeepingTimeR();
	}
	
	/// 内部状態を更新する
	void update() 
	/**
		この関数が呼ばれた瞬間の情報を保持し、
		次のupdateが呼ばれるまでマウスの状態は同じ状態を返す
	*/
	{
		m_primaryMouse.update();
		foreach(MouseInput mouse; m_optionalMouse) {
			mouse.update();
		}
	}
	
	/// update監視
	void updateMark() {
		m_primaryMouse.updateMark();
		foreach(MouseInput mouse; m_optionalMouse) {
			mouse.updateMark();
		}
	}
	
	/// マウスを追加する
	void addMouse(MouseInput mouse) 
	in
	{
		assert( !(mouse is null) );
	}
	body
	{
		m_optionalMouse ~= mouse;
	}
	
	/// コンストラクタ
	this(MouseInput primary) 
	in
	{
		assert( !(primary is null) );
	}
	body
	{
		m_primaryMouse = primary;
	}

protected:
	MouseInput m_primaryMouse;
	MouseInput[] m_optionalMouse;
	
}