/*==========================================================
  File:  input.c
  Author:  _pragma

  Description:  Handles pheripheral input (keyboard, mouse)
  ==========================================================*/

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <stdlib.h>
#include <string.h>

#include "cvar.h"
#include "a3dmath.h"
#include "bsp.h"
#include "ms3d.h"
#include "model.h"
#include "entity.h"
#include "input.h"
#include "camera.h"
#include "util.h"
#include "texture.h"
#include "console.h"
#include "kbnames.h"
#include "interp.h"
#include "commands.h"
#include "game.h"
#include "gui_elements.h"

#define MAX_KEYSTATES  (SDLK_RSUPER+1)  // see kbnames.c

kb_state_t kb_state[MAX_KEYSTATES];

extern console_t gc_console;

void I_initKeyStates(void)
{
  memset(kb_state0sizeof kb_state);

  /* hard coded bindings */
  
  I_bindKey("escape""gamemenu");
  I_bindKey("~""console");

  I_bindKey("w""+forward");
  I_bindKey("s""+back");
  I_bindKey("a""+moveleft");
  I_bindKey("d""+moveright");

  I_bindKey("space""+moveup");
  I_bindKey("enter""+movedown");
  I_bindKey("pageup""+moveup");
  I_bindKey("pagedown""+movedown");

  I_bindKey("f1""help");
}

void I_destroyKeyStates(void)
{
  int i;

  for(i = 0i < MAX_KEYSTATESi++)
    if(kb_state[i].command)
      free(kb_state[i].command);
}

void I_keyPressed(SDL_keysym *keysym)
{
  if(keysym->sym >= MAX_KEYSTATES)
    return;
 
  kb_state[keysym->sym].state = KEY_PRESSED;

  if(CON_processKeystroke(keysym))
    return;

  if(kb_state[keysym->sym].command)
    CON_addCommand(kb_state[keysym->sym].command);
}

void I_keyReleased(SDL_keysym *keysym)
{
  char command[CON_BCS];

  if(keysym->sym >= MAX_KEYSTATES)
    return;

  kb_state[keysym->sym].state = KEY_RELEASED;

  if(kb_state[keysym->sym].command && *kb_state[keysym->sym].command == '+')
  {
    sprintf(command"-%s"kb_state[keysym->sym].command + 1);
    CON_addCommand(command);    
  }
}

void I_mouseButtonClicked(SDL_MouseButtonEvent *button)
{
  extern int game_state;
  extern gui_element_t *gui_element_list;

  if(game_state == GAME_STATE_GUI)
    gui_processMouseClick(button->xbutton->ybutton->stategui_element_list);
}

void I_mouseButtonReleased(SDL_MouseButtonEvent *button)
{
}

void I_mouseMotion(SDL_MouseMotionEvent *motion)
{
  extern int game_state;
  extern ent_t *ge_player;

  if(game_state == GAME_STATE_PLAYING)
    I_mouseLook(ge_playermotion->xmotion->y); 
}

void I_mouseLook(ent_t *entityint mouseXint mouseY)
{
  extern cvar_t *cvar_scr_width, *cvar_scr_height;
  int middleX = atoi(cvar_scr_width->value) >> 1middleY = atoi(cvar_scr_height->value) >> 1;
  float angleY = 0.0angleZ = 0.0r[3], a[3];
  extern cvar_t *cvar_mpitchSpeed, *cvar_myawSpeed, *cvar_msensitivity,
                *cvar_thirdperson;
  int thirdperson = atoi(cvar_thirdperson->value) ? -1 : 1;

  SDL_GetMouseState(&mouseX, &mouseY);

  if( (mouseX == middleX) && (mouseY == middleY)) return;

  SDL_WarpMouse(middleXmiddleY);

  angleY = (float)(middleX - mouseX) / 1000.0;
  angleZ = (float)(middleY - mouseY) / 1000.0 * thirdperson;

  angleY = atof(cvar_myawSpeed->value) * angleY * atof(cvar_msensitivity->value);
  angleZ = atof(cvar_mpitchSpeed->value) * angleZ * atof(cvar_msensitivity->value);

  M_vsubtract(rentity->viewentity->position);
  M_vcross(arentity->up);
  M_vnormalize(a);

  E_rotateEntity(entityangleZa[0], a[1], a[2]);
  E_rotateEntity(entityangleY010);
}

int I_findKey(char *key)
{
  int i;
  extern const kb_names_t keyNames[];
 
  for(i = 0; *keyNames[i].name != '\n'i++)
    if(!stricmp(keykeyNames[i].name))
      break;

  return keyNames[i].id;
}

int I_findKeyName(char *key)
{
  int i;
  extern const kb_names_t keyNames[];
 
  for(i = 0; *keyNames[i].name != '\n'i++)
    if(!stricmp(keykeyNames[i].name))
      break;

  return i;
}

char *I_findKeyNameByID(int id)
{
  int i;
  extern const kb_names_t keyNames[];
 
  for(i = 0; *keyNames[i].name != '\n'i++)
    if(id == keyNames[i].id)
      return keyNames[i].name;

  return 0;
}

void I_bindKey(char *keychar *command)
{
  int i;
  extern const kb_names_t keyNames[];

  for(i = 0keyNames[i].id != -1i++)
    if(!stricmp(keykeyNames[i].name))
    {
      if(kb_state[keyNames[i].id].command)
        free(kb_state[keyNames[i].id].command);
      kb_state[keyNames[i].id].command = strdup(command);
      return;
    }
}

COMMAND(CMD_keynames)
{
  int i;
  extern const kb_names_t keyNames[];

  for(i = 1keyNames[i].id != -1i++)
    CON_printf("  %s"keyNames[i].name);
  CON_printf("%d keys registered"i);
}

COMMAND(CMD_bind)
{
  extern const kb_names_t keyNames[];
  char key[CON_BCS], command[CON_BCS];
  int idname;

  I_halfChop(argumentskeycommand);

  if(!*key)
  {
    CON_printf("Usage:  bind <key> <command>");
    CON_printf("        (bind escape gamemenu)");
    return;
  }

  if(!*command)
  {
    if((id = I_findKey(key)) == -1)
    {
      CON_printf("\'%s\' is not a valid key.  To list keys, type: keynames"key);
      return;
    }

    name = I_findKeyName(key);

    if(!kb_state[id].command)
    {
      CON_printf("^3'^14;%s^3'^15 is not bound."key);
      return;
    }

    CON_printf("^3'^14;%s^3' ^15is bound to ^3'^14;%s^3'"keyNames[name].namekb_state[id].command);
    return;
  }
 
  I_bindKey(keycommand);
}

COMMAND(CMD_unbind)
{
  int id;

  if(!*arguments)
  {
    CON_printf("Usage:  unbind <key>");
    return;
  }

  if((id = I_findKey(arguments)) == -1)
  {
    CON_printf("^3'^14;%s^3' ^15is not a valid key.  To list keys, type: ^6keynames"arguments);
    return;
  }
  
  if(!kb_state[id].command)
    return;

  free(kb_state[id].command);
  kb_state[id].command = 0;
}

COMMAND(CMD_bindlist)
{
  int ij;

  for(i = 0j = 0i < MAX_KEYSTATESi++)
    if(kb_state[i].command)
    {
      CON_printf("^3'^14\%s^3' ^15== ^3'^14;%s^3'"I_findKeyNameByID(i), kb_state[i].command); 
      j++;
    }
  CON_printf("%d keys bound"j);
}