#include <font.h>
#include <gfx.h>
#include <stdarg.h>
#include <stdio.h>

struct sprite font_sprite;

static int renderstr(const enum font f, const short x, short y,
    const char *str, const bool render, short *const max_x,
    short *const max_y)
{
    if (!str)
    {
        if (max_x)
            *max_x = 0;

        if (max_y)
            *max_y = 0;

        return 0;
    }

    static const struct cfg
    {
        const struct sprite *s;
        short fw, fh, fs;
    } cfgs[] =
    {
        [FONT] =
        {
            .s = &font_sprite,
            .fw = 12,
            .fh = 14,
            .fs = 8
        }
    };

    const struct cfg *const cfg = &cfgs[f];
    char c;
    short rx = x;

    if (max_x)
        *max_x = rx;

    if (max_y)
        *max_y = y + cfg->fh;

    while ((c = *str++))
    {
        if (c == ' ')
        {
            rx += cfg->fs;

            if (max_x && rx >= *max_x)
                *max_x = rx;

            continue;
        }
        else if (c == '\n' || c == '\r')
        {
            rx = x;
            y += cfg->fh;

            if (max_y)
                *max_y = y;

            continue;
        }

        if (render)
        {
            sprite_get_or_ret(s, -1);

            if (sprite_clone(cfg->s, s))
                return -1;

            s->w = cfg->fw;
            s->h = cfg->fh;

            /* Substract non-printable characters (NUL to SP). */
            const char ch = c - '!';
            const short u = (cfg->fw * ch) % cfg->s->w;
            const short v = cfg->fh * ((cfg->fw * ch) / cfg->s->w);

            s->u += u;
            s->v += v;
            s->x = rx;
            s->y = y;

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

        rx += cfg->fs;

        if (max_x && rx >= *max_x)
            *max_x = rx;
    }

    return 0;
}

int font_dim(const enum font f, const char *const str, short *const x,
    short *const y)
{
    return renderstr(f, 0, 0, str, false, x, y);
}

int font_puts(const enum font f, const short x, const short y,
    const char *const str)
{
    return renderstr(f, x, y, str, true, NULL, NULL) ? EOF : 0;
}
