#include <stdio.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

#include "_font.h"
#include "_types.h"

/* Enables or disables debug output */
#ifdef __DEBUG
#define __D(fmt, args...) fprintf(stderr, "Font Debug: " fmt, ## args)
#else
#define __D(fmt, args...)
#endif

#define __E(fmt, args...) fprintf(stderr, "Font Error: " fmt, ## args)

static FT_Library   library;
static FT_Face      face;

static FT_Encoding  encoding = FT_ENCODING_UNICODE;

static __u8 _8to5bit[256];
static __u8 _8to6bit[256];

int font_string_size(char *text, int font_height, int *string_width,
                     int *string_height)
{
    FT_Error error;
    int index;
    int width = 0;
    int height = 0;
    FT_Vector pen;

    FT_Set_Char_Size(face,
                     font_height << 6,
                     font_height << 6,
                     100,
                     100);

    pen.x = 0;
    pen.y = 0;

    while (*text) {
        FT_Set_Transform(face, NULL, &pen);

        index = FT_Get_Char_Index(face, *text);

        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }

        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        width += face->glyph->bitmap.width + 1;
        if (face->glyph->bitmap.rows > height) {
            height = face->glyph->bitmap.rows;
        }

        pen.x += face->glyph->advance.x;
        pen.y += face->glyph->advance.y;
        text++;
    }

    *string_width = width;
    *string_height = height;

    return SIMPLEWIDGET_SUCCESS;
}

int font_init(char *filename)
{
    FT_Error error;
    int i;
    static int initialized = 0;

    if (initialized)
        return SIMPLEWIDGET_SUCCESS;

    initialized = 1;

    error = FT_Init_FreeType(&library);

    if (error) {
        __E("Failed to intialize freetype library\n");
        return SIMPLEWIDGET_FAILURE;
    }

    error = FT_New_Face(library, filename, 0, &face);

    if (error) {
        __E("Failed to load font %s\n", filename);
        return SIMPLEWIDGET_FAILURE;
    }

    error = FT_Select_Charmap(face, encoding);
    if (error) {
        __E("Invalid charmap [%d]\n", encoding);
        return SIMPLEWIDGET_FAILURE;
    }

    /* Initialize the conversion arrays */
    for (i=0; i<256; i++)
        _8to5bit[i] = i * (1 << 5) / (1 << 8);

    for (i=0; i<256; i++)
        _8to6bit[i] = i * (1 << 6) / (1 << 8);

    return SIMPLEWIDGET_SUCCESS;
}

int font_render(char *text, int x, int y, int fade, int font_height,
                _simplescreen *scrp)
{
    FT_Error error;
    int index;
    int width, height;
    int i, j, p, q, x_max, y_max, sp, dp;
    __u16 *dst;
    __u8 *src;
    FT_Vector pen;
    __u8 pixel;

    FT_Set_Char_Size(face,
                     font_height << 6,
                     font_height << 6,
                     100,
                     100);

    pen.x = x << 6;
    pen.y = (scrp->h - y) << 6;

    dst = scrp->bufp;

    while (*text) {
        FT_Set_Transform(face, NULL, &pen);

        index = FT_Get_Char_Index(face, *text);

        error = FT_Load_Glyph(face, index, 0);
        if (error) {
            __E("Failed to load glyph for character %c\n", *text);
            break;
        }

        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
            if (error) {
                __E("Failed to render glyph for character %c\n", *text);
                break;
            }
        }

        width = face->glyph->bitmap.width;
        height = face->glyph->bitmap.rows;

        x = face->glyph->bitmap_left;
        y = scrp->h - face->glyph->bitmap_top;

        x_max = x + width;
        y_max = y + height;

        src = face->glyph->bitmap.buffer;

        for (i = x, p = 0; i < x_max; i++, p++) {
            for (j = y, q = 0; j < y_max; j++, q++) {

                if (i >= scrp->w || j >= scrp->h)
                    continue;

                sp = q * width + p;
                dp = j * scrp->w + i;

                pixel = src[sp] * fade / 255;

                dst[dp] |= _8to5bit[pixel] | _8to6bit[pixel] << 5 |
                           _8to5bit[pixel] << 11;
            }
        }
        text++;

        pen.x += face->glyph->advance.x;
        pen.y += face->glyph->advance.y;

    }

    return SIMPLEWIDGET_SUCCESS;
}
