#ifndef __INPUT_SYSTEM_INCLUDED__
#define __INPUT_SYSTEM_INCLUDED__

#include <dinput.h>

#define IS_USEKEYBOARD  1
#define IS_USEMOUSE     2
#define IS_USEJOYSTICK  4

class CKeyboard
{
public:
  CKeyboard(LPDIRECTINPUT8 pDI, HWND hwnd);
  ~CKeyboard();

  bool  KeyDown(char key) { return (m_keys[key] & 0x80) ? true : false; }
  bool  KeyUp(char key) { return (m_keys[key] & 0x80) ? false : true; }

  bool  Update();

  void  Clear() { ZeroMemory(m_keys, 256 * sizeof(char)); }

  bool  Acquire();
  bool  Unacquire();

private:
  LPDIRECTINPUTDEVICE8  m_pDIDev;

  char    m_keys[256];
};


class CMouse
{
public:
  CMouse(LPDIRECTINPUT8 pDI, HWND hwnd, bool isExclusive = true);
  ~CMouse();

  bool  ButtonDown(int button) { return (m_state.rgbButtons[button] & 0x80) ? true : false; }
  bool  ButtonUp(int button) { return (m_state.rgbButtons[button] & 0x80) ? false : true; }
  void  GetMovement(int &dx, int &dy) { dx = m_state.lX; dy = m_state.lY; }

  // Stores the current position of the mouse pointer in (x, y);
  void GetPointerPos( float& x, float& y );

  bool  Update();

  bool  Acquire();
  bool  Unacquire();

  // Draws the mouse pointer onto the screen
  void draw();

  inline float getMaxX() { return MAX_X; };
  inline float getMaxY() { return MAX_Y; };
  inline float getMinX() { return MIN_X; };
  inline float getMinY() { return MIN_Y; };

private:
	// The current x and y positions of the mouse pointer.
	float currX_;
	float currY_;

	// The min and max values for currX and currY
	const float MAX_X;
	const float MIN_X;

	const float MAX_Y;
	const float MIN_Y;

	// The basic unit of mouse pointer movements.
	// The higher the number the more sensitive the mouse is
	float mouseSensitivity_;

  LPDIRECTINPUTDEVICE8  m_pDIDev;
  DIMOUSESTATE          m_state;
};


class CJoystick
{
public:
  CJoystick(LPDIRECTINPUT8 pDI, HINSTANCE appInstance);
  ~CJoystick();

  bool  Update();

  bool  Acquire();
  bool  Unacquire();

private:
  LPDIRECTINPUTDEVICE8  m_pDIDev;
};


class CInputSystem
{
public:
	CInputSystem() { }
	~CInputSystem() { Shutdown(); }
  bool  Initialize(HWND hwnd, HINSTANCE appInstance, bool isExclusive, DWORD flags = 0);
  bool  Shutdown();

  void  AcquireAll();
  void  UnacquireAll();

  CKeyboard  *GetKeyboard() { return m_pKeyboard; }
  CMouse     *GetMouse()    { return m_pMouse; }
  CJoystick  *GetJoystick() { return m_pJoystick; }

  bool  Update();

  bool  KeyDown(char key) { return (m_pKeyboard && m_pKeyboard->KeyDown(key)); }
  bool  KeyUp(char key) { return (m_pKeyboard && m_pKeyboard->KeyUp(key)); }

  bool  ButtonDown(int button) { return (m_pMouse && m_pMouse->ButtonDown(button)); }
  bool  ButtonUp(int button) { return (m_pMouse && m_pMouse->ButtonUp(button)); }
  void  GetMouseMovement(int &dx, int &dy) { if (m_pMouse) m_pMouse->GetMovement(dx, dy); }

private:
  CKeyboard  *m_pKeyboard;
  CMouse     *m_pMouse;
  CJoystick  *m_pJoystick;
  
  LPDIRECTINPUT8 m_pDI;
};


#endif //__INPUT_SYSTEM_INCLUDED__