#include <stdio.h>
#include <assert.h>

#include "ppm.h"
#include "nstring.h"
#include "ppmdfont.h"



static void
generateHeader(struct ppmd_fontHeader const fontHeader) {

    fprintf(stdout, "  {/* .header */\n");
    fprintf(stdout, "    {'p','p','m','d','f','o','n','t'},\n");
    fprintf(stdout, "    0x%02x,\n", fontHeader.format);
    fprintf(stdout, "    %u,\n", fontHeader.characterCount);
    fprintf(stdout, "    %u\n", fontHeader.firstCodePoint);
    fprintf(stdout, "  }\n");
}



static void
generateGlyphCommand(struct ppmd_glyphCommand const glyphCommand) {

    const char * verb;

    switch (glyphCommand.verb) {
    case CMD_NOOP:     verb = "CMD_NOOP";     break;
    case CMD_DRAWLINE: verb = "CMD_DRAWLINE"; break;
    case CMD_MOVEPEN:  verb = "CMD_MOVEPEN";  break;
    }
    
    fprintf(stdout, "  {/* glyphCommand */ %s, %u, %u }\n",
            verb, glyphCommand.x, glyphCommand.y);
    
}



static void
generateCommandTable(struct ppmd_glyph const glyph,
                     const char *      const variableName) {

    unsigned int commandNum;

    fprintf(stdout, "struct ppmd_glyphCommand const %s[%u] = {\n",
            variableName, glyph.header.commandCount);

    for (commandNum = 0;
         commandNum < glyph.header.commandCount;
         ++commandNum) {

        generateGlyphCommand(glyph.commandList[commandNum]);

        if (commandNum < glyph.header.commandCount-1)
            fprintf(stdout, "  ,\n");
    }
}



static void
generateCommandTables(const struct ppmd_font * const fontP,
                      const char *             const glyphTableVariableName) {

    unsigned int relativeCodePoint;

    for (relativeCodePoint = 0;
         relativeCodePoint < fontP->header.characterCount;
         ++relativeCodePoint) {

        if (fontP->glyphTable[relativeCodePoint].header.commandCount > 0) {
            const char * commandTableVariableName;

            asprintfN(&commandTableVariableName, "%s_cmd_%u",
                      glyphTableVariableName,
                      fontP->header.firstCodePoint + relativeCodePoint);
            
            generateCommandTable(fontP->glyphTable[relativeCodePoint],
                                 commandTableVariableName);

            strfree(commandTableVariableName);

            fprintf(stdout, "};\n");
            fprintf(stdout, "\n");
        }
    }
}



static void
generateGlyph(
    struct ppmd_glyph const glyph,
    const char *      const commandTableVariableName) {

    fprintf(stdout, "  { /* glyph */\n");
    fprintf(stdout, "    { /* header */ %u, %u, %u}\n",
            glyph.header.commandCount,
            glyph.header.skipBefore,
            glyph.header.skipAfter
            );

    fprintf(stdout, "    ,\n");
    if (glyph.header.commandCount == 0)
        fprintf(stdout, "    NULL\n");
    else
        fprintf(stdout, "    %s\n", commandTableVariableName);

    fprintf(stdout, "  }\n");
}



static void
generateGlyphTable(const struct ppmd_font * const fontP,
                   const char *             const variableName) {

    unsigned int relativeCodePoint;

    generateCommandTables(fontP, variableName);

    fprintf(stdout, "struct ppmd_glyph const %s[%u] = {\n",
            variableName, fontP->header.characterCount);

    for (relativeCodePoint = 0;
         relativeCodePoint < fontP->header.characterCount;
         ++relativeCodePoint) {

        const char * commandTableVariableName;

        asprintfN(&commandTableVariableName, "%s_cmd_%u",
                  variableName,
                  fontP->header.firstCodePoint + relativeCodePoint);
        
        generateGlyph(fontP->glyphTable[relativeCodePoint],
                      commandTableVariableName);

        strfree(commandTableVariableName);

        if (relativeCodePoint < fontP->header.characterCount - 1)
            fprintf(stdout, "  ,\n");
    }
    fprintf(stdout, "};\n");
    fprintf(stdout, "\n");
}



static void
generateFont(const struct ppmd_font * const fontP,
             const char *             const fontVariableName,
             const char *             const glyphTableVariableName) {

    fprintf(stdout, "struct ppmd_font const %s = {\n", fontVariableName);
    
    generateHeader(fontP->header);

    fprintf(stdout, "  ,\n");

    fprintf(stdout, "  /* .glyphTable: */ %s\n", glyphTableVariableName);

    fprintf(stdout, "};\n");
}



int
main(int argc, char **argv) {

    const char fontVariableName[] = "ppmd_standardfont";
    const struct ppmd_font * fontP;
    const char * glyphTableVariableName;

    ppm_init(&argc, argv);

    ppmd_read_font(stdin, &fontP);

    fprintf(stdout, "/* THIS FILE WAS GENERATED BY 'ppmdcfont' from a "
            "ppmdfont file. */\n");

    fprintf(stdout, "\n");

    fprintf(stdout, "#include \"ppmdfont.h\"\n\n");

    asprintfN(&glyphTableVariableName, "%s_glyphTable", fontVariableName);

    generateGlyphTable(fontP, glyphTableVariableName);

    fprintf(stdout, "\n");
        
    generateFont(fontP, fontVariableName, glyphTableVariableName);

    strfree(glyphTableVariableName);

    ppmd_free_font(fontP);
    
    return 0;
}
