/*
 * GDevelop C++ Platform
 * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
 * reserved. This project is released under the MIT License.
 */
#include "InputManager.h"

InputManager::InputManager(sf::Window* win)
    : window(win),
      lastPressedKey(0),
      keyWasPressed(false),
      touchSimulateMouse(true),
      mouseWheelDelta(0),
      windowHasFocus(true),
      disableInputWhenNotFocused(true) {}

void InputManager::SimulateMousePressed(sf::Vector2i pos) {
  mousePosition = pos;
  buttonsPressed["Left"] = true;
}

void InputManager::NextFrame() {
  keyWasPressed = false;
  charactersEntered.clear();

  oldKeysPressed = keysPressed;
  keysPressed.clear();
  const auto& keyMap = GetKeyNameToSfKeyMap();
  for (auto it = keyMap.begin(); it != keyMap.end(); ++it) {
    keysPressed[it->first] =
        sf::Keyboard::isKeyPressed(static_cast<sf::Keyboard::Key>(it->second));
  }

  mouseWheelDelta = 0;
  oldButtonsPressed = buttonsPressed;
  buttonsPressed.clear();
  const auto& buttonMap = GetButtonNameToSfButtonMap();
  for (auto it = buttonMap.begin(); it != buttonMap.end(); ++it) {
    buttonsPressed[it->first] =
        sf::Mouse::isButtonPressed(static_cast<sf::Mouse::Button>(it->second));
  }

  if (window) mousePosition = sf::Mouse::getPosition(*window);
  if (touchSimulateMouse && !touches.empty())
    SimulateMousePressed(touches.begin()->second);
}

void InputManager::HandleEvent(sf::Event& event) {
  if (event.type == sf::Event::KeyPressed) {
    if (!windowHasFocus && disableInputWhenNotFocused) return;

    lastPressedKey = event.key.code;
    keyWasPressed = true;
  } else if (event.type == sf::Event::TextEntered) {
    if (!windowHasFocus && disableInputWhenNotFocused) return;

    charactersEntered.push_back(event.text.unicode);
  } else if (event.type == sf::Event::MouseWheelMoved)
    mouseWheelDelta = event.mouseWheel.delta;
  else if (event.type == sf::Event::TouchBegan ||
           event.type == sf::Event::TouchMoved) {
    touches[event.touch.finger] = sf::Vector2i(event.touch.x, event.touch.y);
    if (touchSimulateMouse) SimulateMousePressed(touches[event.touch.finger]);
  } else if (event.type == sf::Event::TouchEnded) {
    touches.erase(event.touch.finger);
  } else if (event.type == sf::Event::GainedFocus)
    windowHasFocus = true;
  else if (event.type == sf::Event::LostFocus)
    windowHasFocus = false;
}

bool InputManager::IsKeyPressed(gd::String key) const {
  if (!windowHasFocus && disableInputWhenNotFocused) return false;

  return keysPressed.find(key) != keysPressed.end() &&
         keysPressed.find(key)->second;
}

bool InputManager::WasKeyReleased(gd::String key) const {
  return oldKeysPressed.find(key) != oldKeysPressed.end() &&
         oldKeysPressed.find(key)->second && !IsKeyPressed(key);
}

gd::String InputManager::GetLastPressedKey() const {
  const auto& keyMap = GetSfKeyToKeyNameMap();
  auto it = keyMap.find(lastPressedKey);
  if (it != keyMap.end()) return it->second;

  return "";
}

bool InputManager::AnyKeyIsPressed() const {
  if (!windowHasFocus && disableInputWhenNotFocused) return false;

  return keyWasPressed;
}

sf::Vector2i InputManager::GetMousePosition() const { return mousePosition; }

bool InputManager::IsMouseButtonPressed(const gd::String& button) const {
  if (!windowHasFocus && disableInputWhenNotFocused) return false;

  return buttonsPressed.find(button) != buttonsPressed.end() &&
         buttonsPressed.find(button)->second;
}

bool InputManager::IsMouseButtonReleased(const gd::String& button) const {
  return oldButtonsPressed.find(button) != oldButtonsPressed.end() &&
         oldButtonsPressed.find(button)->second &&
         !IsMouseButtonPressed(button);
}

int InputManager::GetMouseWheelDelta() const {
  if (!windowHasFocus && disableInputWhenNotFocused) return 0;

  return mouseWheelDelta;
}

bool InputManager::IsScrollingUp() const {
  if (!windowHasFocus && disableInputWhenNotFocused) return false;
  
  return mouseWheelDelta > 0;
}

bool InputManager::IsScrollingDown() const {
  if (!windowHasFocus && disableInputWhenNotFocused) return false;
 
  return mouseWheelDelta < 0;
}

const std::map<gd::String, int>& InputManager::GetKeyNameToSfKeyMap() {
  static bool initialized = false;
  static std::map<gd::String, int>* map = new std::map<gd::String, int>();
  if (!initialized) {
    (*map)["a"] = sf::Keyboard::A;
    (*map)["b"] = sf::Keyboard::B;
    (*map)["c"] = sf::Keyboard::C;
    (*map)["d"] = sf::Keyboard::D;
    (*map)["e"] = sf::Keyboard::E;
    (*map)["f"] = sf::Keyboard::F;
    (*map)["g"] = sf::Keyboard::G;
    (*map)["h"] = sf::Keyboard::H;
    (*map)["i"] = sf::Keyboard::I;
    (*map)["j"] = sf::Keyboard::J;
    (*map)["k"] = sf::Keyboard::K;
    (*map)["l"] = sf::Keyboard::L;
    (*map)["m"] = sf::Keyboard::M;
    (*map)["n"] = sf::Keyboard::N;
    (*map)["o"] = sf::Keyboard::O;
    (*map)["p"] = sf::Keyboard::P;
    (*map)["q"] = sf::Keyboard::Q;
    (*map)["r"] = sf::Keyboard::R;
    (*map)["s"] = sf::Keyboard::S;
    (*map)["t"] = sf::Keyboard::T;
    (*map)["u"] = sf::Keyboard::U;
    (*map)["v"] = sf::Keyboard::V;
    (*map)["w"] = sf::Keyboard::W;
    (*map)["x"] = sf::Keyboard::X;
    (*map)["y"] = sf::Keyboard::Y;
    (*map)["z"] = sf::Keyboard::Z;

    (*map)["Num9"] = sf::Keyboard::Num9;
    (*map)["Num8"] = sf::Keyboard::Num8;
    (*map)["Num7"] = sf::Keyboard::Num7;
    (*map)["Num6"] = sf::Keyboard::Num6;
    (*map)["Num5"] = sf::Keyboard::Num5;
    (*map)["Num4"] = sf::Keyboard::Num4;
    (*map)["Num3"] = sf::Keyboard::Num3;
    (*map)["Num2"] = sf::Keyboard::Num2;
    (*map)["Num1"] = sf::Keyboard::Num1;
    (*map)["Num0"] = sf::Keyboard::Num0;

    (*map)["Escape"] = sf::Keyboard::Escape;
    (*map)["RControl"] = sf::Keyboard::RControl;
    (*map)["RShift"] = sf::Keyboard::RShift;
    (*map)["RAlt"] = sf::Keyboard::RAlt;
    (*map)["LControl"] = sf::Keyboard::LControl;
    (*map)["LShift"] = sf::Keyboard::LShift;
    (*map)["LAlt"] = sf::Keyboard::LAlt;
    (*map)["LSystem"] = sf::Keyboard::LSystem;
    (*map)["RSystem"] = sf::Keyboard::RSystem;
    (*map)["Menu"] = sf::Keyboard::Menu;
    (*map)["LBracket"] = sf::Keyboard::LBracket;
    (*map)["RBracket"] = sf::Keyboard::RBracket;
    (*map)["SemiColon"] = sf::Keyboard::SemiColon;
    (*map)["Comma"] = sf::Keyboard::Comma;
    (*map)["Period"] = sf::Keyboard::Period;
    (*map)["Quote"] = sf::Keyboard::Quote;
    (*map)["Slash"] = sf::Keyboard::Slash;
    (*map)["BackSlash"] = sf::Keyboard::BackSlash;
    (*map)["Tilde"] = sf::Keyboard::Tilde;
    (*map)["Equal"] = sf::Keyboard::Equal;
    (*map)["Dash"] = sf::Keyboard::Dash;
    (*map)["Space"] = sf::Keyboard::Space;
    (*map)["Return"] = sf::Keyboard::Return;
    (*map)["Back"] = sf::Keyboard::BackSpace;
    (*map)["Tab"] = sf::Keyboard::Tab;
    (*map)["PageUp"] = sf::Keyboard::PageUp;
    (*map)["PageDown"] = sf::Keyboard::PageDown;
    (*map)["End"] = sf::Keyboard::End;
    (*map)["Home"] = sf::Keyboard::Home;
    (*map)["Insert"] = sf::Keyboard::Insert;
    (*map)["Delete"] = sf::Keyboard::Delete;

    (*map)["Add"] = sf::Keyboard::Add;
    (*map)["Subtract"] = sf::Keyboard::Subtract;
    (*map)["Multiply"] = sf::Keyboard::Multiply;
    (*map)["Divide"] = sf::Keyboard::Divide;

    (*map)["Left"] = sf::Keyboard::Left;
    (*map)["Right"] = sf::Keyboard::Right;
    (*map)["Up"] = sf::Keyboard::Up;
    (*map)["Down"] = sf::Keyboard::Down;

    (*map)["Numpad0"] = sf::Keyboard::Numpad0;
    (*map)["Numpad1"] = sf::Keyboard::Numpad1;
    (*map)["Numpad2"] = sf::Keyboard::Numpad2;
    (*map)["Numpad3"] = sf::Keyboard::Numpad3;
    (*map)["Numpad4"] = sf::Keyboard::Numpad4;
    (*map)["Numpad5"] = sf::Keyboard::Numpad5;
    (*map)["Numpad6"] = sf::Keyboard::Numpad6;
    (*map)["Numpad7"] = sf::Keyboard::Numpad7;
    (*map)["Numpad8"] = sf::Keyboard::Numpad8;
    (*map)["Numpad9"] = sf::Keyboard::Numpad9;

    (*map)["F1"] = sf::Keyboard::F1;
    (*map)["F2"] = sf::Keyboard::F2;
    (*map)["F3"] = sf::Keyboard::F3;
    (*map)["F4"] = sf::Keyboard::F4;
    (*map)["F5"] = sf::Keyboard::F5;
    (*map)["F6"] = sf::Keyboard::F6;
    (*map)["F7"] = sf::Keyboard::F7;
    (*map)["F8"] = sf::Keyboard::F8;
    (*map)["F9"] = sf::Keyboard::F9;
    (*map)["F10"] = sf::Keyboard::F10;
    (*map)["F11"] = sf::Keyboard::F11;
    (*map)["F12"] = sf::Keyboard::F12;
    (*map)["F13"] = sf::Keyboard::F13;
    (*map)["F14"] = sf::Keyboard::F14;
    (*map)["F15"] = sf::Keyboard::F15;

    (*map)["Pause"] = sf::Keyboard::Pause;

    initialized = true;
  }

  return *map;
}

const std::map<int, gd::String>& InputManager::GetSfKeyToKeyNameMap() {
  static bool initialized = false;
  static std::map<int, gd::String>* map = new std::map<int, gd::String>();
  if (!initialized) {
    const auto& keyMap = GetKeyNameToSfKeyMap();
    for (auto it = keyMap.begin(); it != keyMap.end(); ++it)
      (*map)[it->second] = it->first;

    initialized = true;
  }

  return *map;
}

const std::map<gd::String, int>& InputManager::GetButtonNameToSfButtonMap() {
  static bool initialized = false;
  static std::map<gd::String, int>* map = new std::map<gd::String, int>();
  if (!initialized) {
    (*map)["Left"] = sf::Mouse::Left;
    (*map)["Right"] = sf::Mouse::Right;
    (*map)["Middle"] = sf::Mouse::Middle;
    (*map)["XButton1"] = sf::Mouse::XButton1;
    (*map)["XButton2"] = sf::Mouse::XButton2;

    initialized = true;
  }

  return *map;
}

const std::map<int, gd::String>& InputManager::GetSfButtonToButtonNameMap() {
  static bool initialized = false;
  static std::map<int, gd::String>* map = new std::map<int, gd::String>();
  if (!initialized) {
    const auto& buttonMap = GetButtonNameToSfButtonMap();
    for (auto it = buttonMap.begin(); it != buttonMap.end(); ++it)
      (*map)[it->second] = it->first;

    initialized = true;
  }

  return *map;
}
