#!/usr/bin/nickle

typedef struct {
	int[]	bytes;
	int	width;
	int	height;
	int	encoding;
	int	location;
} glyph_t;

typedef struct {
	glyph_t[...]	glyphs;
	int		default_char;
	int		ascent;
} font_t;

glyph_t
read_glyph(file f)
{
	glyph_t	glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 };

	while (!File::end(f)) {
		string	l = fgets(f);

		string[*] tokens = String::split(l, " ");
		if (dim(tokens) == 0)
			continue;

		switch (tokens[0]) {
		case "ENCODING":
			glyph.encoding = atoi(tokens[1]);
			break;
		case "DWIDTH":
			glyph.width = atoi(tokens[1]);
			break;
		case "BBX":
			glyph.height = atoi(tokens[2]);
			break;
		case "ENDCHAR":
			return glyph;
		case "BITMAP":
			while (!File::end(f)) {
				string l = fgets(f);
				if (l == "ENDCHAR")
					return glyph;
				glyph.bytes[dim(glyph.bytes)] = atoi(l, 16);
			}
			break;
		}
	}
	return glyph;
}

font_t read_font(file f) {
	font_t	font = { .glyphs = {}, .default_char = -1 };
	bool in_head = true;

	while (in_head && !File::end(f)) {
		string l = File::fgets(f);

		string[*] tokens = String::split(l, " ");
		switch (tokens[0]) {
		case "DEFAULT_CHAR":
			font.default_char = atoi(tokens[1]);
			break;
		case "FONT_ASCENT":
			font.ascent = atoi(tokens[1]);
			break;
		case "CHARS":
			in_head = false;
			break;
		}
	}
	while (!File::end(f)) {
		glyph_t	glyph = read_glyph(f);
		if (glyph.encoding == -1)
			break;
		font.glyphs[dim(font.glyphs)] = glyph;
	}
	return font;
}

int
flip_byte(int x)
{
	int	dest = 0;

	for (int i = 0; i < 8; i++)
		dest |= ((x >> (7 - i)) & 1) << i;
	return dest;
}

void print_font(font_t font) {
	int	width = font.glyphs[0].width;
	int	height = font.glyphs[0].height;
	int[256] pos = { -1 ... };
	int[...] bytes;

	if (false) {
	for (int i = 1; i < dim(font.glyphs); i++) {
		if (font.glyphs[i].width != width ||
		   font.glyphs[i].height != height)
		{
			File::fprintf(stderr, "font not constant size, glyph %d is %dx%d\n",
				      font.glyphs[i].encoding, font.glyphs[i].width, font.glyphs[i].height);
			exit(1);
		}
	}
	}

	if (font.default_char == -1)
		font.default_char = font.glyphs[0].encoding;

	/* build byte array */
	for (int i = 0; i < dim(font.glyphs); i++) {
		pos[font.glyphs[i].encoding] = dim(bytes);
		for (int b = 0; b < dim(font.glyphs[i].bytes); b++)
			bytes[dim(bytes)] = font.glyphs[i].bytes[b];
	}

	/* Fill in default glyph */
	for (int i = 0; i < dim(pos); i++)
		if (pos[i] == -1)
			pos[i] = pos[font.default_char];

	printf("static const uint8_t glyph_bytes[%d] = {", dim(bytes));
	for (int b = 0; b < dim(bytes); b++) {
		if ((b & 15) == 0)
			printf("\n\t");
		printf("0x%02x, ", flip_byte(bytes[b]));
	}
	printf("\n};\n\n");

	printf("static const uint16_t glyph_pos[%d] = {", dim(pos));
	for (int i = 0; i < dim(pos); i++) {
		if ((i & 7) == 0)
			printf("\n\t");
		printf("%4d, ", pos[i]);
	}
	printf("\n};\n\n");

	printf("#define GLYPH_WIDTH %d\n", width);
	printf("#define GLYPH_HEIGHT %d\n", height);
	printf("#define GLYPH_ASCENT %d\n", font.ascent);
}

twixt (file f = File::open(argv[1], "r"); File::close(f)) {
       font_t font = read_font(f);
       print_font(font);
}
