#include <gui.h>
#include <gui/button.h>
#include <gui_private.h>
#include <gui_button_private.h>
#include <stdio.h>

struct sprite gui_button_sprites[MAX_GUI_BUTTON_SPRITES];

/* Alias for readability. */
static const struct sprite *const refs = gui_button_sprites;

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

    if (sprite_clone(&refs[GUI_BUTTON_LEFT], s))
        return -1;

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

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

    *x = s->x + s->w;
    return 0;
}

static int render_mid(const struct gui_button *const b,
    short *const x, const short y)
{
    const short mid_w = refs[GUI_BUTTON_MID].w,
        lw = refs[GUI_BUTTON_LEFT].w,
        rw = refs[GUI_BUTTON_RIGHT].w,
        w = b->u.type1.w - lw - rw;

    if (w > 0)
    {
        const short rem_mid = w > 0 ? w % mid_w : 0,
            whole_mid = w / mid_w,
            n_mid = rem_mid ? whole_mid + 1 : whole_mid;

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

            if (sprite_clone(&refs[GUI_BUTTON_MID], m))
                return -1;

            m->x = *x;
            m->y = y;

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

            sprite_sort(m);
            *x += m->w;
        }
    }
    else
    {
        fprintf(stderr, "%s: unexpected zero or negative size for button %p\n",
            __func__, (void *)b);
        return -1;
    }

    return 0;
}

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

    if (sprite_clone(&refs[GUI_BUTTON_RIGHT], s))
        return -1;

    s->x = x;
    s->y = y;
    sprite_sort(s);
    return 0;
}

int gui_button_render_type1(const struct gui_button *const b)
{
    short x, y;

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

    if (render_left(b, &x, y)
        || render_mid(b, &x, y)
        || render_right(b, x, y))
        return -1;

    return 0;
}

void gui_button_get_dim_type1(const struct gui_button *const b,
    short *const w, short *const h)
{
    *w = b->u.type1.w;
    *h = refs[GUI_BUTTON_MID].h;
}

void gui_button_init_type1(struct gui_button *const b)
{
    struct gui_label *const l = &b->u.type1.label;

    gui_label_init(l);
    l->common.hcentered = true;
    l->common.vcentered = true;
    gui_add_child(&b->common, &l->common);
}
