/*	ScianFontSystem.c
	Routines for font system and string utilities

	Jim Lyons
	7/26/91

	9/24/91 added support for raster fonts
	1/5/92	EMP added font counting for both types of fonts
	1/28/92	modified StrWidth and DrawString to handle tabs
	4/6/92	added PostScript drawing mode 
	9/14/92 changed DrawString to take alignment parameter
		and changed name to DrawAString
*/

#include "Scian.h"
#include "ScianStyle.h"
#include "ScianTypes.h"
#include "ScianFontSystem.h"
#include "ScianWindows.h"
#include "ScianDraw.h"
#include "ScianTextBoxes.h"

#ifdef GRAPHICS
#include "ScianPalatino18.h"
#include "ScianTitleFont.h"

#define NRASTERFONTS	4	/* NOT including system font or icon fonts */
#define SCIANTITLE	1
#define MAXFONTSUSED	10  /* max different fonts in window (for PS drawing) */

#endif

#ifndef TABWID
#define TABWID	4	/* number of 'chars' per tab stop */
#endif

/*
	The font system handles font manager routines, if available, as
	well as raster fonts. When SetupFont is called, the font name
	is first looked up using fmfindfont. If found, the font is scaled
	to size and currentFontHandle is set for use by subsequent calls 
	to DrawString, StringWidth, etc. If fmfindfont fails (or if not
	FONTS4D) currentFontHandle is set to NULL and the name is looked
	up in the raster font name table, rasterFont[]. (The size parameter
	is ignored.) If not found the system font is used.

	Note that icon fonts are not treated like text fonts, although they
	are initialized here in InitFonts.
*/

/* globals for font system */

#ifdef GRAPHICS

char *rasterFont[NRASTERFONTS + 1];	/* table of raster font name pointers */
int nFonts = 0;
char **fonts;
static int registeredFonts;
char *fontsUsed[MAXFONTSUSED];	/* list of fonts used in PostScript file */
int numFontsUsed = 0;		/* number of fonts used = next index */
char curFontName[64];		/* remember which font is set */
int curFontSize;

#ifdef FONTS4D

fmfonthandle currentFontHandle = NIL;
/*** local font cache system? ***/

#endif
#endif

char showBuf[256];	/* string buffer for PostScript show */

static void CountFonts(s)
char *s;
/*Counts the fonts*/
{
#ifdef GRAPHICS
    ++nFonts;
#endif
}

static void RegisterFont(s)
char *s;
/*Counts the fonts*/
{
#ifdef GRAPHICS
    fonts[registeredFonts] = malloc(strlen(s) + 1);
    strcpy(fonts[registeredFonts], s);
    ++registeredFonts;
#endif
}

void InitFonts(void)
{
#ifdef GRAPHICS
	int i;

	nFonts = 2;
#ifdef FONTS4D
	fminit();
	fmenumerate(CountFonts);
#endif
	fonts = (char**) malloc(sizeof(char *) * nFonts);
#ifdef FONTS4D
	/*** count and register fonts for menu (from ScianMain.c) ***/
	registeredFonts = 0;
	fmenumerate(RegisterFont);
#endif

	/*Complete font menu with System and Palatino18*/
	RegisterFont("System");
	RegisterFont("Palatino18");

	rasterFont[0] = "System"; /* default */
	for (i=1; i<NRASTERFONTS+1; ++i) rasterFont[i] = "\0";

#ifdef BIGFONTSOK
	rasterFont[TITLEFONT] = "ScianTitle";
	defrasterfont(TITLEFONT, ScianTitleFontHT, ScianTitleFontNC, ScianTitleFontchars, 
			ScianTitleFontRS, (void *) ScianTitleFontrasters);
#endif
	rasterFont[SUBTITLEFONT] = "Palatino18";
	defrasterfont(SUBTITLEFONT, palatino18HT, palatino18NC, stChars,
			palatino18RS, (void *) stRasters);
	/*** add raster fonts to menu? ***/

	numFontsUsed = 0;
	strcpy(curFontName, "System");
	curFontSize = 10;
#endif
}

void KillFonts(void)
{
#ifdef GRAPHICS
    int k;
	/*** free memory ***/
    for (k = 0; k < nFonts; ++k)
    {
	free(fonts[k]);
    }
    if (fonts)
    {
	free(fonts);
    }
#endif
}

#ifdef PROTO
Bool SetupFont(char *name, int size)
#else
Bool SetupFont(name, size)
char *name;
int size;
#endif
{
#ifdef GRAPHICS
    int i;

    if (drawingMode == DRAW_SCREEN)
    {
#ifdef FONTS4D
        currentFontHandle = fmfindfont(name);
        if (currentFontHandle)
        {
            currentFontHandle = fmscalefont(currentFontHandle, size);
            fmsetfont(currentFontHandle);
            return true;
	}
        else
        {
            currentFontHandle = NIL;
            for (i=1; i<NRASTERFONTS+1; ++i)
            {
                if (strcmp(name, rasterFont[i]) != 0) continue;
                font(i);
                return true;
            }
            font(0);
            return false;
	}
#else
        for (i=1; i<NRASTERFONTS+1; ++i)
        {
            if (strcmp(name, rasterFont[i]) != 0) continue;
            font(i);
            return true;
        }
        font(0);
        return false;
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
        /* see if same as current font and size */
        if (strcmp(name, curFontName) == 0 && size == curFontSize) return true;
	RegisterFontUsed(name);	/* add to list for PS file trailer */
        strcpy(curFontName, name); /* remember this */
	curFontSize = size;

        /* write PostScript to drawing file to set up font */
	/* size is made larger by 2 points to adjust for screen vs printer */
        fprintf(psFile, "/%s findfont %d scalefont setfont\n", name, size+2);
        return true;
    }
#endif
    return false;
}

#ifdef PROTO
void RegisterFontUsed(char *name)
#else
void RegisterFontUsed(name)
char *name;
#endif
{
#ifdef GRAPHICS
    int i;

    /* check list of fonts used */
    for (i = 0; i < numFontsUsed; ++i)
    {
        if (strcmp(name, fontsUsed[i]) == 0) return;
    }
    if (numFontsUsed >= MAXFONTSUSED)
    {
        ReportError("RegisterFontUsed","Too many fonts!");
        return;
    }
    fontsUsed[numFontsUsed] = malloc(strlen(name) + 1);
    if (fontsUsed[numFontsUsed])
    {
         strcpy(fontsUsed[numFontsUsed], name);
         ++numFontsUsed;
    }
    else OMErr();
#endif
    return;
}


#ifdef PROTO
int ChrWidth(char c)
#else
int ChrWidth(c)
char c;
#endif
{
#ifdef GRAPHICS
	if (c < ' ') return 0;
#ifdef FONTS4D
	if (currentFontHandle)
	{
		return fmgetchrwidth(currentFontHandle, c);
	}
	else
	{
		char buf[2];

		buf[0] = c;
		buf[1] = '\0';
		return strwidth(buf);
	}
#else
	{	char buf[2];

	buf[0] = c;
	buf[1] = '\0';
	return strwidth(buf);
	}
#endif
#else
	return 0;
#endif
}

#ifdef PROTO
int StrWidth(char *s)
#else
int StrWidth(s)
char *s;
#endif
/* handles tabs in string */
{
#ifdef GRAPHICS
	int nTabs=0;
	char *t=s;

	while (*t)
	{
		if (*t++ == '\t')
		{
			s = t; /* point to char following tab */
			++nTabs;   /* incr tab count */
		}
	}
	/* now return the indent plus the length of the string following last tab */
#ifdef FONTS4D
	if (currentFontHandle)
	{
		return nTabs*TABWID*ChrWidth('0') + fmgetstrwidth(currentFontHandle, s);
	}
	else
	{
		return nTabs*TABWID*ChrWidth('0') + strwidth(s);
	}
#else
	return nTabs*TABWID*ChrWidth('0') + strwidth(s);
#endif
#else
	return 0;
#endif
}

#ifdef PROTO
char *show(char *s)
#else
char *show(s)
char *s;
#endif
{
    /*
     * Process any special characters in string for PostScript show.
     */

    char *p = showBuf;
    
    while (*s)
    {
	if (*s == '(' || *s == ')' || *s == '\\') *p++ = '\\';
	*p++ = *s++;
    }
    *p = '\0';
    return showBuf;
}

#ifdef PROTO
void DrawAString(int align, long x, long y, char *s)
#else
void DrawAString(align, x, y, s)
int align;
long x, y;
char *s;
#endif
{
#ifdef GRAPHICS
    int left, right, bottom, top;
	int xx, yy, dxx, dyy;
    
    if (drawingMode == DRAW_SCREEN)
    {
    /* find starting point of string */
	switch (align)
	{
	    case RIGHTALIGN:
		    x -= StrWidth(s);
		    break;

	    case CENTERALIGN:
		    x -= StrWidth(s)/2;
		    break;

	    case LEFTALIGN:
	    default:
		    break;
    	}

    /* check to see if string starts out of window */
	GetWindowBounds(&left, &right, &bottom, &top);
	CurOffset(&xx, &yy);
	GetWindowOrigin(&dxx, &dyy);
	left -= xx - dxx;
	
    /* trim string if necessary */
	while (x < left)
	{
	    if (*s == '\0') return;
	    x += ChrWidth(*s++);
	}
	cmov2i(x, y);
    
#ifdef FONTS4D
	if (currentFontHandle)
	{
		fmprstr(s);
	}
	else
	{
		charstr(s);
	}
#else
	charstr(s);
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile && *s != '\0')
    {
    /* write PostScript to file */
	fprintf(psFile, "%f setgray\n", PSColor());
	switch (align)
	{
		case RIGHTALIGN:
			fprintf(psFile,
	"(%s) dup %d exch stringwidth pop sub %d moveto show\n", show(s), x, y);
			break;

		case CENTERALIGN:
			fprintf(psFile,
	"(%s) dup %d exch stringwidth pop 2 div sub %d moveto show\n", show(s), x, y);
			break;

		case LEFTALIGN:
		default:
        		fprintf(psFile, "%d %d moveto (%s) show\n", x, y, show(s));
			break;
	}
    }
#endif
}
