/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#pragma once
#include "../libs.h"
#include "texture.h"
#include "primitive.h"
#include "primitives/quad.h"
#include "../util/mem.h"
#include "../util/math.h"

/** Which character (ASCII) to start the font from */
#define FONT_FIRST_CHAR 32

/** How many characters (after the first char) to generate */
#define FONT_NUM_CHARS 96

/** Width of the loaded font texture */
#define FONT_TEXTURE_WIDTH 1024

/** Height of the loaded font texture */
#define FONT_TEXTURE_HEIGHT FONT_TEXTURE_WIDTH

/** Refer to STBTT docs for OpenGL Fill Mode v d3d Fill Modes */
#define FONT_FILL_MODE 1

/** Passed to STBTT for scaling the font, essentially the font resolution */
#define FONT_TEXTURE_SIZE 64.0f

/** The global scale, just used to provide fine control of font sizes */
#define FONT_GLOBAL_SCALE 0.5f;

/** Default Font Size (on which all font scales are based) */
#define FONT_SIZE_DEFAULT 16.0f

// Chars
#define FONT_NEWLINE '\n'
#define FONT_SPACE ' '

// Heights
#define FONT_LINE_HEIGHT FONT_TEXTURE_SIZE * 0.75f
#define FONT_INITIAL_LINE FONT_LINE_HEIGHT * 0.75f
#define FONT_SPACE_SIZE FONT_TEXTURE_SIZE * 0.45f

/** Maximum number of characters a font text info can hold. */
#define FONT_TEXT_INFO_CHARS_MAX 1024

/** Maximum number of newlines that a font text info can hold. */
#define FONT_TEXT_INFO_LINES_MAX FONT_TEXT_INFO_CHARS_MAX/50

/** Representation of a font that can be used to render text */
typedef struct {
  texture_t texture;
  stbtt_bakedchar characterData[FONT_NUM_CHARS];
} font_t;

typedef struct {
  /** What (real character) index the line starts at */
  int32_t start;
  /** How many (real) characters the line is in length */
  int32_t length;
} fonttextinfoline_t;

typedef struct {
  /** How many raw chars are in the string */
  int32_t length;

  /** How many real characters (non whitespace) are in the string */
  int32_t realLength;

  /** How many lines is the string? Trailing newlines will count */
  int32_t lineCount;

  /** The real character info for each line */
  fonttextinfoline_t lines[FONT_TEXT_INFO_LINES_MAX];

  /** Dimensions of the string */
  float width, height;

  /** Array of precalculated quads */
  stbtt_aligned_quad quads[FONT_TEXT_INFO_CHARS_MAX];
} fonttextinfo_t;

/**
 * Initializes Font from raw TTF data.
 * @param font Font to initialize
 * @param data Data to intialize for.
 */
void fontInit(font_t *font, char *data);

/**
 * Clean up a previously loaded font
 * @param font Loaded font.
 */
void fontDispose(font_t *Font);

/**
 * Buffers the vertices of a font text onto a primitive. Requires some info
 * about how the font is meant to render from the text info section.
 * 
 * @param font Font to render.
 * @param primitive Primitive to render into.
 * @param info The precalculated text info.
 */
void fontTextBuffer(font_t *font, primitive_t *primitive, fonttextinfo_t *info);

/**
 * Initializes an uninitialized primitive for rendering.
 * 
 * @param font Font to render.
 * @param primitive Primitive to render into.
 * @param info Text Info to use while rendering.
 */
void fontTextInit(font_t *font, primitive_t *primitive, fonttextinfo_t *info);

/**
 * Convert a Font's Size into a Font Scale. The scale is based on the font's 
 * default size for the given texture size (Refer to FONT_SIZE_DEFAULT).
 * 
 * @param fontSize Font size to convert.
 * @return The times scale that the font size is to the textured default.
 */
float fontGetScale(float fontSize);

/**
 * Clamps text to a max width, inserting newlines where possible.
 * 
 * @param font Font to use
 * @param info Font text info to clamp into.
 * @param text Text to clamp.
 * @param maxWidth Max width (pixels) to clamp the text to, -1 for no max width.
 * @param fontSize Font Size of the text.
 */
void fontTextClamp(font_t *font, fonttextinfo_t *info, char *text,
  float maxWidth, float fontSize
);

/**
 * Returns the number of real characters on the lines specified. Useful when
 * attempting to clamp to a set of lines.
 * 
 * @param info Info to get the character counts from.
 * @param start Starting line index.
 * @param count Count of lines, this method will clamp to info's line length.
 * @returns The count of characters in those lines summed.
 */
int32_t fontGetLineCharCount(fonttextinfo_t *info, int32_t start,int32_t count);