/*
 *  Generate the Mana font by stitching together
 *  several scaled images, updating the glyph widths too.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <app.h>

App *app;
int max_width;
int line_height;
int widths[256];

typedef struct {
	char ch;
	char *source;
} SymbolMap;

SymbolMap map[] = {
	{ 'T', "symbols196/T.png" },
	{ 'W', "symbols196/W.png" },
	{ 'U', "symbols196/U.png" },
	{ 'B', "symbols196/B.png" },
	{ 'R', "symbols196/R.png" },
	{ 'G', "symbols196/G.png" },
	{ 'X', "symbols196/X.png" },
	{ 'O', "symbols196/a-black-circle.gif" },
	{ 'o', "symbols196/a-grey-circle.png" },
	{ 't', "symbols196/a-tap-on-card-in-circle.png" },
	{ 'A', "symbols196/a-sideways-T-in-circle.png" },
	{ 'w', "symbols196/w.png" },
	{ 'u', "symbols196/u.png" },
	{ 'b', "symbols196/b.png" },
	{ 'r', "symbols196/r.png" },
	{ 'g', "symbols196/g.png" },
	{ '0', "symbols196/00.png" },
	{ '1', "symbols196/01.png" },
	{ '2', "symbols196/02.png" },
	{ '3', "symbols196/03.png" },
	{ '4', "symbols196/04.png" },
	{ '5', "symbols196/05.png" },
	{ '6', "symbols196/06.png" },
	{ '7', "symbols196/07.png" },
	{ '8', "symbols196/08.png" },
	{ '9', "symbols196/09.png" },
	{ '~', "symbols196/10.png" },
	{ '!', "symbols196/11.png" },
	{ '@', "symbols196/12.png" },
	{ '#', "symbols196/13.png" },
	{ '$', "symbols196/14.png" },
	{ '%', "symbols196/15.png" },
	{ '^', "symbols196/16.png" },
	{ '&', "symbols196/17.png" },
	{ '*', "symbols196/18.png" },
	{ '(', "symbols196/19.png" },
	{ ')', "symbols196/20.png" },
	{ 'Q', "symbols196/WU.png" },
	{ 'q', "symbols196/WB.png" },
	{ 'Y', "symbols196/UB.png" },
	{ 'y', "symbols196/UR.png" },
	{ 'V', "symbols196/BR.png" },
	{ 'v', "symbols196/BG.png" },
	{ 'E', "symbols196/RG.png" },
	{ 'e', "symbols196/RW.png" },
	{ 'F', "symbols196/GW.png" },
	{ 'f', "symbols196/GU.png" }
};

#define NELEM(arr) (sizeof(arr)/sizeof(arr[0]))

Image *sources[NELEM(map)];

/*
 *  This ugly parser function loads the font information file
 *  and skips through it until it finds an entry for the
 *  required subfont. It then proceeds to load just the
 *  information for that subfont.
 *
 */
int load_subfont_info(const char *info_filename, unsigned long sub_base)
{
	FILE *f;
	int i, r, ch, width, start, finish;
	char buf[10];
	unsigned long base;
	unsigned char *range_list;
	int num_ranges;

	/* load the font information file */
	f = app_open_file(info_filename, "r");
	if (! f)
		return 0;

	/* initialise the subfont glyph width array */
	for (i=0; i < 256; i++)
		widths[i] = -2;

	base = 0UL;
	while ((ch = getc(f)) != EOF)
	{
		if ((ch == '\r') || (ch == '\n') || (ch == ' '))
			continue;
		else if (ch == '\t') {
			/* font width descriptor line */
			/* do nothing yet */
		}
		else {
			/* subfont base number */
			i = 0;
			while ((ch = buf[i++] = getc(f)) != EOF) {
				if (i == sizeof(buf)-1)
					break;
				if ((ch == '\r') || (ch == '\n'))
					break;
			}
			buf[i] = '\0';
			base = strtoul(buf, NULL, 16);
			if (base > sub_base)
				break; /* gone too far */
			continue; /* keep looking for the subfont */
		}

		/* if we are here, must be a font width descriptor line */
		if (base != sub_base) {
			/* not the subfont we were looking for */
			while ((ch = getc(f)) != EOF)
				/* discard the line */
				if ((ch == '\r') || (ch == '\n'))
					break;
			continue;
		}

		/* determine the width described by this line */
		i = 0;
		while ((ch = buf[i++] = getc(f)) != EOF) {
			if (i == sizeof(buf)-1)
				break;
			if (ch == ' ')
				break;
		}
		buf[i] = '\0';
		width = strtol(buf, NULL, 10); /* decimal integer */
		start = -1;
		finish = -2;

		/* allocate range list structure */
		range_list = app_zero_alloc(256);
		r = 0;

		/* read the width ranges */
		i = 0;
		while ((ch = getc(f)) != EOF) {
			buf[i++] = ch;
			if (i == sizeof(buf)-1)
				break;
			if (ch == '-') {
				buf[i] = '\0';
				if (start >= 0) {
					range_list[r++] = start;
					range_list[r++] = start;
				}
				start = strtol(buf, NULL, 16);
				finish = start;
				i = 0;
			}
			if (ch == ',') {
				buf[i] = '\0';
				if (finish == start) {
					finish = strtol(buf, NULL, 16);
					range_list[r++] = start;
					range_list[r++] = finish;
					start = -1;
				}
				else if (start >= 0) {
					range_list[r++] = start;
					range_list[r++] = start;
					start = strtol(buf, NULL, 16);
				}
				else {
					start = strtol(buf, NULL, 16);
					finish = start - 1;
				}
				i = 0;
			}
			if ((ch == '\r') || (ch == '\n')) {
				buf[i] = '\0';
				if (finish == start) {
					finish = strtol(buf, NULL, 16);
					range_list[r++] = start;
					range_list[r++] = finish;
				}
				else if (start >= 0) {
					range_list[r++] = start;
					range_list[r++] = start;
					start = strtol(buf, NULL, 16);
					range_list[r++] = start;
					range_list[r++] = start;
				}
				else {
					start = strtol(buf, NULL, 16);
					range_list[r++] = start;
					range_list[r++] = start;
				}
				break;
			}
		}

		num_ranges = r/2;

		/* copy width to the glyph width array for fast lookup */
		if (widths) {
			for (i=0; i < 256; i++) {
				if (widths[i] != -2)
					continue;
				for (r=0; r < num_ranges*2; r+=2) {
					if ((i >= range_list[r]) &&
					    (i <= range_list[r+1]))
						widths[i] = width;
				}
			}
		}
	}
	if (widths) {
		for (i=0; i < 256; i++)
			if (widths[i] == -2)
				widths[i] = -1;
	}

	app_free(range_list);

	app_close_file(f);
	return 1;
}

int save_subfont_widths(FILE *f, int *widths, int max_width, unsigned long sub_base)
{
	int i, width, start, finish, printed;

	fprintf(f, "%08lX\n", sub_base);
	for (width=-1; width <= max_width; width++) {
		printed = 0;
		start = -1;
		finish = -2;
		for (i=0; i < 256; i++) {
			if (widths[i] == width) {
				if (! printed) {
					fprintf(f, "\t%02d ", width);
					printed = 1;
				}
				if (start < 0) {
					start = finish = i;
				}
				else {
					finish++;
				}
			}
			else if (start >= 0) {
				if (printed == 2)
					fprintf(f, ",");
				if (finish > start)
					fprintf(f, "%02X-%02X", start,
						finish);
				else
					fprintf(f, "%02X", start);
				printed = 2;
				start = -1;
			}
		}
		if (start >= 0) {
			if (printed == 2)
				fprintf(f, ",");
			if (finish > start)
				fprintf(f, "%02X-%02X", start, finish);
			else
				fprintf(f, "%02X", start);
		}
		if (printed)
			fprintf(f, "\n");
	}

	return 1;
}

/*
 *  Convert a 32-bit image into a paletted 8-bit image.
 */
Image * img_32_to_8(Image *src, int *exact)
{
	int i, x, y;
	Colour c1, c2;
	Image *dst;

	dst = app_new_image(src->width, src->height, 8);
	dst->cmap = app_alloc(sizeof(Colour) * 256);
	dst->cmap_size = 0;

	for (y = 0; y < src->height; y++)
	{
		for (x = 0; x < src->width; x++)
		{
			c1 = src->data32[y][x];

			/* Clamp the alpha to only two values. */
			if (c1.alpha > 0x7F)
				c1.alpha = c1.red = c1.green = c1.blue = 255;
			else
				c1.alpha = 0;

			/* Search for that colour in the palette. */
			for (i = 0; i < dst->cmap_size; i++)
			{
				c2 = dst->cmap[i];
				if ((c2.alpha == c1.alpha)
				 && (c2.red   == c1.red)
				 && (c2.green == c1.green)
				 && (c2.blue  == c1.blue))
				{
					/* Found in palette! */
					break;
				}
			}
			/* Was it found in the palette? */
			if (i == dst->cmap_size)
			{
				/* Not found in palette; try to add it. */
				if (i == 255)
				{
					/* Insufficient space to add. */
					/* Estimate colour cube instead. */
					app_del_image(dst);
					if (exact != NULL)
						*exact = 0;
					return app_image_convert_8_to_32(src);
				}
				dst->cmap_size++;
				dst->cmap[i] = c1;
			}
			/* Found the colour in palette. */
			dst->data8[y][x] = i;
		}
	}
	if (exact != NULL)
		*exact = 1;
	return dst;
}

/*
 *  Create a folder structure to contain the saved image.
 *  Then, save the image to a file in the appropriate folder.
 *  Also save the font information into a file too.
 */
int save_font_image(Image *img, char *font_name, int style, int height)
{
	int result;
	FILE *fm;
	char path[256];
	int exact;

	if (! img)
		return 0;
	/* img = img_32_to_8(img, &exact); */

	/* Create the folders needed. */

	sprintf(path, "fontsave/");
	app_make_folder(path, 0755);

	sprintf(path, "fontsave/%s/", font_name);
	app_make_folder(path, 0755);

	sprintf(path, "fontsave/%s/%02d%s%s%s/",
			font_name, height,
			style & BOLD ? "b" : "",
			style & ITALIC ? "i" : "",
			style & ANTI_ALIAS ? "a" : "");
	app_make_folder(path, 0755);

	/* Save the sub-font image file. */

	strcat(path, "00000000.png");
	fprintf(stderr, "Saving font image file %s\n", path);

	result = app_write_image(img, path);
	app_del_image(img);
	fprintf(stderr, "Created font image file.\n");

	/* Save the font metrics information. */

	sprintf(path, "fontsave/%s/%02d%s%s%s.txt",
			font_name, height,
			style & BOLD ? "b" : "",
			style & ITALIC ? "i" : "",
			style & ANTI_ALIAS ? "a" : "");

	fprintf(stderr, "Creating metrics file %s\n", path);
	fm = fopen(path, "w");
	if (! fm)
		return 0;
	result &= save_subfont_widths(fm, widths, max_width, 0x00000000UL);
	fclose(fm);
	fprintf(stderr, "Created metrics file.\n");

	return result;
}

void construct_font(const char *font_path, const char *font_info,
			char *font_name, int style, int pixel_size,
			int square, int ygap, int xgap)
{
	int i, x, y, ch;
	Point p;
	Colour c;
	Image *scaled;

	/* Load the font image. */
	Image *img = app_read_image(font_path, 32);
	load_subfont_info(font_info, 0UL);

	/* Now the font characteristics will be valid. */
	max_width = img->width / 32;
	line_height = img->height / 8;

	fprintf(stderr, "Font loaded. Pixel height is %d, max width is %d\n",
			line_height, max_width);

	/* ensure the subfont image has translucency */
	for (y = 0; y < img->height; y++)
	{
		for (x = 0; x < img->width; x++)
		{
			c = img->data32[y][x];
			/* is the subfont image already using alpha? */
			if (c.alpha)
				break;
			/* no, then turn greys into translucent black */
			if ((c.red == c.green) && (c.green == c.blue))
			{
				c.alpha = c.red;
				c.red = c.green = c.blue = 0;
				img->data32[y][x] = c;
			}
		}
	}

	for (i = 0; i < NELEM(map); i++) {
		sources[i] = app_read_image(map[i].source, 32);
		if (sources[i] == NULL) {
			fprintf(stderr, "Could not load %s.\n", map[i].source);
		}
	}

	for (i = 0; i < NELEM(map); i++)
	{
		ch = map[i].ch;
		p.x = (ch % 32) * max_width;
		p.y = (ch / 32) * line_height;
		for (y = p.y; y < p.y + line_height; y++)
		{
		 for (x = p.x; x < p.x + max_width; x++)
		 {
			img->data32[y][x] = CLEAR;
		 }
		}
		scaled = app_scale_image(sources[i],
				rect(0,0,square,square),
				app_get_image_area(sources[i]));
		widths[ch] = square + xgap*2;
		for (y = 0; y < scaled->height; y++)
		{
		 for (x = 0; x < scaled->width; x++)
		 {
			img->data32[p.y + y + ygap][p.x + x + xgap]
				= scaled->data32[y][x];
		 }
		}
		app_del_image(scaled);
	}

	save_font_image(img, font_name, style, line_height);
}

int main(int argc, char *argv[])
{
	app = app_new_app(argc, argv);
	construct_font("/home/loki/apps/app/fonts/Times/56a/00000000.png",
			"/home/loki/apps/app/fonts/Times/56a.txt",
			"Mana", ANTI_ALIAS, 56, 36, 11, 1);
	construct_font("/home/loki/apps/app/fonts/Times/50a/00000000.png",
			"/home/loki/apps/app/fonts/Times/50a.txt",
			"Mana", ANTI_ALIAS, 50, 32, 10, 1);
	construct_font("/home/loki/apps/app/fonts/Times/40a/00000000.png",
			"/home/loki/apps/app/fonts/Times/40a.txt",
			"Mana", ANTI_ALIAS, 40, 26, 8, 1);
	construct_font("/home/loki/apps/app/fonts/Times/39a/00000000.png",
			"/home/loki/apps/app/fonts/Times/39a.txt",
			"Mana", ANTI_ALIAS, 39, 25, 8, 1);
	construct_font("/home/loki/apps/app/fonts/Times/38a/00000000.png",
			"/home/loki/apps/app/fonts/Times/38a.txt",
			"Mana", ANTI_ALIAS, 38, 24, 8, 1);
	construct_font("/home/loki/apps/app/fonts/Times/37a/00000000.png",
			"/home/loki/apps/app/fonts/Times/37a.txt",
			"Mana", ANTI_ALIAS, 37, 24, 7, 1);
	construct_font("/home/loki/apps/app/fonts/Times/36a/00000000.png",
			"/home/loki/apps/app/fonts/Times/36a.txt",
			"Mana", ANTI_ALIAS, 36, 24, 7, 1);
	construct_font("/home/loki/apps/app/fonts/Times/35a/00000000.png",
			"/home/loki/apps/app/fonts/Times/35a.txt",
			"Mana", ANTI_ALIAS, 35, 22, 7, 1);
	construct_font("/home/loki/apps/app/fonts/Times/34a/00000000.png",
			"/home/loki/apps/app/fonts/Times/34a.txt",
			"Mana", ANTI_ALIAS, 34, 21, 7, 1);
	construct_font("/home/loki/apps/app/fonts/Times/33a/00000000.png",
			"/home/loki/apps/app/fonts/Times/33a.txt",
			"Mana", ANTI_ALIAS, 33, 21, 7, 1);
	construct_font("/home/loki/apps/app/fonts/Times/32a/00000000.png",
			"/home/loki/apps/app/fonts/Times/32a.txt",
			"Mana", ANTI_ALIAS, 32, 21, 6, 1);
	construct_font("/home/loki/apps/app/fonts/Times/31a/00000000.png",
			"/home/loki/apps/app/fonts/Times/31a.txt",
			"Mana", ANTI_ALIAS, 31, 20, 6, 1);
	construct_font("/home/loki/apps/app/fonts/Times/30a/00000000.png",
			"/home/loki/apps/app/fonts/Times/30a.txt",
			"Mana", ANTI_ALIAS, 30, 19, 6, 1);
	construct_font("/home/loki/apps/app/fonts/Times/29/00000000.png",
			"/home/loki/apps/app/fonts/Times/29.txt",
			"Mana", ANTI_ALIAS, 29, 19, 6, 1);
	construct_font("/home/loki/apps/app/fonts/Times/28/00000000.png",
			"/home/loki/apps/app/fonts/Times/28.txt",
			"Mana", ANTI_ALIAS, 28, 18, 4, 1);
	construct_font("/home/loki/apps/app/fonts/Times/27/00000000.png",
			"/home/loki/apps/app/fonts/Times/27.txt",
			"Mana", ANTI_ALIAS, 27, 18, 4, 1);
	construct_font("/home/loki/apps/app/fonts/Times/26/00000000.png",
			"/home/loki/apps/app/fonts/Times/26.txt",
			"Mana", ANTI_ALIAS, 26, 17, 4, 1);
	construct_font("/home/loki/apps/app/fonts/Times/25/00000000.png",
			"/home/loki/apps/app/fonts/Times/25.txt",
			"Mana", ANTI_ALIAS, 25, 17, 4, 1);
	construct_font("/home/loki/apps/app/fonts/Times/24/00000000.png",
			"/home/loki/apps/app/fonts/Times/24.txt",
			"Mana", ANTI_ALIAS, 24, 16, 4, 1);
	construct_font("/home/loki/apps/app/fonts/Times/23/00000000.png",
			"/home/loki/apps/app/fonts/Times/23.txt",
			"Mana", ANTI_ALIAS, 23, 17, 4, 1);
	construct_font("/home/loki/apps/app/fonts/Times/22/00000000.png",
			"/home/loki/apps/app/fonts/Times/22.txt",
			"Mana", ANTI_ALIAS, 22, 16, 3, 1);
	construct_font("/home/loki/apps/app/fonts/Times/21/00000000.png",
			"/home/loki/apps/app/fonts/Times/21.txt",
			"Mana", ANTI_ALIAS, 21, 15, 3, 1);
	construct_font("/home/loki/apps/app/fonts/Times/20/00000000.png",
			"/home/loki/apps/app/fonts/Times/20.txt",
			"Mana", ANTI_ALIAS, 20, 15, 2, 1);
	construct_font("/home/loki/apps/app/fonts/Times/19/00000000.png",
			"/home/loki/apps/app/fonts/Times/19.txt",
			"Mana", ANTI_ALIAS, 19, 13, 2, 1);
	construct_font("/home/loki/apps/app/fonts/Times/18/00000000.png",
			"/home/loki/apps/app/fonts/Times/18.txt",
			"Mana", ANTI_ALIAS, 18, 13, 3, 1);
	construct_font("/home/loki/apps/app/fonts/Times/17/00000000.png",
			"/home/loki/apps/app/fonts/Times/17.txt",
			"Mana", ANTI_ALIAS, 17, 12, 3, 1);
	construct_font("/home/loki/apps/app/fonts/Times/16/00000000.png",
			"/home/loki/apps/app/fonts/Times/16.txt",
			"Mana", ANTI_ALIAS, 16, 12, 2, 1);
	app_del_app(app);

	return 0;
}
