#include "core/rendering/movingsprite.h"

#include "core/rendering/texture.h"  // for Texture

// Constructor
MovingSprite::MovingSprite(float x, float y, int w, int h, float velx, float vely, float accelx, float accely, Texture *texture, SDL_Renderer *renderer)
    : Sprite(0, 0, w, h, texture, renderer),
      x_(x),
      y_(y),
      x_prev_(x),
      y_prev_(y),
      vx_(velx),
      vy_(vely),
      ax_(accelx),
      ay_(accely) {
}

// Reinicia todas las variables
void MovingSprite::clear() {
    x_ = 0.0F;
    y_ = 0.0F;

    vx_ = 0.0F;
    vy_ = 0.0F;

    ax_ = 0.0F;
    ay_ = 0.0F;

    zoom_w_ = 1.0F;
    zoom_h_ = 1.0F;

    angle_ = 0.0;
    rotate_enabled_ = false;
    center_ = nullptr;
    rotate_speed_ = 0;
    rotate_amount_ = 0.0;
    counter_ = 0;

    current_flip_ = SDL_FLIP_NONE;
}

// Mueve el sprite
void MovingSprite::move() {
    if (enabled_) {
        x_prev_ = x_;
        y_prev_ = y_;

        x_ += vx_;
        y_ += vy_;

        vx_ += ax_;
        vy_ += ay_;
    }
}

// Muestra el sprite por pantalla
void MovingSprite::render() {
    if (enabled_) {
        texture_->render(renderer_, (int)x_, (int)y_, &sprite_clip_, zoom_w_, zoom_h_, angle_, center_, current_flip_);
    }
}

// Obtiene el valor de la variable
// cppcheck-suppress duplInheritedMember
auto MovingSprite::getPosX() const -> float {
    return x_;
}

// Obtiene el valor de la variable
// cppcheck-suppress duplInheritedMember
auto MovingSprite::getPosY() const -> float {
    return y_;
}

// Obtiene el valor de la variable
auto MovingSprite::getVelX() const -> float {
    return vx_;
}

// Obtiene el valor de la variable
auto MovingSprite::getVelY() const -> float {
    return vy_;
}

// Obtiene el valor de la variable
auto MovingSprite::getAccelX() const -> float {
    return ax_;
}

// Obtiene el valor de la variable
auto MovingSprite::getAccelY() const -> float {
    return ay_;
}

// Obtiene el valor de la variable
auto MovingSprite::getZoomW() const -> float {
    return zoom_w_;
}

// Obtiene el valor de la variable
auto MovingSprite::getZoomH() const -> float {
    return zoom_h_;
}

// Obtiene el valor de la variable
auto MovingSprite::getAngle() const -> double {
    return angle_;
}

// Establece la posición y el tamaño del objeto
void MovingSprite::setRect(SDL_Rect rect) {
    x_ = (float)rect.x;
    y_ = (float)rect.y;
    w_ = rect.w;
    h_ = rect.h;
}

// Establece el valor de la variable
void MovingSprite::setPosX(float value) {
    x_ = value;
}

// Establece el valor de la variable
void MovingSprite::setPosY(float value) {
    y_ = value;
}

// Establece el valor de la variable
void MovingSprite::setVelX(float value) {
    vx_ = value;
}

// Establece el valor de la variable
void MovingSprite::setVelY(float value) {
    vy_ = value;
}

// Establece el valor de la variable
void MovingSprite::setAccelX(float value) {
    ax_ = value;
}

// Establece el valor de la variable
void MovingSprite::setAccelY(float value) {
    ay_ = value;
}

// Establece el valor de la variable
void MovingSprite::setZoomW(float value) {
    zoom_w_ = value;
}

// Establece el valor de la variable
void MovingSprite::setZoomH(float value) {
    zoom_h_ = value;
}

// Establece el valor de la variable
void MovingSprite::setAngle(double value) {
    angle_ = value;
}

// Incrementa el valor de la variable
void MovingSprite::incAngle(double value) {
    angle_ += value;
}

// Decrementa el valor de la variable
void MovingSprite::decAngle(double value) {
    angle_ -= value;
}

// Obtiene el valor de la variable
auto MovingSprite::getRotate() const -> bool {
    return rotate_enabled_;
}

// Obtiene el valor de la variable
auto MovingSprite::getRotateSpeed() const -> Uint16 {
    return rotate_speed_;
}

// Establece la rotacion
void MovingSprite::rotate() {
    if (enabled_) {
        if (rotate_enabled_) {
            if (counter_ % rotate_speed_ == 0) {
                incAngle(rotate_amount_);
            }
        }
    }
}

// Establece el valor de la variable
void MovingSprite::setRotate(bool value) {
    rotate_enabled_ = value;
}

// Establece el valor de la variable
void MovingSprite::setRotateSpeed(int value) {
    if (value < 1) {
        rotate_speed_ = 1;
    } else {
        rotate_speed_ = value;
    }
}

// Establece el valor de la variable
void MovingSprite::setRotateAmount(double value) {
    rotate_amount_ = value;
}

// Establece el valor de la variable
void MovingSprite::disableRotate() {
    rotate_enabled_ = false;
    angle_ = (double)0;
}

// Actualiza las variables internas del objeto
void MovingSprite::update() {
    move();
    rotate();

    if (enabled_) {
        ++counter_ %= 60000;
    }
}

// Cambia el sentido de la rotación
void MovingSprite::switchRotate() {
    rotate_amount_ *= -1;
}

// Establece el valor de la variable
void MovingSprite::setFlip(SDL_FlipMode flip) {
    current_flip_ = flip;
}

// Gira el sprite horizontalmente
void MovingSprite::flip() {
    current_flip_ = (current_flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL;
}

// Obtiene el valor de la variable
auto MovingSprite::getFlip() -> SDL_FlipMode {
    return current_flip_;
}

// Devuelve el rectangulo donde está el sprite
auto MovingSprite::getRect() -> SDL_Rect {
    const SDL_Rect RECT = {(int)x_, (int)y_, w_, h_};
    return RECT;
}

// Deshace el último movimiento
void MovingSprite::undoMove() {
    x_ = x_prev_;
    y_ = y_prev_;
}

// Deshace el último movimiento en el eje X
void MovingSprite::undoMoveX() {
    x_ = x_prev_;
}

// Deshace el último movimiento en el eje Y
void MovingSprite::undoMoveY() {
    y_ = y_prev_;
}

// Pone a cero las velocidades de desplacamiento
void MovingSprite::clearVel() {
    vx_ = vy_ = 0.0F;
}

// Devuelve el incremento en el eje X en pixels
auto MovingSprite::getIncX() const -> int {
    return (int)x_ - (int)x_prev_;
}
