#include <gfx/gfx.h>
#include <gfx/port.h>
#include <header.h>
#include <sdl-1.2/gfx/private.h>
#include <SDL.h>
#include <SDL_rotozoom.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>

void sprite_free(struct gfx_sprite *const s)
{
    if (s && s->s)
        SDL_FreeSurface(s->s);
}

int sprite_clone(const struct gfx_sprite *const src, struct gfx_sprite *const dst)
{
    *dst = *src;
    return 0;
}

static int set_transparent(SDL_Surface *const s)
{
    /* Magenta as transparent. */
    const Uint32 map = SDL_MapRGB(s->format, 255, 0, 255);
    const int ret = SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, map);

    if (ret)
        fprintf(stderr, "SDL_SetColorKey: %s\n", SDL_GetError());

    return ret;
}

int sprite_screen_resize_ev(struct gfx_sprite *const s)
{
    int ret = -1;
    SDL_Surface *const old = s->s, *const old_x = s->s_x;

    if (s->transparent && (set_transparent(old) || set_transparent(old_x)))
        goto end;
    else if (!(s->s = SDL_DisplayFormat(old)))
    {
        fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
        goto end;
    }
    else if (!(s->s_x = SDL_DisplayFormat(old_x)))
    {
        fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
        goto end;
    }

    ret = 0;

end:
    SDL_FreeSurface(old);
    SDL_FreeSurface(old_x);
    return ret;
}

static int load_header(struct gfx_sprite *const s, FILE *const f)
{
    if (header_load_bool(f, "transparent", &s->transparent))
        return -1;

    return 0;
}

static int load_bitmap(struct gfx_sprite *const s, FILE *const f)
{
    int ret = -1;
    SDL_RWops *ops = NULL;
    SDL_Surface *ts = NULL, *zs = NULL;

    if (!(ops = SDL_RWFromFP(f, 0)))
    {
        fprintf(stderr, "SDL_RWFromFP: %s\n", SDL_GetError());
        goto end;
    }
    else if (!(ts = SDL_LoadBMP_RW(ops, 0)))
    {
        fprintf(stderr, "SDL_LoadBMP_RW: %s\n", SDL_GetError());
        goto end;
    }
    else if (!(zs = zoomSurface(ts, -1, 1, 0)))
    {
        fprintf(stderr, "zoomSurface: %s\n", SDL_GetError());
        goto end;
    }
    else if (s->transparent && (set_transparent(ts) || set_transparent(zs)))
        goto end;
    else if (!(s->s = SDL_DisplayFormat(ts)))
    {
        fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
        goto end;
    }
    else if (!(s->s_x = SDL_DisplayFormat(zs)))
    {
        fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
        goto end;
    }

    gfx_register_sprite(s);
    s->w = ts->w;
    s->h = ts->h;
    ret = 0;

end:
    SDL_FreeRW(ops);
    SDL_FreeSurface(ts);
    SDL_FreeSurface(zs);
    return ret;
}

int sprite_from_fp(struct gfx_sprite *const s, FILE *const f)
{
    *s = (const struct gfx_sprite){0};

    if (load_header(s, f) || load_bitmap(s, f))
        return -1;

    return 0;
}

void sprite_sort(struct gfx_sprite *const s)
{
    SDL_Rect r =
    {
        .x = s->x,
        .y = s->y
    };

    SDL_Rect clip =
    {
        .x = s->u,
        .y = s->v,
        .w = s->w,
        .h = s->h
    };

    if (SDL_BlitSurface(s->s, &clip, gfx_screen(), &r))
        fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
}
