#include "kb.h"

#ifndef _WIN32
#include <usb/usbkb/libusbkb_c.h>
#include <types.h>
#include <stdio.h>
#include <sys/timer.h>

#else

#include <windows.h>
#include <stdio.h>

#endif

#define DEBUG_OUTPUT_KEYCODES

KB::KB()
{
  initialized = false;
}

KB::~KB()
{
}

void KB::Init()
{
#ifndef _WIN32
  m_numKB = 1;

  int ret = 0;
  if ( (ret = sceUsbKbInit( MAX_KEYBD )) != SCE_USBKB_OK)
  {
    printf( "Error(%d) : Keyboard initialize error\n", ret );
    return;
  }
  
  int i;
  for (i=0; i<m_numKB; ++i)
  {
    m_oldStatus[i] = 0;
    if ( (ret = sceUsbKbSetRepeat(i, 0, 0)) != SCE_USBKB_OK)
    {
      printf( "Error(%d) : Keyboard - cannot set key repeat, kno = %d\n", ret, i );
      sceUsbKbEnd();
      return;
    } 
  
	  Arrangement[i] = SCE_USBKB_ARRANGEMENT_101;
  	if ((ret = sceUsbKbSetArrangement(i, SCE_USBKB_ARRANGEMENT_101)) != SCE_USBKB_OK)
    {
	      printf("Error(%d) : cannot set key arrangement, kno = %d\n", ret, i);
	      sceUsbKbEnd();
	      return;
    }

	  if ((ret = sceUsbKbSetReadMode(i, SCE_USBKB_RMODE_PACKET)) != SCE_USBKB_OK)
    {
	      printf("Error(%d) : cannot set read mode, kno = %d\n", ret, i);
	      sceUsbKbEnd();
  	    return;
	  }

    if ((ret = sceUsbKbSetCodeType(i ,SCE_USBKB_CODETYPE_RAW)) != SCE_USBKB_OK)
    {
	      printf("Error(%d) : cannot set code type, kno = %d\n", ret, i);
	      sceUsbKbEnd();
	      return;
  	}
  }

  initialized = true;
#else

  // For window mode this is always safe
  initialized = true;

#endif  // _WIN32

  if (initialized)
  {
    printf( "Keyboard initialized successfully\n" );
  }

  #ifndef _WIN32
  for (i=0; i<KB_MAX_KEYS; ++i)
  {
    m_keyStatus[i] = 0;
  }
  #endif
}

void KB::Shutdown()
{
#ifndef _WIN32
  sceUsbKbEnd();
#endif  // _WIN32
}

void KB::Update()
{
  if (!initialized)
  {
#ifdef DEBUG_OUTPUT_KEYCODES
    printf( "KB::Update - not initialized\n" ); 
#endif
    return;
  }
  
#ifndef _WIN32
  uint8_t ret;

  if ( (ret = sceUsbKbGetInfo(&info)) != SCE_USBKB_OK)
  {
#ifdef DEBUG_OUTPUT_KEYCODES
    printf( "KB::Update - sceUsbKbGetInfo failed\n" );
#endif
    initialized = false;
    return;
  }

  for (int i=0; i<m_numKB; ++i)
  {
    if (info.status[i] == 0)
    {
      continue;
    }
  
    /* keyboard i has been connected */
    if (m_oldStatus[i]==0)
    {
      /* the keyboard was not connected on the last update */
      ret = sceUsbKbSetLEDMode( i, SCE_USBKB_LED_MODE_AUTO1, NULL);
      if (ret != SCE_USBKB_OK)
      {
        continue;
      }
    }
       
    /* read keyboard data using PACKET mode */
    ret = sceUsbKbRead( i, &kdataPacket );
    if (ret != SCE_USBKB_OK)
    {
      continue;
    }

		int metaKeyState = 0;

    // update key status
    // ...because we know there is a packet update, just clear all of it
    if (kdataPacket.len > 0)
    {
      for (i=0; i<KB_MAX_KEYS; ++i)
      {
        m_keyStatus[i] = 0x0;
      }

			const int lshift 	= ((kdataPacket.mkey & SCE_USBKB_MKEY_L_SHIFT) != 0) ? KB_FLAG_L_SHIFT : 0;
			const int rshift 	= ((kdataPacket.mkey & SCE_USBKB_MKEY_R_SHIFT) != 0) ? KB_FLAG_R_SHIFT : 0;
			const int lalt 		= ((kdataPacket.mkey & SCE_USBKB_MKEY_L_ALT) != 0) ? KB_FLAG_L_ALT : 0;
			const int ralt 		= ((kdataPacket.mkey & SCE_USBKB_MKEY_R_ALT) != 0) ? KB_FLAG_R_ALT : 0;
			const int lctrl 	= ((kdataPacket.mkey & SCE_USBKB_MKEY_L_CTRL) != 0) ? KB_FLAG_L_CTRL : 0;
			const int rctrl 	= ((kdataPacket.mkey & SCE_USBKB_MKEY_R_CTRL) != 0) ? KB_FLAG_R_CTRL : 0;

			metaKeyState = lshift|rshift|lalt|ralt|lctrl|rctrl;
    }
    // ...otherwise, just clear the keyhit flags and preserve the keydown flags
    else
    {
      for (i=0; i<KB_MAX_KEYS; ++i)
      {
        m_keyStatus[i] &= ~KB_FLAG_KEYHIT;
      }
    }

    for (i=0; i<kdataPacket.len; ++i)
    {
      int val = (kdataPacket.keycode[i]&~SCE_USBKB_RAWDAT);
    
			m_keyStatus[val] = KB_FLAG_KEYHIT|KB_FLAG_KEYDOWN|metaKeyState;
    }
    
    /* save the old status */
    m_oldStatus[i] = info.status[i];
  }
#endif  // _WIN32
}

bool KB::IsKeyHit( uint8 code )
{
  if (!initialized)
  {
#ifdef DEBUG_OUTPUT_KEYCODES
    printf( "KB::IsKeyHit - not intialized\n" );
#endif
    return false;
  }
  
  bool result = false;

#ifdef _WIN32
  
  if (GetAsyncKeyState(code) & 0x8000)
  {
    result = true;
  }
  
#else

  if (m_keyStatus[code] & KB_FLAG_KEYHIT)
  {
    result = true;
  }
  
#endif

  return result;
}

bool KB::IsKeyDown( uint8 code )
{
  if (!initialized)
  {
#ifdef DEBUG_OUTPUT_KEYCODES
    printf( "KB::IsKeyDown - not intialized\n" );
#endif
    return false;
  }
  
  bool result = false;

#ifdef _WIN32
  
  if (GetAsyncKeyState(code) & 0x8000)
  {
    result = true;
  }
  
#else

  if (m_keyStatus[code] & KB_FLAG_KEYDOWN)
  {
    result = true;
  }
#endif

  return result;
}



int KB::GetKeyState( uint8 code )
{
  if (!initialized)
  {
#ifdef DEBUG_OUTPUT_KEYCODES
    printf( "KB::IsKeyDown - not intialized\n" );
#endif
    return 0;
  }
  
  int result = 0;

#ifdef _WIN32
  
  SHORT keyState = GetAsyncKeyState(code);

	result |= ((GetAsyncKeyState( VK_LSHIFT ) & 0x8000) != 0) ? KB_FLAG_L_SHIFT : 0;
	result |= ((GetAsyncKeyState( VK_RSHIFT ) & 0x8000) != 0) ? KB_FLAG_R_SHIFT : 0;
	result |= ((GetAsyncKeyState( VK_LCONTROL ) & 0x8000) != 0) ? KB_FLAG_L_CTRL : 0;
	result |= ((GetAsyncKeyState( VK_RMENU ) & 0x8000) != 0) ? KB_FLAG_R_ALT : 0;
	result |= ((GetAsyncKeyState( VK_LMENU ) & 0x8000) != 0) ? KB_FLAG_L_ALT : 0;
	result |= ((GetAsyncKeyState( VK_RCONTROL ) & 0x8000) != 0) ? KB_FLAG_R_CTRL : 0;
	result |= ((GetAsyncKeyState( code ) & 0x8000) != 0) ? KB_FLAG_KEYDOWN : 0;  
  
#else

  result = m_keyStatus[code];

#endif

  return result;
}


