/**
 *
 * $Id: FontList.c,v 1.14 1998/09/12 15:05:27 rwscott 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 const char rcsid[] = "$Id: FontList.c,v 1.14 1998/09/12 15:05:27 rwscott Exp $";

#include <LTconfig.h>

#include <locale.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;
    XFontStruct *fs = XLoadQueryFont(d, XmDEFAULT_FONT);

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

    return XmFontListAppendEntry(NULL, &defaultEntry);
}

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

    if (entry == NULL)
    {
	/* We can't just return "old" here, because of memory allocation
	 * rules: old can be freed by the caller; while the result of
	 * XmFontListAppendEntry should be newly allocated (and hence
	 * should be freed by the caller as well).
	 */
	return XmFontListCopy(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;

    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 = charset;	/* XmFontListAppendEntry *copies* this */
				/* so we don't need to */
    entry.type = XmFONT_IS_FONT;
    entry.font = (XtPointer)font;

    r = XmFontListAppendEntry(NULL, &entry);

    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);

    return newFontList;
}

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

    if (!fontlist)
    {
	return NULL;
    }

    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;
    }

    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)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "XmFontListEntryFree(0x%x)\n", entry));

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

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

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

    DEBUGOUT(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;

    DEBUGOUT(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';
    }

    if (*font_name == '"' && *(p-1) == '"') {
	font_name++;
	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)XtNewString(setlocale(LC_CTYPE, NULL))/*&"C"*/;	/* FIX ME */
	cvtArg[1].size = sizeof(char *);

	success = XtCallConverter(display, XtCvtStringToFontSet, cvtArg, (Cardinal)2, &fromString, &toFont, NULL);
	XtFree(cvtArg[1].addr);
	break;
    }

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

	return entry;
    }
}

void
XmFontListFree(XmFontList list)
{
    if (!list || list == (XmFontList)XmUNSPECIFIED)
    {
	return;
    }

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

    __XmFontListDealloc(list);
}

void
XmFontListFreeFontContext(XmFontContext context)
{
    DEBUGOUT(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;
}
