// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <map>
#include <string>

namespace ButtonManager
{
enum ButtonType
{
  // GC
  BUTTON_A = 0,
  BUTTON_B = 1,
  BUTTON_START = 2,
  BUTTON_X = 3,
  BUTTON_Y = 4,
  BUTTON_Z = 5,
  BUTTON_UP = 6,
  BUTTON_DOWN = 7,
  BUTTON_LEFT = 8,
  BUTTON_RIGHT = 9,
  STICK_MAIN = 10,  // Used on Java Side
  STICK_MAIN_UP = 11,
  STICK_MAIN_DOWN = 12,
  STICK_MAIN_LEFT = 13,
  STICK_MAIN_RIGHT = 14,
  STICK_C = 15,  // Used on Java Side
  STICK_C_UP = 16,
  STICK_C_DOWN = 17,
  STICK_C_LEFT = 18,
  STICK_C_RIGHT = 19,
  TRIGGER_L = 20,
  TRIGGER_R = 21,
  // Wiimote
  WIIMOTE_BUTTON_A = 100,
  WIIMOTE_BUTTON_B = 101,
  WIIMOTE_BUTTON_MINUS = 102,
  WIIMOTE_BUTTON_PLUS = 103,
  WIIMOTE_BUTTON_HOME = 104,
  WIIMOTE_BUTTON_1 = 105,
  WIIMOTE_BUTTON_2 = 106,
  WIIMOTE_UP = 107,
  WIIMOTE_DOWN = 108,
  WIIMOTE_LEFT = 109,
  WIIMOTE_RIGHT = 110,
  WIIMOTE_IR = 111,  // To Be Used on Java Side
  WIIMOTE_IR_UP = 112,
  WIIMOTE_IR_DOWN = 113,
  WIIMOTE_IR_LEFT = 114,
  WIIMOTE_IR_RIGHT = 115,
  WIIMOTE_IR_FORWARD = 116,
  WIIMOTE_IR_BACKWARD = 117,
  WIIMOTE_IR_HIDE = 118,
  WIIMOTE_SWING = 119,  // To Be Used on Java Side
  WIIMOTE_SWING_UP = 120,
  WIIMOTE_SWING_DOWN = 121,
  WIIMOTE_SWING_LEFT = 122,
  WIIMOTE_SWING_RIGHT = 123,
  WIIMOTE_SWING_FORWARD = 124,
  WIIMOTE_SWING_BACKWARD = 125,
  WIIMOTE_TILT = 126,  // To Be Used on Java Side
  WIIMOTE_TILT_FORWARD = 127,
  WIIMOTE_TILT_BACKWARD = 128,
  WIIMOTE_TILT_LEFT = 129,
  WIIMOTE_TILT_RIGHT = 130,
  WIIMOTE_TILT_MODIFIER = 131,
  WIIMOTE_SHAKE_X = 132,
  WIIMOTE_SHAKE_Y = 133,
  WIIMOTE_SHAKE_Z = 134,
  // Nunchuk
  NUNCHUK_BUTTON_C = 200,
  NUNCHUK_BUTTON_Z = 201,
  NUNCHUK_STICK = 202,  // To Be Used on Java Side
  NUNCHUK_STICK_UP = 203,
  NUNCHUK_STICK_DOWN = 204,
  NUNCHUK_STICK_LEFT = 205,
  NUNCHUK_STICK_RIGHT = 206,
  NUNCHUK_SWING = 207,  // To Be Used on Java Side
  NUNCHUK_SWING_UP = 208,
  NUNCHUK_SWING_DOWN = 209,
  NUNCHUK_SWING_LEFT = 210,
  NUNCHUK_SWING_RIGHT = 211,
  NUNCHUK_SWING_FORWARD = 212,
  NUNCHUK_SWING_BACKWARD = 213,
  NUNCHUK_TILT = 214,  // To Be Used on Java Side
  NUNCHUK_TILT_FORWARD = 215,
  NUNCHUK_TILT_BACKWARD = 216,
  NUNCHUK_TILT_LEFT = 217,
  NUNCHUK_TILT_RIGHT = 218,
  NUNCHUK_TILT_MODIFIER = 219,
  NUNCHUK_SHAKE_X = 220,
  NUNCHUK_SHAKE_Y = 221,
  NUNCHUK_SHAKE_Z = 222,
  // Classic
  CLASSIC_BUTTON_A = 300,
  CLASSIC_BUTTON_B = 301,
  CLASSIC_BUTTON_X = 302,
  CLASSIC_BUTTON_Y = 303,
  CLASSIC_BUTTON_MINUS = 304,
  CLASSIC_BUTTON_PLUS = 305,
  CLASSIC_BUTTON_HOME = 306,
  CLASSIC_BUTTON_ZL = 307,
  CLASSIC_BUTTON_ZR = 308,
  CLASSIC_DPAD_UP = 309,
  CLASSIC_DPAD_DOWN = 310,
  CLASSIC_DPAD_LEFT = 311,
  CLASSIC_DPAD_RIGHT = 312,
  CLASSIC_STICK_LEFT = 313,  // To Be Used on Java Side
  CLASSIC_STICK_LEFT_UP = 314,
  CLASSIC_STICK_LEFT_DOWN = 315,
  CLASSIC_STICK_LEFT_LEFT = 316,
  CLASSIC_STICK_LEFT_RIGHT = 317,
  CLASSIC_STICK_RIGHT = 318,  // To Be Used on Java Side
  CLASSIC_STICK_RIGHT_UP = 319,
  CLASSIC_STICK_RIGHT_DOWN = 320,
  CLASSIC_STICK_RIGHT_LEFT = 321,
  CLASSIC_STICK_RIGHT_RIGHT = 322,
  CLASSIC_TRIGGER_L = 323,
  CLASSIC_TRIGGER_R = 324,
  // Guitar
  GUITAR_BUTTON_MINUS = 400,
  GUITAR_BUTTON_PLUS = 401,
  GUITAR_FRET_GREEN = 402,
  GUITAR_FRET_RED = 403,
  GUITAR_FRET_YELLOW = 404,
  GUITAR_FRET_BLUE = 405,
  GUITAR_FRET_ORANGE = 406,
  GUITAR_STRUM_UP = 407,
  GUITAR_STRUM_DOWN = 408,
  GUITAR_STICK = 409,  // To Be Used on Java Side
  GUITAR_STICK_UP = 410,
  GUITAR_STICK_DOWN = 411,
  GUITAR_STICK_LEFT = 412,
  GUITAR_STICK_RIGHT = 413,
  GUITAR_WHAMMY_BAR = 414,
  // Drums
  DRUMS_BUTTON_MINUS = 500,
  DRUMS_BUTTON_PLUS = 501,
  DRUMS_PAD_RED = 502,
  DRUMS_PAD_YELLOW = 503,
  DRUMS_PAD_BLUE = 504,
  DRUMS_PAD_GREEN = 505,
  DRUMS_PAD_ORANGE = 506,
  DRUMS_PAD_BASS = 507,
  DRUMS_STICK = 508,  // To Be Used on Java Side
  DRUMS_STICK_UP = 509,
  DRUMS_STICK_DOWN = 510,
  DRUMS_STICK_LEFT = 511,
  DRUMS_STICK_RIGHT = 512,
  // Turntable
  TURNTABLE_BUTTON_GREEN_LEFT = 600,
  TURNTABLE_BUTTON_RED_LEFT = 601,
  TURNTABLE_BUTTON_BLUE_LEFT = 602,
  TURNTABLE_BUTTON_GREEN_RIGHT = 603,
  TURNTABLE_BUTTON_RED_RIGHT = 604,
  TURNTABLE_BUTTON_BLUE_RIGHT = 605,
  TURNTABLE_BUTTON_MINUS = 606,
  TURNTABLE_BUTTON_PLUS = 607,
  TURNTABLE_BUTTON_HOME = 608,
  TURNTABLE_BUTTON_EUPHORIA = 609,
  TURNTABLE_TABLE_LEFT = 610,  // To Be Used on Java Side
  TURNTABLE_TABLE_LEFT_LEFT = 611,
  TURNTABLE_TABLE_LEFT_RIGHT = 612,
  TURNTABLE_TABLE_RIGHT = 613,  // To Be Used on Java Side
  TURNTABLE_TABLE_RIGHT_LEFT = 614,
  TURNTABLE_TABLE_RIGHT_RIGHT = 615,
  TURNTABLE_STICK = 616,  // To Be Used on Java Side
  TURNTABLE_STICK_UP = 617,
  TURNTABLE_STICK_DOWN = 618,
  TURNTABLE_STICK_LEFT = 619,
  TURNTABLE_STICK_RIGHT = 620,
  TURNTABLE_EFFECT_DIAL = 621,
  TURNTABLE_CROSSFADE = 622,  // To Be Used on Java Side
  TURNTABLE_CROSSFADE_LEFT = 623,
  TURNTABLE_CROSSFADE_RIGHT = 624,
};
enum ButtonState
{
  BUTTON_RELEASED = 0,
  BUTTON_PRESSED = 1
};
enum BindType
{
  BIND_BUTTON = 0,
  BIND_AXIS
};
class Button
{
private:
  ButtonState m_state;

public:
  Button() : m_state(BUTTON_RELEASED) {}
  void SetState(ButtonState state) { m_state = state; }
  bool Pressed() { return m_state == BUTTON_PRESSED; }
  ~Button() {}
};
class Axis
{
private:
  float m_value;

public:
  Axis() : m_value(0.0f) {}
  void SetValue(float value) { m_value = value; }
  float AxisValue() { return m_value; }
  ~Axis() {}
};

struct sBind
{
  const int _padID;
  const ButtonType _buttontype;
  const BindType _bindtype;
  const int _bind;
  const float _neg;
  sBind(int padID, ButtonType buttontype, BindType bindtype, int bind, float neg)
      : _padID(padID), _buttontype(buttontype), _bindtype(bindtype), _bind(bind), _neg(neg)
  {
  }
};

class InputDevice
{
private:
  const std::string _dev;
  std::map<ButtonType, bool> _buttons;
  std::map<ButtonType, float> _axises;

  // Key is padID and ButtonType
  std::map<std::pair<int, ButtonType>, sBind*> _inputbinds;

public:
  InputDevice(std::string dev) : _dev(dev) {}
  ~InputDevice()
  {
    for (const auto& bind : _inputbinds)
      delete bind.second;
    _inputbinds.clear();
  }
  void AddBind(sBind* bind) { _inputbinds[std::make_pair(bind->_padID, bind->_buttontype)] = bind; }
  bool PressEvent(int button, int action);
  void AxisEvent(int axis, float value);
  bool ButtonValue(int padID, ButtonType button);
  float AxisValue(int padID, ButtonType axis);
};

void Init();
bool GetButtonPressed(int padID, ButtonType button);
float GetAxisValue(int padID, ButtonType axis);
bool GamepadEvent(const std::string& dev, int button, int action);
void GamepadAxisEvent(const std::string& dev, int axis, float value);
void Shutdown();
}