/**
 * @file textbox.c
 * @brief The dialogue panel: two rectangles and a string, drawn over the world.
 *
 * Text in libakgl is immediate mode. Every akgl_text_rendertextat call
 * rasterizes the string through SDL_ttf, uploads it as a texture, blits it and
 * destroys the texture again -- there is no cached glyph atlas and no text
 * object to hold on to. That is the wrong shape for a page of static prose
 * redrawn sixty times a second and exactly the right shape for this: one short
 * line, on screen only while somebody is talking.
 */

#include <stdbool.h>

#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <akerror.h>
#include <akstdlib.h>

#include <akgl/draw.h>
#include <akgl/error.h>
#include <akgl/game.h>
#include <akgl/registry.h>
#include <akgl/text.h>

#include "jrpg.h"

/*
 *  Colour                                  R     G     B     A
 */
static const SDL_Color TEXTBOX_FILL = {    24,   20,   37,  235 };
static const SDL_Color TEXTBOX_EDGE = {   240,  236,  214,  255 };
static const SDL_Color TEXTBOX_INK  = {   240,  236,  214,  255 };

/** @brief Pixels between the panel and the edges of the screen. */
#define TEXTBOX_MARGIN  8.0f
/** @brief Panel height in pixels. Two lines of 12pt monospace, plus padding. */
#define TEXTBOX_HEIGHT  56.0f
/** @brief Pixels between the panel's edge and the text inside it. */
#define TEXTBOX_PADDING 8.0f

static char textbox_text[JRPG_TEXTBOX_MAX_TEXT];
static bool textbox_visible = false;

bool jrpg_textbox_showing(void)
{
    return textbox_visible;
}

void jrpg_textbox_close(void)
{
    textbox_visible = false;
}

akerr_ErrorContext *jrpg_textbox_open(char *text)
{
    PREPARE_ERROR(errctx);

    FAIL_ZERO_RETURN(errctx, text, AKERR_NULLPOINTER, "text");
    // aksl_strncpy, not strncpy: this is a fixed-width field, and strncpy at
    // exactly the field width leaves it unterminated. Bounded at one less than
    // the field so an over-long line truncates rather than being refused.
    PASS(errctx,
	 aksl_strncpy(
	     textbox_text,
	     sizeof(textbox_text),
	     text,
	     sizeof(textbox_text) - 1
	     ));
    textbox_visible = true;
    SUCCEED_RETURN(errctx);
}

akerr_ErrorContext *jrpg_textbox_draw(void)
{
    PREPARE_ERROR(errctx);
    TTF_Font *font = NULL;
    SDL_FRect panel;

    if ( textbox_visible == false ) {
	SUCCEED_RETURN(errctx);
    }
    // akgl_text_rendertextat refuses the empty string -- SDL_ttf reports "Text
    // has zero width" and the library passes that on as AKERR_NULLPOINTER,
    // while akgl_text_measure accepts it. The two disagree, so anything drawing
    // a line that might be empty checks for it. TODO.md, "Found while
    // rewriting the Doxygen comments".
    if ( textbox_text[0] == '\0' ) {
	SUCCEED_RETURN(errctx);
    }

    // Fonts live in a registry under a name, not in an akgl type. There is no
    // handle to keep, and no reference counting either: whoever calls
    // akgl_text_unloadfont invalidates every pointer anybody else fetched.
    // Fetching it per frame is the cheap way to stay honest about that.
    font = SDL_GetPointerProperty(AKGL_REGISTRY_FONT, JRPG_FONT_NAME, NULL);
    FAIL_ZERO_RETURN(
	errctx,
	font,
	AKGL_ERR_REGISTRY,
	"No font registered as \"%s\"",
	JRPG_FONT_NAME
	);

    // Screen coordinates, from the camera's size rather than from a second copy
    // of the window dimensions. akgl_render_2d_init put them there.
    panel.x = TEXTBOX_MARGIN;
    panel.w = akgl_camera->w - (2.0f * TEXTBOX_MARGIN);
    panel.h = TEXTBOX_HEIGHT;
    panel.y = akgl_camera->h - TEXTBOX_MARGIN - panel.h;

    PASS(errctx, akgl_draw_filled_rect(akgl_renderer, &panel, TEXTBOX_FILL));
    PASS(errctx, akgl_draw_rect(akgl_renderer, &panel, TEXTBOX_EDGE));
    PASS(errctx,
	 akgl_text_rendertextat(
	     font,
	     textbox_text,
	     TEXTBOX_INK,
	     (int)(panel.w - (2.0f * TEXTBOX_PADDING)),
	     (int)(panel.x + TEXTBOX_PADDING),
	     (int)(panel.y + TEXTBOX_PADDING)
	     ));

    SUCCEED_RETURN(errctx);
}
