#include "textbox.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ERROR(...) fprintf(stderr, __VA_ARGS__)

TextBox *textBoxNew(const char *text, float x, float y, float textSize,
                    SDL_Color color, SDL_Texture *background, TTF_Font *font,
                    const Window *window) {
    TextBox *box = malloc(sizeof(TextBox));
    if (!box) {
        ERROR("error: out of memory\n");
        exit(EXIT_FAILURE);
    }
    box->text = strdup(text);
    if (!box->text) {
        ERROR("error: out of memory\n");
        free(box);
        exit(EXIT_FAILURE);
    }
    box->x = x;
    box->y = y;
    box->textColor = color;
    box->background = background;
    box->font = font;
    box->textSize = textSize;
    textBoxUpdate(box, window);
    return box;
}

void textBoxDelete(TextBox *textBox) {
    free(textBox->text);
    size_t i;
    for (i = 0; i < textBox->lineCount; ++i) {
        SDL_DestroyTexture(textBox->renderedText[i]);
    }
    free(textBox->renderedText);
    free(textBox);
}

static void getLineSizes(TextBox *textBox, int ww, int wh, int *widths,
                         int *width, int *height) {
    int yInc = textBox->textSize * wh;
    *width = 0;
    size_t i;
    for (i = 0; i < textBox->lineCount; ++i) {
        int tw, th;
        SDL_QueryTexture(textBox->renderedText[i], NULL, NULL, &tw, &th);
        int lw = ((float)tw / (float)th) * (float)yInc;
        widths[i] = lw;
        if (lw > *width) {
            *width = lw;
        }
    }
    *width += ww * TEXT_BOX_PADDING;
    *height = yInc * textBox->lineCount;
}

void textBoxDraw(TextBox *textBox, const Window *window) {
    int ww, wh;
    SDL_GetWindowSize(window->obj, &ww, &wh);
    int widths[textBox->lineCount];
    int bw, bh;
    getLineSizes(textBox, ww, wh, widths, &bw, &bh);
    SDL_Rect backArea = {textBox->x * ww, textBox->y * wh, bw, bh};
    if (textBox->background != NULL) {
        SDL_RenderCopy(window->render, textBox->background, NULL, &backArea);
    }
    int yInc = textBox->textSize * wh;
    size_t i;
    for (i = 0; i < textBox->lineCount; ++i) {
        int th;
        SDL_QueryTexture(textBox->renderedText[i], NULL, NULL, NULL, &th);
        SDL_Rect area = {backArea.x * (1.0f + TEXT_BOX_PADDING),
                         (backArea.y * (1.0f + TEXT_BOX_PADDING)) + (yInc * i),
                         widths[i] * (1.0f - (2 * TEXT_BOX_PADDING)),
                         yInc * (1.0f - (2 * TEXT_BOX_PADDING))};
        SDL_RenderCopy(window->render, textBox->renderedText[i], NULL, &area);
    }
}

static SDL_Texture *renderLine(const char *text, const TextBox *textBox,
                               const Window *window) {
    SDL_Surface *surface =
        TTF_RenderText_Blended(textBox->font, text, textBox->textColor);
    if (!surface) {
        ERROR("error: sdl2: ttf: %s\n", TTF_GetError());
        exit(EXIT_FAILURE);
    }
    SDL_Texture *texture =
        SDL_CreateTextureFromSurface(window->render, surface);
    SDL_FreeSurface(surface);
    if (!texture) {
        ERROR("error: sdl2: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }
    return texture;
}

void textBoxUpdate(TextBox *textBox, const Window *window) {
    textBox->renderedText = malloc(1);
    if (!textBox->renderedText) {
        ERROR("error: out of memory\n");
        exit(EXIT_FAILURE);
    }
    char *savePtr;
    char *line = strtok_r(textBox->text, "\n", &savePtr);
    for (textBox->lineCount = 0; line != NULL; ++textBox->lineCount) {
        textBox->renderedText =
            realloc(textBox->renderedText,
                    sizeof(SDL_Texture *) * (textBox->lineCount + 1));
        if (!textBox->renderedText) {
            ERROR("error: out of memory\n");
            exit(EXIT_FAILURE);
        }
        textBox->renderedText[textBox->lineCount] =
            renderLine(line, textBox, window);
        line = strtok_r(NULL, "\n", &savePtr);
    }
}
