#include "sprite.h"
#include "camera.h"
#include "debug.h"
#include "render.h"
#include "spritesheet.h"
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_render.h>

struct Sprite {
    // The animation sheet to sample sprites from.
    Spritesheet* spritesheet;

    // The current frame of animation.
    size_t tile_index;

    // The local transformation of this sprite.
    Vector origin;

    SDL_RendererFlip flip_state;
};

Sprite* sprite_new_empty() {
    Sprite* self = malloc(sizeof(Sprite));
    ASSERT_RETURN(self != NULL, NULL, "Failed to allocate memory for new sprite.");
    *self = (Sprite){
        .spritesheet = NULL,
        .tile_index = 0,
        .origin = ZeroVector,
        .flip_state = SDL_FLIP_NONE,
    };
    return self;
}

Sprite* sprite_from_spritesheet(Spritesheet* sheet, size_t initial_frame) {
    Sprite* self = sprite_new_empty();
    self->spritesheet = sheet;
    self->origin = VectorFrom(0.5f);
    self->tile_index = initial_frame;
    return self;
}

void sprite_destroy(Sprite* self) {
    free(self);
}

void sprite_draw(Sprite* self, Transform transform) {
    SDL_Texture* texture = spritesheet_get_texture(self->spritesheet);
    SDL_Rect source = spritesheet_get_tile_rect(self->spritesheet, self->tile_index);

    Vector origin = self->origin;
    if(self->flip_state && SDL_FLIP_HORIZONTAL) {
        origin.x = 1.0f-origin.x;
    }
    if((self->flip_state & SDL_FLIP_VERTICAL) != 0) {
        origin.y = 1.0f-origin.y;
    }

    Vector left_top = transform_point(&transform, vinvf(origin));
    SDL_FRect destination = (SDL_FRect) {
        left_top.x, left_top.y,
        transform.scale.x, transform.scale.y
    };
    destination = camera_world_to_pixel_rect(&g_camera, &destination);

    origin = vmulf(origin, transform.scale);

    SDL_RenderCopyExF(g_renderer, texture, &source, &destination,
                      transform.rotation * 57.2958, &origin, self->flip_state);
    SDL_SetRenderDrawColor(g_renderer, 255, 255, 255, 255);
}

Vector sprite_get_origin(Sprite* self) {
    return self->origin;
}

void sprite_set_origin(Sprite* self, Vector origin) {
    self->origin = origin;
}

size_t sprite_get_tile(const Sprite* self) {
    return self->tile_index;
}

void sprite_set_tile(Sprite* self, size_t frame) {
    self->tile_index = frame % spritesheet_get_tile_count(self->spritesheet);
}

Spritesheet* sprite_get_spritesheet(const Sprite* self) {
    return self->spritesheet;
}

void sprite_set_spritesheet(Sprite* self, Spritesheet* spritesheet) {
    self->spritesheet = spritesheet;
}

void sprite_flip_horizontal(Sprite* self, int horizontal) {
    if(horizontal) {
        self->flip_state |= SDL_FLIP_HORIZONTAL;
    } else {
        self->flip_state &= ~SDL_FLIP_HORIZONTAL;
    }
}

void sprite_flip_vertical(Sprite* self, int vertical) {
    if(vertical) {
        self->flip_state |= SDL_FLIP_VERTICAL;
    } else {
        self->flip_state &= ~SDL_FLIP_VERTICAL;
    }
}
