/* $Header: /afs/athena.mit.edu/astaff/project/atdev/src/text/RCS/FontFamily.c,v 3.2 91/10/09 10:29:52 dot Exp $ */

/*******************************************************************
  Copyright (C) 1990 by the Massachusetts Institute of Technology

   Export of this software from the United States of America is assumed
   to require a specific license from the United States Government.
   It is the responsibility of any person or organization contemplating
   export to obtain such a license before exporting.

WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
distribute this software and its documentation for any purpose and
without fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation, and that
the name of M.I.T. not be used in advertising or publicity pertaining
to distribution of the software without specific, written prior
permission.  M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is" without express
or implied warranty.

***************************************************************** */

#include <stdio.h>

#ifdef _AtDevelopment_
#include "FontFamilyP.h"
#else
#include <At/FontFamilyP.h>
#endif

#define AtFontNUMFACES 4
#define AtFontNUMSIZES 6
static XFontStruct *DefaultFont = NULL;
static AtFontFamily *familycache = NULL;
#define HAS_BOLD 1
#define HAS_ITALIC 2

#define New(type) (type *)malloc(sizeof(type))
#define CopyString(s) strcpy(malloc(strlen(s)+1),s)

AtFontFamilyInfo _AtFontFamilies[] = {
{"courier",
 {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"},
 HAS_BOLD | HAS_ITALIC, 'o', NULL},

{"helvetica",
 {"Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique"},
  HAS_BOLD | HAS_ITALIC, 'o', NULL},
    
{"times",
 {"Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic"},
 HAS_BOLD | HAS_ITALIC, 'i', NULL},

{"new century schoolbook",
 {"NewCenturySchlbk-Roman", "NewCenturySchlbk-Bold",
      "NewCenturySchlbk-Italic", "NewCenturySchlbk-BoldItalic",},
 HAS_BOLD | HAS_ITALIC, 'i', NULL},

{"symbol",
 {"Symbol", "Symbol", "Symbol", "Symbol"},
     0, '*', NULL},
};


static short pointsize[] = {8,10,12,14,18,24};

int AtFontPointSize(family, size)
AtFontFamily *family;
int size;
/* ARGSUSED */
{
    return pointsize[size];
}

int AtFontPixelSize(family,size)
AtFontFamily *family;
int size;
/* ARGSUSED */
{
    return pointsize[size];   /* this is a hack for now... */
}

char *AtFontFamilyGetName(family)
AtFontFamily *family;
{
    return XNAME(family);
}


AtFontFamily *AtFontFamilyGet(dpy, name)
Display *dpy;
char *name;
{
    AtFontFamily *family;
    char buf[200];
    int num;

    if (DefaultFont==NULL) DefaultFont = XLoadQueryFont(dpy,"fixed");

    if (strcasecmp(name,"new century schoolbook") == 0) 
	num = AtFontSCHOOLBOOK;
    else if (strcasecmp(name,"schoolbook") == 0)
	num = AtFontSCHOOLBOOK;
    else if (strcasecmp(name,"times") == 0)
	num = AtFontTIMES;
    else if (strcasecmp(name,"helvetica") == 0)
	num = AtFontHELVETICA;
    else if (strcasecmp(name,"courier") == 0) 
	num = AtFontCOURIER;
    else if (strcasecmp(name,"symbol") ==0)
	num = AtFontSYMBOL;
    else 
	num = -1;

    /* go look through the family cache to see if its already been created */
    family = familycache;
    while (family != NULL)  {
	if ((family->dpy == dpy) && (family->num == num)) break;
	family = family->next;
    }

    if (family != NULL) {
	family->refcount++;
    }
    else {
	family = New(AtFontFamily);
	family->dpy = dpy;
	family->refcount = 1;
	family->num = num;
	if (num == -1) {
	    family->cache = NULL;
	    sprintf(buf, "Warning: no font family '%s'.\n", name);
	    fprintf(stderr, buf);
	}
	else
	    family->cache = (XFontStruct **)
		calloc(AtFontNUMFACES * AtFontNUMSIZES,sizeof(XFontStruct *));
	family->next = familycache;
	familycache = family;
    }
    return family;
}

void AtFontFamilyRelease(family)
AtFontFamily *family;
{
    AtFontFamily *f,*g;

    family->refcount--;
    
    /* only really destroy the font family if noone is using it anymore */
    
    if (family->refcount == 0) {
	/* unlink it from the cache linked list */
	if (family == familycache) 
	    familycache = familycache->next;
	else {
	    g = familycache;
	    f = familycache->next;
	    while (f != family) {
		g = f;
		f = f->next;
	    }
	    g->next = f->next;
	}

	/* now free up the internals */
	if (family->cache) {
	    int i;
	    for (i=0; i < AtFontNUMSIZES*AtFontNUMFACES; i++) 
		if (family->cache[i]) XFreeFont(family->dpy,family->cache[i]);
	    free(family->cache);
	}
	/* now free the font family struct itself */
	free(family);
    }
}
	

XFontStruct *AtFontFetch(family, face, size)
AtFontFamily *family;
int face,size;
{
    char namebuf[150];
    char *weight, slant;
    int points;

    if (family->cache == NULL) return DefaultFont;

    if ((face & AtFontBOLD) && !(FLAGS(family) & HAS_BOLD))
	face &= ~AtFontBOLD;
    if ((face & AtFontITALIC) && !(FLAGS(family) & HAS_ITALIC))
	face &= ~AtFontITALIC;
    if (family->cache[face + size * AtFontNUMFACES] == NULL) {
	if (face & AtFontBOLD) weight = "bold";
	else weight = "medium";
	if (face & AtFontITALIC) slant = SLANTCHAR(family);
	else slant = 'r';
	points = AtFontPointSize(family, size);
	sprintf(namebuf,"*-%s-%s-%c-*-*-*-%d-*",
		XNAME(family),weight,slant,points*10);

	family->cache[face+size*AtFontNUMFACES] =
	    XLoadQueryFont(family->dpy,namebuf);

	if (family->cache[face+size*AtFontNUMFACES] == NULL)
	    family->cache[face+size*AtFontNUMFACES] = (XFontStruct *)-1;
    }

    if (family->cache[face + size * AtFontNUMFACES] == (XFontStruct *)-1)
	return DefaultFont;
    else
	return family->cache[face + size*AtFontNUMFACES];
}
		
	
int AtFontStringToSize (str)
     char *str;
{
    int points;
    char buf[200];
    
    if (!strcasecmp (str, "smallest")) 
	return AtFontSMALLEST;
    else if (!strcasecmp (str, "small")) 
	return AtFontSMALL;
    else if (!strcasecmp (str, "medium")) 
	return AtFontMEDIUM;
    else if (!strcasecmp (str, "normal")) 
	return AtFontNORMAL;
    else if (!strcasecmp (str, "big")) 
	return AtFontBIG;
    else if (!strcasecmp (str, "biggest")) 
	return AtFontBIGGEST;
    
    /* else if string is an integer, convert to the font size
       which is closest to that number of points */

    else if (((points = atoi(str)) > 0) && (points < 30))
	switch (points) {
	case 1:	case 2:	case 3:	case 4:
	case 5:	case 6:	case 7:	case 8:
	    return AtFontSMALLEST;
	case 9:	case 10:
	    return AtFontSMALL;
	case 11: case 12:
	    return AtFontMEDIUM;
	case 13: case 14: case 15:
	    return AtFontNORMAL;
	case 16: case 17: case 18:
	case 19: case 20: case 21:
	    return AtFontBIG;
	case 22: case 23: case 24: case 25:
	case 26: case 27: case 28: case 29:
	    return AtFontBIGGEST;
	}
    else {
	sprintf(buf,
	      "AtFontStringToSize: cannot convert string '%s' to font size.\n",
		str);
	fprintf(stderr,buf);
	return AtFontNORMAL;
    }
}
