/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2008.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: include/sgx/input/inputmanager.hpp

*/

#ifndef SGX_INPUT_MANAGER_HPP
#define SGX_INPUT_MANAGER_HPP		1

class CSGXInputManager {
public:
	typedef char tKey;

	typedef enum {
		eButton0 = 0,
		eButton1,
		eButton2,
		eButton3,
		eButton4,
		eButton5,
		eButton6,
		eButton7,
		eButton8,
		eButton9,
		eButton10,
		eButton11,
		eButton12,
		eButton13,
		eButton14,
		eButton15,
		//
		eFirstStick,
		eStick0x,
		eStick0y,
		eStick1x,
		eStick1y,
		eStick2x,
		eStick2y,
		eStick3x,
		eStick3y,
		//
		eLastControl = SGX_ENUM_PADDING
	} tControl;

	typedef enum {
		eMouseButtonLeft = 0,
		eMouseButtonRight,
		eMouseButtonMiddle,
		eMouseButtonLast = SGX_ENUM_PADDING
	} tMouseButton;

typedef enum {
	   ePhysical0 = 0,
	   ePhysical1,
	   ePhysical2,
	   ePhysical3,

	   eFirst,
	   eSecond,
	   eThird,
	   eFourth,

	   eAllLogical,
	   eGUIForwards,
	   eGUIBackwards,
	   eGUISelect,

	   eLastController = SGX_ENUM_PADDING
	} tController;

	class CControlStick {
	public:
		tREAL32           	m_fPosX, m_fPosY;
		tREAL32           	m_fRawPosX, m_fRawPosY;

		CControlStick();
		void reset();
		void update(const tREAL32 telaps);
		void applyPosition(const tREAL32 x, const tREAL32 y);
		void setControlRange(const tREAL32 rangeX);
		void setControlRange(const tREAL32 rangeX, const tREAL32 rangeY);
		void setDeadZone(const tREAL32 range);
		void setClampX(const tREAL32 minX, const tREAL32 minY);
		void setClampY(const tREAL32 minY, const tREAL32 minZ);
		
	private:
		tREAL32 			m_fDeadZone;
		tREAL32 			m_fGivenDeadZone;
		tREAL32				m_fControlRangeX;	// we scale the input from a range of +/- m_fControlRange to +- 1
		tREAL32				m_fControlRangeY;
		tREAL32				m_fScaleRangeX;		// pre-computed value of controlRange-deadzone
		tREAL32				m_fScaleRangeY;
		tREAL32				m_fClampMinX, m_fClampMinY;
		tREAL32				m_fClampMaxX, m_fClampMaxY;
	};

	class CControlButton {
	public:
		tBOOL             	m_bPressed, m_bReleased;
		tBOOL             	m_bIsDown, m_bIsUp;

		CControlButton();
		void reset();
		
		void update(const tREAL32 telaps);

		void applyButton(tBOOL down) { if (down) applyButtonDown(); else applyButtonUp(); }
		void applyButtonDown();
		void applyButtonUp();
		void applyButtonPressed();
		void applyButtonReleased();
	};

	class CKeyboardKey : public CControlButton {
	public:
	};

	//
	// Basic controllers
	//
	class CControllerMouse {	
		// TODO: call them controllers. call the above controls
	public:

		tINT32				x,y;
		CControlButton		m_Buttons[SGX_MAXINP_MOUSEBUTTONS];

		CControllerMouse();
		virtual void reset();
		virtual void update(const tREAL32 telaps, CControllerMouse &result);
	};

	class CControllerKeyboard {
	public:
		CKeyboardKey		m_Key[SGX_MAXINP_KEYBOARD_KEYS];

		CControllerKeyboard();
		virtual void reset();
		virtual void update(const tREAL32 telaps, CControllerKeyboard &result);
	};

	class CControllerJoypad {
	public:
		tBOOL				m_Valid;
		CControlButton		m_Buttons[SGX_MAXINP_BUTTONS];
		CControlStick		m_Sticks[SGX_MAXINP_STICKS];
		CSGXRumbleDevice 	*m_pRumble;

		CControllerJoypad();	// this is so derived classes don't need the (idx) version [which creates a null rumble device]
		CControllerJoypad(tUINT32 idx);
		virtual void reset();
		virtual void update(const tREAL32 telaps, CSGXInputManager::CControllerJoypad &result);	
	};

	// The input manager
	static CSGXInputManager *create();
	static CSGXInputManager *get();

	virtual void 		initializeGeneric();
	virtual void		initialize();
	virtual void		createMapping();
	virtual tUINT32		getNumControllers();
	virtual tUINT32		getMaxControllers();	// must be unchanging

	virtual CSGXInputManager::CControllerJoypad *	createJoypad(tUINT32 idx);
	virtual CSGXInputManager::CControllerKeyboard *	createKeyboard();
	virtual CSGXInputManager::CControllerMouse *	createMouse();

	virtual void		update(const tREAL32 telaps);

	// Application (from platform-specific)
	//. TODO: Remove because this is available from the low-level manager driver
	virtual void		applyKeyboardKeyUp(const tKey &key);
	virtual void		applyKeyboardKeyDown(const tKey &key);
	virtual void		applyKeyboardPressed(const tKey &key);
	virtual void		applyKeyboardReleased(const tKey &key);

	virtual void		applyMouseButton(tMouseButton button, tBOOL bState);
	virtual void		applyMousePosition(const tINT32 x, const tINT32 y);

	// Query (to end user)
	virtual tBOOL		isKeyboardKeyDown(const tKey &key);
	virtual tBOOL		isKeyboardKeyUp(const tKey &key);
	virtual tBOOL		isKeyboardKeyPressed(const tKey &key);
	virtual tBOOL		isKeyboardKeyReleased(const tKey &key);

	virtual tBOOL		isMouseButtonDown(const tMouseButton &button);
	virtual tBOOL		isMouseButtonUp(const tMouseButton &button);
	virtual tBOOL		isMouseButtonPressed(const tMouseButton &button);
	virtual tBOOL		isMouseButtonReleased(const tMouseButton &button);
	virtual tINT32		getMouseX();
	virtual tINT32		getMouseY();

	virtual const CControllerJoypad *getController(tController controller);	// actually returns the device
	virtual const CControlButton &getControlButton(tController controller, tControl button);
	virtual const CControlStick  &getControlStick(tController controller, tControl stick);
	
protected:
	static CSGXInputManager *m_pSingleton;

	struct {
    tBOOL    bState;
    tREAL32  fState;
    tBOOL    bPressed;
    tBOOL    breleased;
} ButtonState;

	//
	// Buffered states. Reflecting the current state
	// (copied to working state on update)
	// These are dynamically allocated because they might
	// contain plaform-specific features
	CControllerJoypad    	**m_pDeviceController;
	CControllerKeyboard		*m_pDeviceKeyboard;
	CControllerMouse		*m_pDeviceMouse;
	tUINT32					*m_Mapping;

	
	// This struct (and the associated m_Mouse and m_Keyboard) are
	// cross-platform versions that contains the actual data that is
	// queriable by the user.

	// These are always the genric versions
	CControllerJoypad    **m_pController;
	CControllerKeyboard	m_Keyboard;
	CControllerMouse		m_Mouse;
};

#endif /* SGX_INPUT_MANAGER_HPP */
