#pragma once

#include <frostbite2D/event/event.h>
#include <frostbite2D/types/type_math.h>
#include <SDL2/SDL_mouse.h>

namespace frostbite2D {

enum class MouseButton {
  Left = SDL_BUTTON_LEFT,
  Right = SDL_BUTTON_RIGHT,
  Middle = SDL_BUTTON_MIDDLE,
  X1 = SDL_BUTTON_X1,
  X2 = SDL_BUTTON_X2
};

class MouseEvent : public Event {
public:
  MouseEvent(EventType type, uint32 timestamp, const Vec2& position)
    : Event(timestamp)
    , type_(type)
    , position_(position) {}
  
  virtual ~MouseEvent() = default;
  
  EventType getType() const override { return type_; }
  const Vec2& getPosition() const { return position_; }
  int32 getX() const { return static_cast<int32>(position_.x); }
  int32 getY() const { return static_cast<int32>(position_.y); }
  
protected:
  EventType type_;
  Vec2 position_;
};

class MouseMoveEvent : public Event {
public:
  MouseMoveEvent(uint32 timestamp, const Vec2& position, const Vec2& relative)
    : Event(timestamp)
    , position_(position)
    , relative_(relative) {}
  
  EventType getType() const override {
    return EventType::MouseMove;
  }
  
  const Vec2& getPosition() const { return position_; }
  const Vec2& getRelative() const { return relative_; }
  
  int32 getX() const { return static_cast<int32>(position_.x); }
  int32 getY() const { return static_cast<int32>(position_.y); }
  
private:
  Vec2 position_;
  Vec2 relative_;
};

class MouseButtonEvent : public Event {
public:
  MouseButtonEvent(uint32 timestamp, MouseButton button, const Vec2& position, bool down)
    : Event(timestamp)
    , button_(button)
    , position_(position)
    , down_(down) {}
  
  EventType getType() const override {
    return down_ ? EventType::MouseButtonDown : EventType::MouseButtonUp;
  }
  
  MouseButton getButton() const { return button_; }
  const Vec2& getPosition() const { return position_; }
  bool isDown() const { return down_; }
  
  int32 getX() const { return static_cast<int32>(position_.x); }
  int32 getY() const { return static_cast<int32>(position_.y); }
  
private:
  MouseButton button_;
  Vec2 position_;
  bool down_;
};

class MouseWheelEvent : public Event {
public:
  MouseWheelEvent(uint32 timestamp, const Vec2& position, const Vec2& direction, bool flipped)
    : Event(timestamp)
    , position_(position)
    , direction_(direction)
    , flipped_(flipped) {}
  
  EventType getType() const override {
    return EventType::MouseWheel;
  }
  
  const Vec2& getPosition() const { return position_; }
  const Vec2& getDirection() const { return direction_; }
  bool isFlipped() const { return flipped_; }
  
  int32 getX() const { return static_cast<int32>(direction_.x); }
  int32 getY() const { return static_cast<int32>(direction_.y); }
  
private:
  Vec2 position_;
  Vec2 direction_;
  bool flipped_;
};

}
