#include "keyboard.hpp"

#include "common.hpp"

#ifdef use_sdl
#include "renderer.hpp"
#include "sdlout.hpp"
#endif

#include <iostream>

using std::string;


static const char* convert_table[] = {
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"TAB","" ,"" ,"" ,"ENTER","" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 "SPACE","" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 "0"    ,"1","2","3","4","5","6","7","8","9"  ,":",";","<","="    ,">","?",
 "@"    ,"A","B","C","D","E","F","G","H","I"  ,"J","K","L","M"    ,"N","O",
 "P"    ,"Q","R","S","T","U","V","W","X","Y"  ,"Z","[","" ,"]"    ,"^","_",
 ""     ,"a","b","c","d","e","f","g","h","i"  ,"j","k","l","m"    ,"n","o",
 "p"    ,"q","r","s","t","u","v","w","x","y"  ,"z","{","" ,"}"    ,"~","" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,
 ""     ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""   ,"" ,"" ,"" ,""     ,"" ,"" ,

 "BACKSPACE","DEL" ,"INS" ,"HOME","END","PGUP","PGDOWN","ESC",""  ,""  ,""   ,""   ,""   ,""   ,""   ,"",
 "RIGHT"    ,"LEFT","DOWN","UP"  ,""   ,""    ,""      ,""   ,""  ,""  ,""   ,""   ,""   ,""   ,""   ,"",
 ""         ,""    ,""    ,""    ,""   ,""    ,""      ,""   ,""  ,""  ,""   ,""   ,""   ,""   ,""   ,"",
 ""         ,""    ,""    ,""    ,""   ,""    ,""      ,""   ,""  ,""  ,""   ,""   ,""   ,""   ,""   ,"",
 ""         ,"F1"  ,"F2"  ,"F3"  ,"F4" ,"F5"  ,"F6"    ,"F7" ,"F8","F9","F10","F11","F12","F13","F14","F15"};

Keyboard::Keyboard()
  : halfdelay_time(100), tty_mode(0)
{
#ifdef use_sdl
  SDL_EnableKeyRepeat( 500, 30 );
#endif
  cbreak();
}

string convert_int_to_string(int i)
{
  if (i >= 0 && i < 337) {
    string value = convert_table[i];
    return value;
  } else {
    char kbuf[10] = {0};
    snprintf(kbuf, sizeof(kbuf), "#%d", i);
    string keycode = string_format::convert(kbuf);
    return keycode;
 }
  return "";
}

#ifdef use_sdl
string Keyboard::getSDLkey()
{
  SDLdev *dev = reinterpret_cast<SDLdev*>(Render::get_instance()->device);

  if (dev) {
    dev->get_input();
    dev->get_input_event.wait();
    return dev->input_key;
  } else {
    std::cerr << "FIXME: this should not happen" << std::endl;
    return "";
  }
}
#endif

void Keyboard::run()
{
  Input_master *input_master = Input_master::get_instance();

  while (true) {
    
    input_done_.signal();
    input_ready.wait();
    input_ready.reset();

  nogood:    

    string input_from_device;
#ifdef use_sdl
    if(SDL_WasInit(SDL_INIT_VIDEO)) {
      input_from_device = getSDLkey();
    } else {
#endif
      input_from_device = convert_int_to_string(getch2(halfdelay_time));
#ifdef use_sdl
    } // SDL_WasInit(...)
#endif  

    if (accept_all) {

      Input i;

      input_map::iterator im = input_master->cur_map->find(input_from_device);
      if (im != input_master->cur_map->end())
	i = im->second;
      else
	i.key = input_from_device;

      input = i;

    } else {
      
      input_map::iterator im = input_master->cur_map->find(input_from_device);
      if (im != input_master->cur_map->end())
	input = im->second;
      else
	goto nogood;
    }
  }
}

// one-char-at-a-time
void Keyboard::cbreak()
{
#ifdef use_sdl
  if(!SDL_WasInit(SDL_INIT_VIDEO)) {
#endif

  if (tty_mode == 0)
    {
      tcgetattr(0, &orig_tty);
      tty_mode = 1;
      new_tty = orig_tty;
    }

  new_tty.c_lflag &= ~(ICANON | ECHO);
  new_tty.c_cc[VMIN] = 1;
  new_tty.c_cc[VTIME] = 0;
  tcsetattr(0, TCSANOW, &new_tty);

#ifdef use_sdl
  } else /* SDL_WasInit(...) */
    SDL_EnableUNICODE(1);
#endif
}

// normal keyboard mode
void Keyboard::normal()
{
#ifdef use_sdl
  if(!SDL_WasInit(SDL_INIT_VIDEO)) {
#endif

  if (tty_mode == 1)
    {
      tcsetattr(0, TCSANOW, &orig_tty);
      new_tty = orig_tty;
    }

#ifdef use_sdl
  } else /* SDL_WasInit(...) */
    SDL_EnableUNICODE(0);
#endif
}
