#include <gui/bar.h>
#include <gui_private.h>
#include <gui.h>
#include <gfx.h>

struct sprite gui_bar_sprites[MAX_GUI_BAR_SPRITES];

static int render_topleft(const struct gui_bar *const b, const short x,
    const short y)
{
    sprite_get_or_ret(s, -1);

    if (sprite_clone(&gui_bar_sprites[GUI_BAR_LEFT], s))
        return -1;

    s->x = x;
    s->y = y;

    const int ret = sprite_sort(s);

    if (ret)
        fprintf(stderr, "%s: sprite_sort failed\n", __func__);

    return ret;
}

static int render_topright(const struct gui_bar *const b, const short x,
    const short y)
{
    sprite_get_or_ret(s, -1);

    if (sprite_clone(&gui_bar_sprites[GUI_BAR_RIGHT], s))
        return -1;

    s->x = x + b->w - s->w;
    s->y = y;

    const int ret = sprite_sort(s);

    if (ret)
        fprintf(stderr, "%s: sprite_sort failed\n", __func__);

    return 0;
}

static int render_topmid(const struct gui_bar *const b, const short x,
    const short y)
{
    const short mid_w = gui_bar_sprites[GUI_BAR_MID].w,
        lw = gui_bar_sprites[GUI_BAR_LEFT].w,
        w = b->w - lw - lw;

    if (w <= 0)
        return -1;

    const short rem_mid = w % mid_w,
        whole_mid = w / mid_w,
        n_mid = rem_mid ? whole_mid + 1 : whole_mid;

    for (struct
        {
            size_t i;
            short x;
        } a = {.x = x + lw}; a.i < n_mid; a.i++, a.x += mid_w)
    {
        sprite_get_or_ret(m, -1);

        if (sprite_clone(&gui_bar_sprites[GUI_BAR_MID], m))
            return -1;

        m->x = a.x;
        m->y = y;

        if (rem_mid && a.i + 1 == n_mid)
            m->w = rem_mid;
        else
            m->w = mid_w;

        if (sprite_sort(m))
        {
            fprintf(stderr, "%s: sprite_sort failed\n", __func__);
            return -1;
        }
    }

    return 0;
}

static int render(const struct gui_common *const g)
{
    const struct gui_bar *const b = (const struct gui_bar *)g;
    short x, y;

    gui_coords(&b->common, &x, &y);

    if (render_topleft(b, x, y)
        || render_topright(b, x, y)
        || render_topmid(b, x, y))
        return -1;

    return 0;
}

static void get_dim(const struct gui_common *const g, short *const w,
    short *const h)
{
    const struct gui_bar *const b = (const struct gui_bar *)g;

    *w = b->w;
    *h = gui_bar_sprites[GUI_BAR_MID].h;
}

void gui_bar_init(struct gui_bar *const b)
{
    static const struct gui_common_cb cb =
    {
        .render = render,
        .get_dim = get_dim
    };

    *b = (const struct gui_bar)
    {
        .common =
        {
            .cb = &cb
        }
    };
}
