#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <libps/pslib.h>
#ifdef MEMORY_DEBUGGING
#include <libps/pslib-mp.h>
#endif

void errorhandler(PSDoc *p, int error, const char *str, void *data) {
	fprintf(stderr, "PSLib: %s\n", str);
}

void usage() {
	fprintf(stderr, "Usage: glyphlist <list of fontnames>\n\n");
}

/* qsort_comp_names() {{{
 *  * Function passed to qsort for comparing glyph names.
 *   */
int qsort_comp_names(const void *data1, const void *data2) {
  void **d1 = (void **) data1;
  void **d2 = (void **) data2;
  return(strcmp(*d1, *d2));
}
/* }}} */

int main(int argc, char *argv[]) {
	PSDoc *psdoc;
	int psfont, samplefont;
	float bottommargin, colwidth, rowheight, leftmargin;
	float textwidth, fontsize, fontsamplesize;
	int i, j, k, p;
	char *text;
	int listlen, pages, glc;
	char **glyphlist;

	colwidth = 30;
	rowheight = 30;
	leftmargin = 70;
	bottommargin = 270;
	fontsize = 10.0;
	fontsamplesize = 14.0;

	if(argc < 2) {
		usage();
		exit(1);
	}

	PS_boot();
#ifdef MEMORY_DEBUGGING
	PS_mp_init();
#endif

#ifdef MEMORY_DEBUGGING
	psdoc = PS_new2(errorhandler, PS_mp_malloc, PS_mp_realloc, PS_mp_free, NULL);
#else
	psdoc = PS_new();
#endif

	PS_open_file(psdoc, "glyphlist.ps");
	PS_set_info(psdoc, "Creator", __FILE__);
	PS_set_info(psdoc, "Author", "Uwe Steinmann");
	PS_set_info(psdoc, "Title", "List of glyphs");
	PS_set_info(psdoc, "Keywords", "glyph, font");
	PS_set_info(psdoc, "BoundingBox", "0 0 596 842");

	PS_set_parameter(psdoc, "SearchPath", "/usr/share/fonts/type1/gsfonts");
	PS_set_parameter(psdoc, "SearchPath", "/usr/share/fonts/type1/linux-libertine");

	psfont = PS_findfont(psdoc, "Helvetica", NULL, 1);
	for(k=1; k<argc; k++) {
		fprintf(stdout, "Creating page for %s\n", argv[k]);
		text = malloc(100);

		samplefont = PS_findfont(psdoc, argv[k], "builtin", 1);

//		PS_setfont(psdoc, psfont, 15.0);
//		sprintf(text, "Fontsample for '%s'", PS_get_parameter(psdoc, "fontname", (float) samplefont));
//		PS_show_xy(psdoc, text, leftmargin, bottommargin+20*rowheight);
//		PS_setfont(psdoc, psfont, 10.0);

		if(PS_glyph_list(psdoc, samplefont, &glyphlist, &listlen)) {
			fprintf(stderr, "Font has %d glyphs\n", listlen);
			qsort((void *)glyphlist, listlen, sizeof(char *), qsort_comp_names);
			pages = listlen / 256 + 1;

			glc = 0;
			for(p=0; p<pages; p++) {
				PS_begin_page(psdoc, 596, 842);
				for(i=0; i<=16; i++) {
					PS_moveto(psdoc, leftmargin+i*colwidth, bottommargin);
					PS_lineto(psdoc, leftmargin+i*colwidth, bottommargin+16*rowheight);
					PS_stroke(psdoc);
				}
				for(j=0; j<=16; j++) {
					PS_moveto(psdoc, leftmargin, bottommargin+j*rowheight);
					PS_lineto(psdoc, leftmargin+16*colwidth, bottommargin+j*rowheight);
					PS_stroke(psdoc);
				}

				PS_setfont(psdoc, psfont, fontsize);
				for(i=0; i<16; i++) {
					sprintf(text, "x%X", i);
					textwidth = PS_stringwidth2(psdoc, text,  -1, psfont, fontsize);
					PS_show_xy(psdoc, text, leftmargin+i*colwidth+colwidth/2-textwidth/2, bottommargin+16*rowheight+fontsize/2);
				}
				for(j=0; j<16; j++) {
					sprintf(text, "%Xx", j);
					PS_show_xy(psdoc, text, leftmargin-1.7*fontsize, bottommargin+(15-j)*rowheight+rowheight/2-fontsize/2);
				}

				/* The symbol itself */
				PS_setfont(psdoc, samplefont, fontsamplesize);
				PS_setlinewidth(psdoc, 0.2);
				for(j=0; j<16; j++) {
					for(i=0; i<16; i++) {
						if(glc+(j*16+i) < listlen) {
							textwidth = PS_glyph_width(psdoc, glyphlist[glc+(j*16+i)], 0, fontsamplesize);
							PS_set_value(psdoc, "textx", leftmargin+i*colwidth+colwidth/2-textwidth/2);
							PS_set_value(psdoc, "texty", bottommargin+(15-j)*rowheight+rowheight/2+3-fontsize/2);
							PS_glyph_show(psdoc, glyphlist[glc+(j*16+i)]);
							PS_moveto(psdoc, leftmargin+i*colwidth+colwidth/2-textwidth/2, bottommargin+(15-j)*rowheight+rowheight/2+3-fontsize/2);
							PS_lineto(psdoc, leftmargin+i*colwidth+colwidth/2+textwidth/2, bottommargin+(15-j)*rowheight+rowheight/2+3-fontsize/2);
							PS_stroke(psdoc);
						}
					}
				}

				/* The name of the symbol */
				PS_setfont(psdoc, psfont, 3);
				for(j=0; j<16; j++) {
					for(i=0; i<16; i++) {
						if(glc+(j*16+i) < listlen) {
							PS_set_value(psdoc, "textx", leftmargin+i*colwidth+2);
							PS_set_value(psdoc, "texty", bottommargin+(15-j)*rowheight+2);
							PS_show(psdoc, glyphlist[glc+(j*16+i)]);
						}
					}
				}
				PS_end_page(psdoc);
				glc += 256;
			}
			free(text);
			PS_free_glyph_list(psdoc, glyphlist, listlen);
		}
		PS_deletefont(psdoc, samplefont);
	}
	PS_deletefont(psdoc, psfont);
	PS_close(psdoc);
	PS_delete(psdoc);
#ifdef MEMORY_DEBUGGING 
	PS_mp_list_unfreed();
#endif  
	PS_shutdown();
	exit(0);
}
