#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <ft2build.h>
#include FT_FREETYPE_H

#define array_size(a) (sizeof(a) / sizeof((a)[0]))

#define FONT "FiraMonoOT-Regular.otf"

static FT_Library freetype;
static FT_Face font_face;

static _Noreturn void
die(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    fprintf(stderr, "Error: ");
    vfprintf(stderr, fmt, args);
    va_end(args);
    fputc('\n', stderr);
    exit(1);
}

int
main(void)
{
    int err;

    err = FT_Init_FreeType(&freetype);
    if (err)
        die("Failed to initialize freetype.");

    err = FT_New_Face(freetype, FONT, 0, &font_face);
    if (err)
        die("Failed to open font.");

    err = FT_Set_Pixel_Sizes(font_face, 16, 16);
    if (err)
        die("Failed to set font size.");

    FT_ULong charcode;
    FT_UInt index;
    FT_GlyphSlot slot = font_face->glyph;

    uint16_t interval_starts[128] = {};
    uint8_t interval_sizes[128] = {};
    int num_intervals = 0;

    uint16_t charcodes[1024] = {};
    uint32_t bitmap_offsets[1024] = {};
    int num_glyphs = 0;

    uint8_t bitmap_bytes[1024 * 1024] = {};
    int num_bitmap_bytes = 0;

    charcode = FT_Get_First_Char(font_face, &index);
    while (index != 0) {
        bool choose =
            (charcode == 0) ||
            (32 <= charcode && charcode <= 126) ||
            (0x80 <= charcode && charcode <= 0xff) ||
            (0x2000 <= charcode && charcode <= 0x206f) ||
            (0x2500 <= charcode && charcode <= 0x257f) ||
            (charcode == 0x25c9);
        if (choose) {
            charcodes[num_glyphs] = charcode;
            err = FT_Load_Glyph(font_face, index, FT_LOAD_RENDER);
            if (err)
                die("Failed to load glyph.");
            bitmap_offsets[num_glyphs] = num_bitmap_bytes;
            num_glyphs++;
            bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap_top;
            bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap_left;
            bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap.rows;
            bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap.width;
            int num_pixels = slot->bitmap.rows * slot->bitmap.width;
            for (int i = 0; i < num_pixels; i++)
                bitmap_bytes[num_bitmap_bytes++] = slot->bitmap.buffer[i];
        }
        charcode = FT_Get_Next_Char(font_face, charcode, &index);
    }

    if (num_glyphs > 0) {
        interval_starts[0] = charcodes[0];
        interval_sizes[0] = 1;
        for (int i = 1; i < num_glyphs; i++) {
            if (charcodes[i - 1] + 1 != charcodes[i]) {
                num_intervals++;
                interval_starts[num_intervals] = charcodes[i];
            }
            interval_sizes[num_intervals]++;
        }
        num_intervals++;
    }

    int fds[2];
    pipe(fds);

    if (fork() == 0) {
        close(fds[1]);
        dup2(fds[0], 0);
        close(fds[0]);
        execlp("fmt", "fmt", "--prefix=    ", (char *)NULL);
    }
    close(fds[0]);
    dup2(fds[1], 1);
    close(fds[1]);

    printf("static const uint16_t interval_starts[%d] = {\n\n    ", num_intervals);
    for (int i = 0; i < num_intervals; i++) {
        printf("%u, ", (unsigned)interval_starts[i]);
    }
    printf("\n\n};\n\n");

    printf("static const uint8_t interval_sizes[%d] = {\n\n    ", num_intervals);
    for (int i = 0; i < num_intervals; i++) {
        printf("%u, ", (unsigned)interval_sizes[i]);
    }
    printf("\n\n};\n\n");

    printf("static const uint16_t bitmap_offsets[%d] = {\n\n    ", num_glyphs);
    for (int i = 0; i < num_glyphs; i++) {
        printf("%u, ", (unsigned)bitmap_offsets[i]);
    }
    printf("\n\n};\n\n");

    printf("static const uint8_t bitmap_bytes[%d] = {\n\n    ", num_bitmap_bytes);
    for (int i = 0; i < num_bitmap_bytes; i++) {
        printf("%u, ", (unsigned)bitmap_bytes[i]);
    }
    printf("\n\n};\n");
    fflush(stdout);

    close(1);
    wait(NULL);

    return 0;
}