#pragma once

#include <frostbite2D/event/event.h>
#include <SDL2/SDL_joystick.h>

namespace frostbite2D {

class JoystickEvent : public Event {
public:
  JoystickEvent(EventType type, uint32 timestamp, int32 deviceId)
    : Event(timestamp)
    , type_(type)
    , deviceId_(deviceId) {}
  
  EventType getType() const override {
    return type_;
  }
  
  int32 getDeviceId() const { return deviceId_; }
  
protected:
  EventType type_;
  int32 deviceId_;
};

class JoystickAxisEvent : public JoystickEvent {
public:
  JoystickAxisEvent(uint32 timestamp, int32 deviceId, uint8 axis, int16 value)
    : JoystickEvent(EventType::JoystickAxis, timestamp, deviceId)
    , axis_(axis)
    , value_(value) {}
  
  uint8 getAxis() const { return axis_; }
  int16 getValue() const { return value_; }
  
  float getNormalizedValue() const {
    return static_cast<float>(value_) / 32767.0f;
  }
  
private:
  uint8 axis_;
  int16 value_;
};

class JoystickBallEvent : public JoystickEvent {
public:
  JoystickBallEvent(uint32 timestamp, int32 deviceId, uint8 ball, int16 dx, int16 dy)
    : JoystickEvent(EventType::JoystickBall, timestamp, deviceId)
    , ball_(ball)
    , dx_(dx)
    , dy_(dy) {}
  
  uint8 getBall() const { return ball_; }
  int16 getDX() const { return dx_; }
  int16 getDY() const { return dy_; }
  
private:
  uint8 ball_;
  int16 dx_;
  int16 dy_;
};

class JoystickHatEvent : public JoystickEvent {
public:
  JoystickHatEvent(uint32 timestamp, int32 deviceId, uint8 hat, uint8 value)
    : JoystickEvent(EventType::JoystickHat, timestamp, deviceId)
    , hat_(hat)
    , value_(value) {}
  
  uint8 getHat() const { return hat_; }
  uint8 getValue() const { return value_; }
  
  bool isCentered() const { return value_ == SDL_HAT_CENTERED; }
  bool isUp() const { return (value_ & SDL_HAT_UP) != 0; }
  bool isRight() const { return (value_ & SDL_HAT_RIGHT) != 0; }
  bool isDown() const { return (value_ & SDL_HAT_DOWN) != 0; }
  bool isLeft() const { return (value_ & SDL_HAT_LEFT) != 0; }
  
private:
  uint8 hat_;
  uint8 value_;
};

class JoystickButtonEvent : public JoystickEvent {
public:
  JoystickButtonEvent(EventType type, uint32 timestamp, int32 deviceId, uint8 button)
    : JoystickEvent(type, timestamp, deviceId)
    , button_(button) {}
  
  EventType getType() const override {
    return type_;
  }
  
  uint8 getButton() const { return button_; }
  
private:
  uint8 button_;
};

class JoystickButtonDownEvent : public JoystickButtonEvent {
public:
  JoystickButtonDownEvent(uint32 timestamp, int32 deviceId, uint8 button)
    : JoystickButtonEvent(EventType::JoystickButtonDown, timestamp, deviceId, button) {}
};

class JoystickButtonUpEvent : public JoystickButtonEvent {
public:
  JoystickButtonUpEvent(uint32 timestamp, int32 deviceId, uint8 button)
    : JoystickButtonEvent(EventType::JoystickButtonUp, timestamp, deviceId, button) {}
};

}
