#include "InputSystem.h"

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>

CKeyboard::CKeyboard(LPDIRECTINPUT8 pDI, HWND hwnd)
{
  if (FAILED(pDI->CreateDevice(GUID_SysKeyboard, &m_pDIDev, NULL)))
  {
    // error processing
  }

  if (FAILED(m_pDIDev->SetDataFormat(&c_dfDIKeyboard)))
  {
    // error processing
  }

  if (FAILED(m_pDIDev->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))
  {
    // error processing
  }

  if (FAILED(m_pDIDev->Acquire()))
  {
    // error processing
  }

  Clear();
}


CKeyboard::~CKeyboard()
{
  if (m_pDIDev)
  {
    m_pDIDev->Unacquire();
    m_pDIDev->Release();
  }
}


bool CKeyboard::Acquire()
{
  Clear();
  return (!FAILED(m_pDIDev->Acquire()));
}


bool CKeyboard::Unacquire()
{
  Clear();
  return (!FAILED(m_pDIDev->Unacquire()));
}


bool CKeyboard::Update()
{
  if (FAILED(m_pDIDev->GetDeviceState(sizeof(m_keys), (LPVOID)m_keys)))
  {
    if (FAILED(m_pDIDev->Acquire()))
    {
      return false;
    }
    if (FAILED(m_pDIDev->GetDeviceState(sizeof(m_keys), (LPVOID)m_keys)))
    {
      return false;
    }
  }
  return true;
}


CMouse::CMouse(LPDIRECTINPUT8 pDI, HWND hwnd, bool isExclusive) : 
			   currX_(5), currY_(5), mouseSensitivity_(25), MAX_X(22), MAX_Y(17),
			   MIN_X(0), MIN_Y(0)
{
  if (FAILED(pDI->CreateDevice(GUID_SysMouse, &m_pDIDev, NULL)))
  {
    // error processing
  }

  if (FAILED(m_pDIDev->SetDataFormat(&c_dfDIMouse)))
  {
    // error processing
  }

  DWORD flags;

  if (isExclusive)
    flags = DISCL_FOREGROUND | DISCL_EXCLUSIVE | DISCL_NOWINKEY;
  else
    flags = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;


  if (FAILED(m_pDIDev->SetCooperativeLevel(hwnd, flags)))
  {
    // error processing
  }

  if (FAILED(m_pDIDev->Acquire()))
  {
    // error processing
  }

  if (FAILED(m_pDIDev->GetDeviceState(sizeof(DIMOUSESTATE), &m_state)))
  {
    // error processing
  }
}


bool CMouse::Update()
{
  if (FAILED(m_pDIDev->GetDeviceState(sizeof(DIMOUSESTATE), &m_state)))
  {
    if (FAILED(m_pDIDev->Acquire()))
    {
      return false;
    }
    if (FAILED(m_pDIDev->GetDeviceState(sizeof(DIMOUSESTATE), &m_state)))
    {
      return false;
    }
  }

  // Update the current mouse pointer position.
  int x, y;
  GetMovement(x, y);
  currX_ += x / mouseSensitivity_;
  currY_ -= y / mouseSensitivity_;

  if(currX_ > MAX_X)
	  currX_ = MAX_X;
  
  if(currX_ < MIN_X)
	  currX_ = MIN_X;

  if(currY_ > MAX_Y)
	  currY_ = MAX_Y;

  if(currY_ < MIN_Y)
	  currY_ = MIN_Y;

  return true;
}

void CMouse::draw()
{
	glPushMatrix();
	glTranslatef(currX_, currY_, 0);

	glLineWidth(5);
	glBegin(GL_LINES);
		glVertex3f( 0,   0, 0);
		glVertex3f(.5, -.5, 0);
	glEnd();

	glPopMatrix();
}

// Sets (x, y) to (currX_, currY_)
void CMouse::GetPointerPos( float& x, float& y )
{
	x = currX_;
	y = currY_;
}// End CMouse::GetPointerPos

CMouse::~CMouse()
{
  if (m_pDIDev)
  {
    m_pDIDev->Unacquire();
    m_pDIDev->Release();
  }
}


bool CMouse::Acquire()
{
  return (!FAILED(m_pDIDev->Acquire()));
}


bool CMouse::Unacquire()
{
  return (!FAILED(m_pDIDev->Unacquire()));
}


CJoystick::CJoystick(LPDIRECTINPUT8 pDI, HINSTANCE appInstance)
{
}

CJoystick::~CJoystick()
{
  if (m_pDIDev)
  {
    m_pDIDev->Unacquire();
    m_pDIDev->Release();
  }
}


bool CInputSystem::Initialize(HWND hwnd, HINSTANCE appInstance, bool isExclusive, DWORD flags)
{
  m_pKeyboard = NULL; 
  m_pMouse = NULL; 
  m_pJoystick = NULL; 

  if (FAILED(DirectInput8Create(appInstance,
                               DIRECTINPUT_VERSION,
                               IID_IDirectInput8,
                               (void **)&m_pDI,
                               NULL)))
    return false;

  if (flags & IS_USEKEYBOARD)
  {
    m_pKeyboard = new CKeyboard(m_pDI, hwnd);
  }
  if (flags & IS_USEMOUSE)
  {
    m_pMouse = new CMouse(m_pDI, hwnd, true);
  }
  if (flags & IS_USEJOYSTICK)
  {
    m_pJoystick = new CJoystick(m_pDI, appInstance);
  }
  return true;
}


bool CInputSystem::Shutdown()
{
  UnacquireAll();
  if (m_pKeyboard)
  {
    delete m_pKeyboard;
    m_pKeyboard = NULL;
  }

  if (m_pKeyboard)
  {
    delete m_pMouse;
    m_pMouse = NULL;
  }

  if (m_pJoystick)
  {
    delete m_pJoystick;
    m_pJoystick = NULL;
  }

  if (FAILED(m_pDI->Release()))
    return false;

  return true;
}

bool CInputSystem::Update()
{
  if (m_pKeyboard)
    m_pKeyboard->Update();
  if (m_pMouse)
    m_pMouse->Update();
  if (m_pJoystick)
    m_pJoystick->Update();

  return true;
}


void CInputSystem::AcquireAll()
{
  if (m_pKeyboard)
    m_pKeyboard->Acquire();
  if (m_pMouse)
    m_pMouse->Acquire();
  if (m_pJoystick)
    m_pJoystick->Acquire();
}


void CInputSystem::UnacquireAll()
{
  if (m_pKeyboard)
    m_pKeyboard->Unacquire();
  if (m_pMouse)
    m_pMouse->Unacquire();
  if (m_pJoystick)
    m_pJoystick->Unacquire();
}


bool CJoystick::Acquire()
{
  return (!FAILED(m_pDIDev->Acquire()));
}


bool CJoystick::Unacquire()
{
  return (!FAILED(m_pDIDev->Unacquire()));
}


bool CJoystick::Update()
{
  return true;
}