#!/usr/bin/env python3

# converts Hershey fonts into a format easier to consume by the Badger2040
# e-ink badge library - the result can be piped directly into a .hpp file.

import argparse
from pathlib import Path

parser = argparse.ArgumentParser(
    description="Converts Hershey fonts into the format used by Badger2040."
)
parser.add_argument("file", nargs="+", help="input files to convert")

options = parser.parse_args()


def convert_font(data):
    # parse hershey font data file, the file format contains one record per
    # character with the format:
    #
    #  2761  8MXP[OZPYQZQ[P]N_
    #
    # first 5 characters: represent the character id (or a dummy value
    # of 12345). if it is a character id then a separate file contains the
    # mapping information to convert that into an ascii table entry. if all of
    # the ids are 12345 then it seems that the files contain 95 entries that
    # start from ascii character 32 (space) in order
    #
    # next 3 characters: number of vertices (including special left/right
    # bounds value)
    #
    # next 2 characters: represent the "left" and "right" offsets for this
    # character, to convert you must subtract 'R' from them. this pair counts
    # as the first "vertex"
    #
    # subsequent pairs of characters: represent each vertex, as before converted
    # into numbers by subtracting 'R'. there are vertex count (-1) of these
    #
    # note! within the vertex data can be extra newline characters which must
    # be ignored.

    vertex_data = []
    char_data = {}

    auto_char_code = 0

    # we'll loop, extracting one character per iteration, until all of the
    # data is consumed
    while len(data) > 0:
        char_code = auto_char_code
        auto_char_code += 1

        # extract vertex count
        vertex_count = int(data[5:8])
        vertex_count -= 1  # remove one for the bounds data

        # extract bounds
        left = ord(data[8:9]) - ord("R")
        right = ord(data[9:10]) - ord("R")

        char_data[char_code] = {
            "width": right - left,
            "vertex_count": vertex_count,
            "first_vertex_offset": len(vertex_data),
        }

        # work out expected total length of character data
        char_data_len = 10 + (vertex_count * 2)

        # if there are any newlines within this data then remove them before we
        # move on the parse the vertices
        while data.find("\n", char_data_len) != -1:
            data = data.replace("\n", "", 1)

        for i in range(0, vertex_count):
            offset = 10 + (i * 2)
            if data[offset:offset + 2] == " R":
                # pen up for one
                x = -128
                y = -128
            else:
                x = ord(data[offset + 0:offset + 1]) - ord("R") - left
                y = ord(data[offset + 1:offset + 2]) - ord("R")

            vertex_data.append(str(x))
            vertex_data.append(str(y))

        data = data[char_data_len:]

    font_name = Path(input_filename).stem

    # create code for all of the vertices
    vertex_code = """\
    static const int8_t {font_name}_vertices[{count}] = {{
      {vertices}
    }};
  """.format(
        font_name=font_name, count=len(vertex_data), vertices=", ".join(vertex_data)
    )

    # create code for chars and font
    #
    # struct hershey_font_glyph_t {
    #   uint32_t width;        // character width
    #   uint32_t vertex_count; // number of vertices
    #   int8_t  *vertices;     // vertex data (indices: even = x, odd = y)
    # };
    chars = []
    for i in range(0, 95):
        if i in char_data:
            chars.append(
                "      {{.width={width}, .vertex_count={vertex_count}, .vertices=&{font_name}_vertices[{offset}]}}".format(
                    width=char_data[i]["width"],
                    vertex_count=char_data[i]["vertex_count"],
                    font_name=font_name,
                    offset=char_data[i]["first_vertex_offset"],
                )
            )
        else:
            chars.append("      {.width=0, .vertex_count=0, .vertices=nullptr}")

    # struct hershey_font_t {
    #   hershey_font_glyph_t chars[95];
    # };
    font_code = """\
    static const hershey_font_t {font_name} {{
      .chars = {{
  {chars}
      }}
    }};
  """.format(
        font_name=font_name, chars=",\n".join(chars)
    )

    print(vertex_code)

    print(font_code)

    return """  {{ \"{font_name}\", &{font_name} }}""".format(font_name=font_name)


# create map of font name to font structure
font_list = []
for input_filename in options.file:
    input_file = open(input_filename, mode="r")
    data = input_file.read()
    input_file.close()

    font_list.append(convert_font(data))

map_code = """\
std::map<std::string, const hershey_font_t*> fonts = {{
{font_list}
}};
""".format(
    font_list=",\n".join(font_list)
)

print(map_code)
