#pragma once

#include <frostbite2D/event/event.h>
#include <SDL2/SDL_keyboard.h>
#include <string>

namespace frostbite2D {

enum class KeyCode {
  Unknown = SDLK_UNKNOWN,
  Return = SDLK_RETURN,
  Escape = SDLK_ESCAPE,
  Backspace = SDLK_BACKSPACE,
  Tab = SDLK_TAB,
  Space = SDLK_SPACE,
  Exclaim = SDLK_EXCLAIM,
  Quotedbl = SDLK_QUOTEDBL,
  Hash = SDLK_HASH,
  Percent = SDLK_PERCENT,
  Dollar = SDLK_DOLLAR,
  Ampersand = SDLK_AMPERSAND,
  Quote = SDLK_QUOTE,
  LeftParen = SDLK_LEFTPAREN,
  RightParen = SDLK_RIGHTPAREN,
  Asterisk = SDLK_ASTERISK,
  Plus = SDLK_PLUS,
  Comma = SDLK_COMMA,
  Minus = SDLK_MINUS,
  Period = SDLK_PERIOD,
  Slash = SDLK_SLASH,
  Num0 = SDLK_0,
  Num1 = SDLK_1,
  Num2 = SDLK_2,
  Num3 = SDLK_3,
  Num4 = SDLK_4,
  Num5 = SDLK_5,
  Num6 = SDLK_6,
  Num7 = SDLK_7,
  Num8 = SDLK_8,
  Num9 = SDLK_9,
  Colon = SDLK_COLON,
  Semicolon = SDLK_SEMICOLON,
  Less = SDLK_LESS,
  Equals = SDLK_EQUALS,
  Greater = SDLK_GREATER,
  Question = SDLK_QUESTION,
  At = SDLK_AT,
  LeftBracket = SDLK_LEFTBRACKET,
  Backslash = SDLK_BACKSLASH,
  RightBracket = SDLK_RIGHTBRACKET,
  Caret = SDLK_CARET,
  Underscore = SDLK_UNDERSCORE,
  Backquote = SDLK_BACKQUOTE,
  a = SDLK_a,
  b = SDLK_b,
  c = SDLK_c,
  d = SDLK_d,
  e = SDLK_e,
  f = SDLK_f,
  g = SDLK_g,
  h = SDLK_h,
  i = SDLK_i,
  j = SDLK_j,
  k = SDLK_k,
  l = SDLK_l,
  m = SDLK_m,
  n = SDLK_n,
  o = SDLK_o,
  p = SDLK_p,
  q = SDLK_q,
  r = SDLK_r,
  s = SDLK_s,
  t = SDLK_t,
  u = SDLK_u,
  v = SDLK_v,
  w = SDLK_w,
  x = SDLK_x,
  y = SDLK_y,
  z = SDLK_z,
  CapsLock = SDLK_CAPSLOCK,
  F1 = SDLK_F1,
  F2 = SDLK_F2,
  F3 = SDLK_F3,
  F4 = SDLK_F4,
  F5 = SDLK_F5,
  F6 = SDLK_F6,
  F7 = SDLK_F7,
  F8 = SDLK_F8,
  F9 = SDLK_F9,
  F10 = SDLK_F10,
  F11 = SDLK_F11,
  F12 = SDLK_F12,
  PrintScreen = SDLK_PRINTSCREEN,
  ScrollLock = SDLK_SCROLLLOCK,
  Pause = SDLK_PAUSE,
  Insert = SDLK_INSERT,
  Home = SDLK_HOME,
  PageUp = SDLK_PAGEUP,
  Delete = SDLK_DELETE,
  End = SDLK_END,
  PageDown = SDLK_PAGEDOWN,
  Right = SDLK_RIGHT,
  Left = SDLK_LEFT,
  Down = SDLK_DOWN,
  Up = SDLK_UP,
  Numpad0 = SDLK_KP_0,
  Numpad1 = SDLK_KP_1,
  Numpad2 = SDLK_KP_2,
  Numpad3 = SDLK_KP_3,
  Numpad4 = SDLK_KP_4,
  Numpad5 = SDLK_KP_5,
  Numpad6 = SDLK_KP_6,
  Numpad7 = SDLK_KP_7,
  Numpad8 = SDLK_KP_8,
  Numpad9 = SDLK_KP_9,
  NumpadDecimal = SDLK_KP_DECIMAL,
  NumpadDivide = SDLK_KP_DIVIDE,
  NumpadMultiply = SDLK_KP_MULTIPLY,
  NumpadMinus = SDLK_KP_MINUS,
  NumpadPlus = SDLK_KP_PLUS,
  NumpadEnter = SDLK_KP_ENTER,
  NumpadEquals = SDLK_KP_EQUALS,
  LShift = SDLK_LSHIFT,
  RShift = SDLK_RSHIFT,
  LCtrl = SDLK_LCTRL,
  RCtrl = SDLK_RCTRL,
  LAlt = SDLK_LALT,
  RAlt = SDLK_RALT,
  LGui = SDLK_LGUI,
  RGui = SDLK_RGUI
};

enum class KeyMod {
  None = KMOD_NONE,
  LShift = KMOD_LSHIFT,
  RShift = KMOD_RSHIFT,
  Shift = KMOD_SHIFT,
  LCtrl = KMOD_LCTRL,
  RCtrl = KMOD_RCTRL,
  Ctrl = KMOD_CTRL,
  LAlt = KMOD_LALT,
  RAlt = KMOD_RALT,
  Alt = KMOD_ALT,
  LGui = KMOD_LGUI,
  RGui = KMOD_RGUI,
  Gui = KMOD_GUI,
  Num = KMOD_NUM,
  Caps = KMOD_CAPS
};

class KeyEvent : public Event {
public:
  KeyEvent(uint32 timestamp, KeyCode keyCode, KeyMod modifiers, bool repeat)
    : Event(timestamp)
    , keyCode_(keyCode)
    , modifiers_(modifiers)
    , repeat_(repeat) {}
  
  EventType getType() const override {
    return EventType::KeyDown;
  }
  
  KeyCode getKeyCode() const { return keyCode_; }
  KeyMod getModifiers() const { return modifiers_; }
  bool isRepeat() const { return repeat_; }
  
private:
  KeyCode keyCode_;
  KeyMod modifiers_;
  bool repeat_;
};

class KeyUpEvent : public Event {
public:
  KeyUpEvent(uint32 timestamp, KeyCode keyCode, KeyMod modifiers)
    : Event(timestamp)
    , keyCode_(keyCode)
    , modifiers_(modifiers) {}
  
  EventType getType() const override {
    return EventType::KeyUp;
  }
  
  KeyCode getKeyCode() const { return keyCode_; }
  KeyMod getModifiers() const { return modifiers_; }
  
private:
  KeyCode keyCode_;
  KeyMod modifiers_;
};

class KeyTextEvent : public Event {
public:
  KeyTextEvent(uint32 timestamp, const std::string& text)
    : Event(timestamp)
    , text_(text) {}
  
  EventType getType() const override {
    return EventType::KeyText;
  }
  
  const std::string& getText() const { return text_; }
  
private:
  std::string text_;
};

}
