#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "key.h"

static const struct {
  key_code_t code;
  const char *name;
} keys[] = {
  { KEY_CODE_ENTER       , KEY_NAME_ENTER        },
  { KEY_CODE_ESCAPE      , KEY_NAME_ESCAPE       },
  { KEY_CODE_BACKSPACE   , KEY_NAME_BACKSPACE    },
  { KEY_CODE_TAB         , KEY_NAME_TAB          },
  { KEY_CODE_SPACE       , KEY_NAME_SPACE        },
  { KEY_CODE_EXCLAIM     , KEY_NAME_EXCLAIM      },
  { KEY_CODE_QUOTEDBL    , KEY_NAME_QUOTEDBL     },
  { KEY_CODE_HASH        , KEY_NAME_HASH         },
  { KEY_CODE_PERCENT     , KEY_NAME_PERCENT      },
  { KEY_CODE_DOLLAR      , KEY_NAME_DOLLAR       },
  { KEY_CODE_AMPERSAND   , KEY_NAME_AMPERSAND    },
  { KEY_CODE_QUOTE       , KEY_NAME_QUOTE        },
  { KEY_CODE_LEFTPAREN   , KEY_NAME_LEFTPAREN    },
  { KEY_CODE_RIGHTPAREN  , KEY_NAME_RIGHTPAREN   },
  { KEY_CODE_ASTERISK    , KEY_NAME_ASTERISK     },
  { KEY_CODE_PLUS        , KEY_NAME_PLUS         },
  { KEY_CODE_COMMA       , KEY_NAME_COMMA        },
  { KEY_CODE_MINUS       , KEY_NAME_MINUS        },
  { KEY_CODE_PERIOD      , KEY_NAME_PERIOD       },
  { KEY_CODE_SLASH       , KEY_NAME_SLASH        },
  { KEY_CODE_0           , KEY_NAME_0            },
  { KEY_CODE_1           , KEY_NAME_1            },
  { KEY_CODE_2           , KEY_NAME_2            },
  { KEY_CODE_3           , KEY_NAME_3            },
  { KEY_CODE_4           , KEY_NAME_4            },
  { KEY_CODE_5           , KEY_NAME_5            },
  { KEY_CODE_6           , KEY_NAME_6            },
  { KEY_CODE_7           , KEY_NAME_7            },
  { KEY_CODE_8           , KEY_NAME_8            },
  { KEY_CODE_9           , KEY_NAME_9            },
  { KEY_CODE_COLON       , KEY_NAME_COLON        },
  { KEY_CODE_SEMICOLON   , KEY_NAME_SEMICOLON    },
  { KEY_CODE_LESS        , KEY_NAME_LESS         },
  { KEY_CODE_EQUALS      , KEY_NAME_EQUALS       },
  { KEY_CODE_GREATER     , KEY_NAME_GREATER      },
  { KEY_CODE_QUESTION    , KEY_NAME_QUESTION     },
  { KEY_CODE_AT          , KEY_NAME_AT           },
  { KEY_CODE_LEFTBRACKET , KEY_NAME_LEFTBRACKET  },
  { KEY_CODE_BACKSLASH   , KEY_NAME_BACKSLASH    },
  { KEY_CODE_RIGHTBRACKET, KEY_NAME_RIGHTBRACKET },
  { KEY_CODE_CARET       , KEY_NAME_CARET        },
  { KEY_CODE_UNDERSCORE  , KEY_NAME_UNDERSCORE   },
  { KEY_CODE_BACKQUOTE   , KEY_NAME_BACKQUOTE    },
  { KEY_CODE_A           , KEY_NAME_A            },
  { KEY_CODE_B           , KEY_NAME_B            },
  { KEY_CODE_C           , KEY_NAME_C            },
  { KEY_CODE_D           , KEY_NAME_D            },
  { KEY_CODE_E           , KEY_NAME_E            },
  { KEY_CODE_F           , KEY_NAME_F            },
  { KEY_CODE_G           , KEY_NAME_G            },
  { KEY_CODE_H           , KEY_NAME_H            },
  { KEY_CODE_I           , KEY_NAME_I            },
  { KEY_CODE_J           , KEY_NAME_J            },
  { KEY_CODE_K           , KEY_NAME_K            },
  { KEY_CODE_L           , KEY_NAME_L            },
  { KEY_CODE_M           , KEY_NAME_M            },
  { KEY_CODE_N           , KEY_NAME_N            },
  { KEY_CODE_O           , KEY_NAME_O            },
  { KEY_CODE_P           , KEY_NAME_P            },
  { KEY_CODE_Q           , KEY_NAME_Q            },
  { KEY_CODE_R           , KEY_NAME_R            },
  { KEY_CODE_S           , KEY_NAME_S            },
  { KEY_CODE_T           , KEY_NAME_T            },
  { KEY_CODE_U           , KEY_NAME_U            },
  { KEY_CODE_V           , KEY_NAME_V            },
  { KEY_CODE_W           , KEY_NAME_W            },
  { KEY_CODE_X           , KEY_NAME_X            },
  { KEY_CODE_Y           , KEY_NAME_Y            },
  { KEY_CODE_Z           , KEY_NAME_Z            },

  { KEY_CODE_CAPSLOCK    , KEY_NAME_CAPSLOCK     },
  { KEY_CODE_F1          , KEY_NAME_F1           },
  { KEY_CODE_F2          , KEY_NAME_F2           },
  { KEY_CODE_F3          , KEY_NAME_F3           },
  { KEY_CODE_F4          , KEY_NAME_F4           },
  { KEY_CODE_F5          , KEY_NAME_F5           },
  { KEY_CODE_F6          , KEY_NAME_F6           },
  { KEY_CODE_F7          , KEY_NAME_F7           },
  { KEY_CODE_F8          , KEY_NAME_F8           },
  { KEY_CODE_F9          , KEY_NAME_F9           },
  { KEY_CODE_F10         , KEY_NAME_F10          },
  { KEY_CODE_F11         , KEY_NAME_F11          },
  { KEY_CODE_F12         , KEY_NAME_F12          },

  { KEY_CODE_PRINTSCREEN , KEY_NAME_PRINTSCREEN  },
  { KEY_CODE_SCROLLLOCK  , KEY_NAME_SCROLLLOCK   },
  { KEY_CODE_PAUSE       , KEY_NAME_PAUSE        },
  { KEY_CODE_INSERT      , KEY_NAME_INSERT       },
  { KEY_CODE_HOME        , KEY_NAME_HOME         },
  { KEY_CODE_PAGEUP      , KEY_NAME_PAGEUP       },
  { KEY_CODE_DELETE      , KEY_NAME_DELETE       },
  { KEY_CODE_END         , KEY_NAME_END          },
  { KEY_CODE_PAGEDOWN    , KEY_NAME_PAGEDOWN     },
  { KEY_CODE_RIGHT       , KEY_NAME_RIGHT        },
  { KEY_CODE_LEFT        , KEY_NAME_LEFT         },
  { KEY_CODE_DOWN        , KEY_NAME_DOWN         },
  { KEY_CODE_UP          , KEY_NAME_UP           },

  { KEY_CODE_F13         , KEY_NAME_F13          },
  { KEY_CODE_F14         , KEY_NAME_F14          },
  { KEY_CODE_F15         , KEY_NAME_F15          },

  { KEY_CODE_LCTRL       , KEY_NAME_LCTRL        },
  { KEY_CODE_LSHIFT      , KEY_NAME_LSHIFT       },
  { KEY_CODE_LALT        , KEY_NAME_LALT         },
  { KEY_CODE_RCTRL       , KEY_NAME_RCTRL        },
  { KEY_CODE_RSHIFT      , KEY_NAME_RSHIFT       },
  { KEY_CODE_RALT        , KEY_NAME_RALT         },

  { KEY_CODE_NONE        , NULL                  },
};

const char *keyname_get(key_code_t code)
{
  static const char *names[KEY_CODE_NUM];
  static int made = 0;
  int i;

  if (!made) {
    for (i = 0; i < KEY_CODE_NUM; i++)
      names[i] = NULL;
    for (i = 0; keys[i].name; i++)
      names[keys[i].code] = keys[i].name;
    made = 1;
  }

  if (((code < 0) || (code >= KEY_CODE_NUM)) ||
      (code == KEY_CODE_NONE))
    return NULL;

  return names[code];
}

#ifndef KEY_HASH_SMALL
#define HASHNUM 256
#define CODENUM 2
#else
#define HASHNUM 7
#define CODENUM 17
#endif

static int hashindex(const char *name)
{
  int r0, r1 = 0xff, r2 = 0xaa;

  r0 = name[0];
  if (name[0]) {
    r1 = name[1];
    if (name[1]) {
      r2 = name[2];
    }
  }

  return (r0 ^ r1 ^ r2) % HASHNUM;
}

key_code_t keycode_get(const char *name)
{
  static struct {
    struct {
      key_code_t code;
      const char *name;
    } codes[CODENUM];
    int num;
  } hash[HASHNUM];
  static int made = 0;
  int i, n;

  if (!made) {
    for (i = 0; i < HASHNUM; i++)
      hash[i].num = 0;
    for (i = 0; keys[i].name; i++) {
      n = hashindex(keys[i].name);
      if (hash[n].num == CODENUM)
	return KEY_CODE_NONE;
      hash[n].codes[hash[n].num].code = keys[i].code;
      hash[n].codes[hash[n].num].name = keys[i].name;
      hash[n].num++;
    }
    made = 1;
  }

  n = hashindex(name);

  for (i = 0; i < hash[n].num; i++) {
    if (!strcmp(name, hash[n].codes[i].name))
      return hash[n].codes[i].code;
  }

  return KEY_CODE_NONE;
}
