/**
 *
 * $Id: FontList.c,v 1.4 1997/04/03 19:32:27 miers Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static char rcsid[] = "$Id: FontList.c,v 1.4 1997/04/03 19:32:27 miers Exp $";

#include <LTconfig.h>
#include <XmI/XmI.h>

#include <X11/Xfuncs.h>
#include <Xm/XmP.h>
#include <Xm/XmosP.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif

#include <XmI/DebugUtil.h>

/**************************** INTERNAL FUNCTIONS **************************/
static XmFontList
__XmFontListAlloc(int numberOfEntries)
{
    XmFontList newFontList = (XmFontList)XtCalloc(numberOfEntries + 1,
						  sizeof(struct _XmFontListRec));
    return newFontList;
}

static int
__XmFontListNumEntries(XmFontList flist)
{
    int cnt;

    for (cnt = 0; flist[cnt].tag != NULL; cnt++)
	;

    return cnt;
}

static void
__XmFontListDealloc(XmFontList list)
{
    int i;

    for (i = 0; list[i].tag != NULL; i++)
	XtFree(list[i].tag);

    XtFree((char*)list);
}

/************************* LOW LEVEL FUNCTIONS **************************/
XmFontList 
_XmFontListCreateDefault(Display *d)
{
    struct _XmFontListRec defaultEntry;
    XmFontList defaultList;
    XFontStruct *fs = XLoadQueryFont(d, XmDEFAULT_FONT);

    defaultEntry.tag = XmFONTLIST_DEFAULT_TAG;
    defaultEntry.type = XmFONT_IS_FONT;
    defaultEntry.font = (XtPointer)fs;

    defaultList = XmFontListAppendEntry(NULL, &defaultEntry);

#if 0
    XdbDebug(__FILE__, NULL, "_XmFontListCreateDefault() => 0x%X\n", defaultList);
#endif

    return defaultList;
}

/************************** PUBLIC FUNCTIONS ***********************/
XmFontList 
XmFontListAppendEntry(XmFontList old,
		      XmFontListEntry entry)
{
    XmFontList newFontList;
    int i;

    if (entry == NULL)
	return old;

    if (old == NULL)
    {
	newFontList = __XmFontListAlloc(1);
	i = 0;
    }
    else
    {
	newFontList = __XmFontListAlloc(__XmFontListNumEntries(old) + 1);
	
	for (i=0; old[i].tag != NULL; i++)
	{
	    newFontList[i].tag = XtNewString(old[i].tag);
	    newFontList[i].type = old[i].type;
	    newFontList[i].font = old[i].font;
	}
	
	__XmFontListDealloc(old);
    }

    newFontList[i].tag = XtNewString(entry->tag);
    newFontList[i].type = entry->type;
    newFontList[i].font = entry->font;

#if 0
    XdbDebug(__FILE__, NULL, "XmFontListAppendEntry() => 0x%X\n", newFontList);
#endif

    return newFontList;
}

XmFontList
XmFontListCreate(XFontStruct *font, XmStringCharSet charset)
{
    /* this function is obsolete and should not be used.  Use
       XmFontListAppendEntry instead */

    XmFontList	r;
    struct _XmFontListRec entry;

    entry.tag = XtNewString(charset);
    entry.type = XmFONT_IS_FONT;
    entry.font = (XtPointer)font;

    r = XmFontListAppendEntry(NULL, &entry);

#if 0
    XdbDebug(__FILE__, NULL, "XmFontListCreate() => 0x%X\n", r);
#endif

    return r;
}

/*
 * this function is "obsolete"; however Xmt uses it.
 */
XmFontList
XmFontListAdd(XmFontList old, XFontStruct *font, XmStringCharSet charset)
{
    XmFontList newFontList;
    struct _XmFontListRec newfont;

    newfont.tag = charset;
    newfont.type = XmFONT_IS_FONT;
    newfont.font = (XtPointer)font;

    newFontList = XmFontListAppendEntry(old, &newfont);

#if 0
    XdbDebug(__FILE__, NULL, "XmFontListAppendEntry() => 0x%X\n", newFontList);
#endif

    return newFontList;
}

XmFontList 
XmFontListCopy(XmFontList fontlist)
{
    XmFontList newFontList;
    int i;

    newFontList = __XmFontListAlloc(__XmFontListNumEntries(fontlist));

    for (i=0; fontlist[i].tag != NULL; i++)
    {
	newFontList[i].tag = XtNewString(fontlist[i].tag);
	newFontList[i].type = fontlist[i].type;
	newFontList[i].font = fontlist[i].font;
    }

#if 0
    XdbDebug(__FILE__, NULL, "XmFontListCopy(0x%X) => 0x%X\n",
	fontlist, newFontList);
#endif

    return newFontList;
}

XmFontListEntry 
XmFontListEntryCreate(char *tag,
		      XmFontType type,
		      XtPointer font)
{
    XmFontListEntry entry = (XmFontListEntry)XtMalloc(sizeof(struct _XmFontListRec));
    
    entry->tag = XtNewString(tag);
    entry->type = type;
    entry->font = font;

    return entry;
}

void 
XmFontListEntryFree(XmFontListEntry *entry)
{
    XdbDebug(__FILE__, NULL, "XmFontListEntryFree(0x%x)\n", entry);

    if (entry)
    {
	XtFree((*entry)->tag);

	/* should we close the Font? */
    }
}

XtPointer
XmFontListEntryGetFont(XmFontListEntry entry,
		       XmFontType *type_return)
{
    if (entry == NULL) {
	XdbDebug(__FILE__, NULL, "XmFontListEntryGetFont(NULL)\n");
	if (type_return)
	    *type_return = XmFONT_IS_FONT;
	return NULL;
    }

    XdbDebug(__FILE__, NULL, "XmFontListEntryGetFont()\n");

    if (type_return)
	*type_return = entry->type;
    return entry->font;
}

char *
XmFontListEntryGetTag(XmFontListEntry entry)
{
    return XtNewString(entry->tag);
}

XmFontListEntry 
XmFontListEntryLoad(Display *display,
		    char *font_name,
		    XmFontType type,
		    char *tag)
{
    XmFontListEntry	entry;
    XrmValue		fromString, toFont, cvtArg[2];
    Boolean		success = False;
    char		*p;

    XdbDebug(__FILE__, NULL, "XmFontListEntryLoad(%s, tag %s)\n",
	font_name, tag);

/* Strip trailing semi-colon */
    for (p=font_name; *p; p++) ;
    while (p > font_name && *(p-1) == ';') {
		p--;
		*p = '\0';
	}

    entry = (XmFontListEntry)XtMalloc(sizeof(struct _XmFontListRec));

    fromString.addr = font_name;
    fromString.size = strlen(font_name) + 1;

    cvtArg[0].addr = (XtPointer)&display;
    cvtArg[0].size = sizeof(Display *);

    bzero((char *)entry, sizeof(struct _XmFontListRec));

    switch (type)
    {
    case XmFONT_IS_FONT:
	toFont.addr = (XtPointer)&(entry->font);
	toFont.size = sizeof(XFontStruct*);

	success = XtCallConverter(display, XtCvtStringToFontStruct, cvtArg, (Cardinal)1, &fromString, &toFont, NULL);
	break;
    case XmFONT_IS_FONTSET:
	toFont.addr = (XtPointer)&(entry->font);
	toFont.size = sizeof(XFontSet);

	/* XtCvtStringToFontSet needs 2 arguments : display and locale */
	cvtArg[1].addr = (XtPointer)&"C";	/* FIX ME */
	cvtArg[1].size = sizeof(char *);

	success = XtCallConverter(display, XtCvtStringToFontSet, cvtArg, (Cardinal)2, &fromString, &toFont, NULL);
	break;
    }

    if (!success) {
	XdbDebug(__FILE__, NULL, "XmFontListEntryLoad => NULL\n");
	return NULL;
    } else {
	entry->tag = XtNewString(tag);
	entry->type = type;

	return entry;
    }
}

void 
XmFontListFree(XmFontList list)
{
    XdbDebug(__FILE__, NULL, "XmFontListFree(0x%X)\n", list);

    __XmFontListDealloc(list);
}

void 
XmFontListFreeFontContext(XmFontContext context)
{
    XdbDebug(__FILE__, NULL, "XmFontListFreeFontContext(0x%X)\n", context);
    XtFree((char*)context);
}

Boolean 
XmFontListInitFontContext(XmFontContext *context,
			  XmFontList fontlist)
{
    if (fontlist && context)
    {
	*context = (XmFontContext)XtMalloc(sizeof(struct _XmFontListContextRec));
	(*context)->fontlist = fontlist;
	(*context)->current_entry = -1;

	return True;
    }
    else
	return False;
}

XmFontListEntry 
XmFontListNextEntry(XmFontContext context)
{
    context->current_entry++;

    if (context->current_entry < __XmFontListNumEntries(context->fontlist))
	return &context->fontlist[context->current_entry];
    else
	return NULL;
}

Boolean
XmFontListGetNextFont(XmFontContext context, XmStringCharSet *charset, XFontStruct **font)
{
    context->current_entry++;

    if (context->current_entry < __XmFontListNumEntries(context->fontlist))
    {
	if (context->fontlist[context->current_entry].type == XmFONT_IS_FONT) {
	    *font = (XFontStruct*)(context->fontlist
					[context->current_entry].font);
	    *charset = XtNewString(context->fontlist
					[context->current_entry].tag);
	}
	else
	{
	    XFontStruct **foo;
	    char **bar;

	    if (XFontsOfFontSet((XFontSet)(context->fontlist
						[context->current_entry].font),
					   &foo,
					   &bar) < 1)
		*font = NULL;
	    else
		*font = foo[0];
	    *charset = XtNewString(context->fontlist
					[context->current_entry].tag);
	}
	return True;
    }
    else
	return False;
}

XmFontList 
XmFontListRemoveEntry(XmFontList oldlist,
		      XmFontListEntry entry)
{    
    XmFontList newFontList;
    int i,j;

    newFontList = __XmFontListAlloc(__XmFontListNumEntries(oldlist)-1);

    j=0;

    for (i=0; oldlist[i].tag != NULL; i++)
    {
	if (!(!strcmp(entry->tag, oldlist[i].tag) &&
	      entry->type == oldlist[i].type &&
	      entry->font == oldlist[i].font))
	{
	    newFontList[j].tag = XtNewString(oldlist[i].tag);
	    newFontList[j].type = oldlist[i].type;
	    newFontList[j].font = oldlist[i].font;
	    
	    j++;
	}
    }

    __XmFontListDealloc(oldlist);

    return newFontList;
}
