/*-------------------------------------------------------------------------*/
/* fontfile.c --- Load font character and encoding defitions		   */
/* Copyright (c) 2001  Tim Edwards, Johns Hopkins University        	   */
/*-------------------------------------------------------------------------*/
   
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#ifdef TCL_WRAPPER 
#include <tk.h>
#else
#include "Xw/Xw.h"
#endif

/*-------------------------------------------------------------------------*/
/* Local includes                                                          */
/*-------------------------------------------------------------------------*/

#include "xcircuit.h"

/*----------------------------------------------------------------------*/
/* Function prototype declarations                                      */
/*----------------------------------------------------------------------*/
#include "prototypes.h"

/*-------------------------------------------------------------------------*/
/* Global Variable definitions						   */
/*-------------------------------------------------------------------------*/

extern char _STR2[250], _STR[150];

extern short fontcount;
extern fontinfo *fonts;

extern Globaldata xobjs;
extern short beeper;

extern float version;

#ifdef TCL_WRAPPER
extern Tcl_Interp *xcinterp;
#endif

/*----------------------------------------------------------------------*/
/* Find the file containing the encoding for the given font		*/
/*----------------------------------------------------------------------*/

FILE *findfontfile(char *fontname)
{
   int i;
   char tempname[100];
   char *tmp_s = getenv((const char *)"XCIRCUIT_LIB_DIR");
   FILE *fd;

   strcpy(_STR, fontname);

   /* change string to all lowercase and remove dashes */

   for (i = 0; i < strlen(_STR); i++) {
      _STR[i] = tolower(_STR[i]);
      if (_STR[i] == '-') _STR[i] = '_';
   }

   /* Fprintf(stdout, "Searching for font file \"%s\"\n", _STR); */

   /* pick up file to load from _STR (defined from rcfile.c and files.c) */
   /* try first in current directory, then in default library and subdir "fonts" */

   if ((fd = fopen(_STR, "r")) == NULL) {
      if (tmp_s != NULL) {
         sprintf(tempname, "%s/%s", tmp_s, _STR);
         fd = fopen(tempname, "r");
         if (fd == NULL) {
            sprintf(tempname, "%s/%s.xfe", tmp_s, _STR);
            fd = fopen(tempname, "r");
         }
         if (fd == NULL) {
            sprintf(tempname, "%s/fonts/%s", tmp_s, _STR);
            fd = fopen(tempname, "r");
         }
         if (fd == NULL) {
            sprintf(tempname, "%s/fonts/%s.xfe", tmp_s, _STR);
            fd = fopen(tempname, "r");
         }
      }

      /* last resort:  hard-coded directory BUILTINS_DIR and subdir "fonts" */

      if (fd == NULL) {
         sprintf(tempname, "%s/%s", BUILTINS_DIR, _STR);
         fd = fopen(tempname, "r");
         if (fd == NULL) {
            sprintf(tempname, "%s/%s.xfe", BUILTINS_DIR, _STR);
            fd = fopen(tempname, "r");
	 }
         if (fd == NULL) {
            sprintf(tempname, "%s/fonts/%s", BUILTINS_DIR, _STR);
            fd = fopen(tempname, "r");
	 }
         if (fd == NULL) {
            sprintf(tempname, "%s/fonts/%s.xfe", BUILTINS_DIR, _STR);
            fd = fopen(tempname, "r");
	 }
         if (fd == NULL) {
	    char *dashptr;

	    /* If this font has a suffix, remove it and look for its root */
	    /* font on the supposition that this font is derived from the */
	    /* root font.						  */

	    strncpy(tempname, fontname, 99);
	    if ((dashptr = strrchr(tempname, '-')) != NULL) {
	       *dashptr = '\0';
	       if ((fd = findfontfile(tempname)) != NULL) return fd;

	       /* And finally, because it's a common case, try adding	*/
	       /* -Roman and trying again (but don't infinite loop!)	*/

	       if (strcmp(dashptr + 1, "Roman")) {
	          strcat(dashptr, "-Roman");
	          if ((fd = findfontfile(tempname)) != NULL) return fd;
	       }
	    }

            Wprintf("No font encoding file found.");
	    if (fontcount > 0) {	/* Make font substitution */
	       char *dchr, *psname = NULL;
	       short fval;

	       if ((dchr = strrchr(_STR, '.')) != NULL) *dchr = '\0';
	       if ((fval = findhelvetica()) == fontcount) {
		  /* This will cause some chaos. . . */
		  Fprintf(stderr,
			  "Error:  No fonts available!  Check library path?\n");
		  exit(1);
	       }
	       psname = (char *)malloc((1 + strlen(fontname)) * sizeof(char));
	       strcpy(psname, fontname);
	       sprintf(_STR, "No encoding file found for font %s: substituting %s",
			psname, fonts[fval].psname);
               Wprintf(_STR);
               fonts = (fontinfo *)realloc(fonts, (fontcount + 1) * sizeof(fontinfo));
               fonts[fontcount].psname = psname;
               fonts[fontcount].family = psname;
               fonts[fontcount].encoding = fonts[fval].encoding;
               fonts[fontcount].flags = 0; 
               fonts[fontcount].scale = 1.0;
               fontcount++;
	       makenewfontbutton();
	    }
	    else {
	       Fprintf(stderr, "Error:  font encoding file missing for font \"%s\"\n",
			fontname);
	       Fprintf(stderr, "No fonts exist for a subsitution.  Make sure "
			"fonts are installed or that\nenvironment variable "
			"XCIRCUIT_LIB_DIR points to a directory of valid fonts.\n");
	    }
            return (FILE *)NULL;
         }
      }
   }
   return fd;
}

/*----------------------------------------------------------------------*/
/* Load a named font							*/
/* Return 1 if successful, 0 if font is already present, and -1 if any	*/
/* other error occurred.						*/
/*----------------------------------------------------------------------*/

int loadfontfile(char *fontname)
{
   FILE *fd;
   char temp[250], commandstr[30], tempname[100];
   char *psname = NULL, *family = NULL;
   char *cmdptr;
   int flags = 0;
   int i;
   float fontscale = 1.0;
   objectptr *j, *eptr;
   objectptr *encoding = NULL;
   float saveversion = version;

   /* check to see if font name is in list of fonts */

   for (i = 0; i < fontcount; i++) {
      if (!strcmp(fonts[i].psname, fontname)) {
	 return 0;
      }
   }
   if ((fd = findfontfile(fontname)) == NULL) return -1;

   while (fgets(temp, 249, fd) != NULL) {
      if (*temp == '\n') continue;
      sscanf(temp, "%29s", commandstr);
      for(cmdptr = commandstr; isspace(*cmdptr); cmdptr++);

      /* very liberal about comment line characters */

      if (*cmdptr == '#' || *cmdptr == '%' || *cmdptr == ';');

      else if (!strcmp(cmdptr, "name:")) {
	 sscanf(temp, "%*s %99s", tempname);

         /* If font is already in list, ignore it 			   */
	 /* This condition should be caught at the top of the routine. . . */

         for (i = 0; i < fontcount; i++) {
            if (!strcmp(fonts[i].psname, tempname)) {
	       /* Fprintf(stdout, "Font already loaded.\n"); */
	       return 0;
	    }
	 }
	 psname = (char *)malloc((1 + strlen(tempname)) * sizeof(char));
	 strcpy(psname, tempname);
      }

      else if (!strcmp(cmdptr, "file:") || !strcmp(cmdptr, "load:")) {
	 /* Fprintf(stdout, "found file identifier in xfe file\n"); */
	 sscanf(temp, "%*s %149s", _STR);

	 /* since we can be in the middle of a file load, protect the	*/
	 /* current version number for the file load.			*/

	 version = PROG_VERSION;
	 loadlibrary(FONTLIB);
	 version = saveversion;
      }

      else if (!strcmp(cmdptr, "family:")){
	 sscanf(temp, "%*s %99s", tempname);
	 family = (char *)malloc((1 + strlen(tempname)) * sizeof(char));
	 strcpy(family, tempname);
      }

      else if (!strcmp(cmdptr, "weight:")){
	 sscanf(temp, "%*s %99s", tempname);
	 tempname[0] = tolower(tempname[0]);
	 if (!strcmp(tempname, "bold"))
	    flags |= 0x01;
      }

      else if (!strcmp(cmdptr, "shape:")){
	 sscanf(temp, "%*s %99s", tempname);
	 tempname[0] = tolower(tempname[0]);
	 if (!strcmp(tempname, "italic") || !strcmp(tempname, "oblique")
		|| !strcmp(tempname, "slanted"))
	    flags |= 0x02;
      }

      else if (!strcmp(cmdptr, "scale:")){
	 sscanf(temp, "%*s %f", &fontscale);
      }

      else if (!strcmp(cmdptr, "type:")) {
	 sscanf(temp, "%*s %99s", tempname);
	 tempname[0] = tolower(tempname[0]);
	 if (!strcmp(tempname, "drawn") || !strcmp(tempname, "vectored"))
	    flags |= 0x08;
      }

      else if (!strcmp(cmdptr, "derived:")) {
	 if (encoding == NULL) {
	    Fprintf(stdout, "Font warning: \"derived\" statement must come "
			"after encoding\n");
	 }
	 else {
	    char *psname2;
	    sscanf(temp, "%*s %99s", tempname);
	    psname2 = (char *)malloc((1 + strlen(tempname)) * sizeof(char));
	    strcpy(psname2, tempname);
	    flags &= 0xffe0;		/* shares these flags with original */
	    flags |= 0x020;		/* derived font flag		    */

	    /* determine rest of flags */

	    sscanf(temp, "%*s %*s %99s", tempname);
	    tempname[0] = tolower(tempname[0]);
	    if (!strcmp(tempname, "bold"))
	       flags |= 0x1;

	    sscanf(temp, "%*s %*s %*s %99s", tempname);
	    tempname[0] = tolower(tempname[0]);
	    if (!strcmp(tempname, "italic") || !strcmp(tempname, "oblique"))
	       flags |= 0x2;

	    sscanf(temp, "%*s %*s %*s %*s %99s", tempname);
	    tempname[0] = tolower(tempname[0]);
	    if (!strcmp(tempname, "drawn") || !strcmp(tempname, "vectored"))
	       flags |= 0x08;
	    else if (!strcmp(tempname, "special"))
	       flags |= 0x10;

	    /* generate a new fontinfo entry for the derived font */

            fonts = (fontinfo *) realloc (fonts, (fontcount + 1) * sizeof(fontinfo));
            fonts[fontcount].psname = psname2;
            if (family == NULL)
               fonts[fontcount].family = psname;
            else
               fonts[fontcount].family = family;
            fonts[fontcount].encoding = encoding;  /* use original encoding */
            fonts[fontcount].flags = flags; 
	    fonts[fontcount].scale = fontscale;
            fontcount++;
	 }
      }

      else if (!strcmp(cmdptr, "encoding:")) {
	 sscanf(temp, "%*s %99s", tempname);
	 
	 if (!strcmp(tempname, "special") || !strcmp(tempname, "Special")) {
	    flags |= 0x80;
#ifdef TCL_WRAPPER
	    Tcl_Eval(xcinterp, "xcircuit::newencodingbutton special");
#else
	    makenewencodingbutton("Special", (char)1);
#endif
	 }

	 /* ISO-LatinX encodings where X=1 to 6 */

	 if (strstr(tempname, "ISO") != NULL) {
	    char estr[38];
	    for (i = 0; i < 6; i++) {
	       if (strchr(tempname, '1' + (char)i) != NULL) {
	          flags |= ((i + 2) << 7);
#ifdef TCL_WRAPPER
		  snprintf(estr, sizeof(estr),
			"xcircuit::newencodingbutton ISOLatin%d", i + 1);
		  Tcl_Eval(xcinterp, estr);
#else
		  snprintf(estr, sizeof(estr), "ISO-Latin%d", i + 1);
	          makenewencodingbutton(estr, (char)(i + 2));
#endif
		  break;
	       }
	    }
	 }

         /* Make space for the font encoding vector */

         encoding = (objectptr *)malloc(256 * sizeof(objectptr));
         eptr = encoding;

	 while (fgets(temp, 249, fd) != NULL) {
	    char *temp2 = temp;
	    while (*temp2 != '\0') {
	       if ((int)(eptr - encoding) == 256) break;
	       sscanf(temp2, "%99s", tempname);
	       *eptr = (objectptr) NULL;
	       for (j = xobjs.fontlib.library; j < xobjs.fontlib.library +
			xobjs.fontlib.number; j++) {
	          if (!strcmp(tempname, (*j)->name)) {
	             *eptr = (*j);
		     break;
	          }
	       }
	       if (j == xobjs.fontlib.library + xobjs.fontlib.number) {
	          Fprintf(stdout, "Font load warning: character \"%s\" at code ",
				tempname);
	 	  Fprintf(stdout, "position %d not found.\n", (int)(eptr - encoding));
	       }
	       eptr++;
	       while (*temp2 != ' ' && *temp2 != '\n' && *temp2 != '\0') temp2++;
	       while (*temp2 == ' ' || *temp2 == '\n') temp2++;
	    }
	    if ((int)(eptr - encoding) == 256) break;
	 }
	 if ((int)(eptr - encoding) != 256) {
	    Fprintf(stdout, "Font load warning: Only %d characters encoded.\n", 
		  (int)(eptr - encoding));
	    while (eptr < encoding + 256)
	       *eptr++ = (objectptr) NULL;
	 }

         /* If successful, register the font */

         fonts = (fontinfo *) realloc (fonts, (fontcount + 1) * sizeof(fontinfo));
         fonts[fontcount].psname = psname;
         if (family == NULL)
            fonts[fontcount].family = psname;
         else
            fonts[fontcount].family = family;
         fonts[fontcount].encoding = encoding;
         fonts[fontcount].flags = flags; 
         fonts[fontcount].scale = fontscale;
         fontcount++;

         /* Create a new menu button for the font family, if this is the first	*/
	 /* (In Tcl, this just registers the family name for cycling through	*/
	 /* via Alt-F; the menu update is done via command tag callback).	*/

	 for (i = 0; i < fontcount - 1; i++)
	    if (!strcmp(fonts[i].family, fonts[fontcount - 1].family))
	       break;
    
	 if (i == fontcount - 1)
	    makenewfontbutton();
      }
   }
   return 1;
}
