#ifndef CODE_FONTGROUP_CXX
#define CODE_FONTGROUP_CXX

/*-----------------------------------------------------------------------
 * Xclasses code file
 * ($Id: fontgroup.cxx,v 1.8 2002/03/09 21:59:26 schmitzj Exp $)
 * 
 * Copyright (C) 1998 Jürgen Schmitz
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *-----------------------------------------------------------------------
 */

#include "types.h"
#include <ctype.h>
#include <stdlib.h>
#include <Xclasses/gadget.h>
#include <Xclasses/fontgroup.h>
#include "include/fontgroup_p.h"

static char *spacitems[]={"all","proportional","monospaced","charcell",NULL};
static char *slanitems[]={"Roman","Italic","Oblique",NULL};
static char *wghtitems[]={"black","bold","demibold","medium",NULL};
static char *leer[]={NULL};
static char spcs[4]={'*','p','m','c'};

static void gfunc(gadget *gg,int id)
{
	((pfontgroup*)gg->userdata)->handle(gg);
}

fontgroup::fontgroup(void) : bordergroup()
{
	while (!(p=new pfontgroup))
	{
		outOfMemory("fontgroup");
	}
	p->o=this;
	Name("fontgroup");

	Vert();
	 p->listgr.Horiz();
	  p->choicegr.Vert();
	  p->choicegr.Weight(40);
	   p->spacing.Items(spacitems);
	   p->spacing.userdata=p;
	   p->spacing.Callback(gfunc);
	  p->choicegr.Add(p->spacing);
	   p->slant.Items(slanitems);
	   p->slant.userdata=p;
	   p->slant.Callback(gfunc);
	  p->choicegr.Add(p->slant);
	   p->wght.Items(wghtitems);
	   p->wght.userdata=p;
	   p->wght.Callback(gfunc);
	  p->choicegr.Add(p->wght);
	   p->fontprev.Text(" \n \n \n \n ");
	   p->fontprev.AutoFormat();
	  p->choicegr.Add(p->fontprev);
	 p->listgr.Add(p->choicegr);
	  p->names.ShowSelected();
	  p->names.userdata=p;
	  p->names.Callback(gfunc);
	  p->names.Weight(150);
	 p->listgr.Add(p->names);
	  p->sizes.ShowSelected();
	  p->sizes.userdata=p;
	  p->sizes.Callback(gfunc);
	  p->sizes.Weight(20);
	 p->listgr.Add(p->sizes);
	Add(p->listgr);
	 p->fontname.MaxChars(sizeof(p->fontstr));
	 p->fontname.AlwaysMode();
	 p->fontname.userdata=p;
  	 p->fontname.Callback(gfunc);
  	 p->fontname.Font(FONT_FIXED);
	Add(p->fontname);
}
pfontgroup::pfontgroup() : listgr(), choicegr(), spacing(), names(), sizes(), slant(), wght(), fontname(), fontprev(), allfonts()
{
	fontlist=NULL;
	fontstr[0]=0;
	totalfonts=0;
	firstadd=0;
	spacing_sel=0;
}
fontgroup::~fontgroup(void)
{
	if (p) delete p;
}
pfontgroup::~pfontgroup()
{
}
int fontgroup::Create(void)
{
	p->start();
	if (bordergroup::Create())
	{
		Mode(gg_mode()|GM_NORMALTICK);
		return 1;
	}
	return 0;
}
void fontgroup::Free()
{
	bordergroup::Free();
	p->RemoveAll();
	p->firstadd=0;
}
int fontgroup::GActivate(XEvent *e,int why)
{
	if (why==GA_TICK)
	{
		if (p->fontlist)
		{
			for(int i=0;i<p->totalfonts/30;i++)
			{
				if (p->font_i<p->totalfonts)
				{
					p->addfont(p->fontlist[p->font_i]);
					if (++p->font_i>=p->totalfonts)
					{
						XFreeFontNames(p->fontlist);
						p->fontlist=NULL;
						p->shownames();
						p->listgr.Unblock(0);
						p->fontprev.Text("");
						if (p->fontstr[0])
							p->handle(&p->fontname);
					}
				}
			}
		}
		return 0;
	}
	else
		return bordergroup::GActivate(e,why);
}
void pfontgroup::RemoveAll(void)
{
	struct font_name *n;
	while (n=(font_name*)allfonts.RemTail())
	{
		delete n;
	}
}
void pfontgroup::addfont(char *fnt)
{ // -*-helvetica-medium-r-*-*-14-*-*-*-p-*-*-*
	char name[50]="*",wght[15],slant[4],size[5],vendor[50]="*";
	char fontname[110];
	struct font_name *n;
	int i,in;
	char *dup=strdup(fnt),*tk,*c;
	char dummy=' ';

	i=0;
	tk=c=dup;
	while (i<12 && *c)
	{
		if (*c=='-')
		{
			*c=0;
			switch (i)
			{
				case 1:
					strncpy(vendor,tk,sizeof(vendor));
					break;
				case 2:
					strncpy(name,tk,sizeof(name));
					break;
				case 3:
					strncpy(wght,tk,sizeof(wght));
					break;
				case 4:
					strncpy(slant,tk,sizeof(slant));
					break;
				case 7:
					strncpy(size,tk,sizeof(size));
					break;
				case 11:
					dummy=tk[0];
					break;
			}
			tk=c+1;
			i++;
		}
		c++;
	}
	::free(dup);
	if (atoi(size)==0) return;
	sprintf(fontname,"%s (%s)",name,vendor);
	if (!(n=(font_name*)allfonts.FindText(fontname,allfonts.head)))
	{
		if (!(n=new font_name)) return;
		strncpy(n->name,name,sizeof(n->name));
		strncpy(n->vendor,vendor,sizeof(n->vendor));
		strncpy(n->fontname,fontname,sizeof(n->fontname));
		n->wght_c=0; 	n->uwght[0]=NULL;
		n->slant_c=0;	n->uslant[0]=NULL;
		n->size_c=0;	n->start_slant=0;
		n->spc=tolower(dummy);
		n->base.text=n->fontname;
		allfonts.AddAlpha((node*)n);
	}
	if (n->wght_c<MAXWGHTS)
	{
		in=0;
		for(i=0;i<n->wght_c;i++)
		{
			if (!strcmp(n->wght[i],wght)) in=1;
		}
		if (!in)
		{
			n->uwght[n->wght_c]=n->wght[n->wght_c];
			strcpy(n->wght[n->wght_c++],wght);
			n->uwght[n->wght_c]=NULL;
		}
	}
	if (n->slant_c<MAXSLANTS)
	{
		in=0;
		for(i=0;i<n->slant_c;i++)
		{
			if (!strcmp(n->slant[i],slant)) in=1;
		}
		if (!in)
		{
			switch (toupper(slant[0]))
			{
				case 'R':
					n->uslant[n->slant_c]="Roman";
					n->start_slant=n->slant_c;
					break;
				case 'I':
					n->uslant[n->slant_c]="Italic";
					break;
				case 'O':
					n->uslant[n->slant_c]="Oblique";
					break;
			}
			strcpy(n->slant[n->slant_c++],slant);
			n->uslant[n->slant_c]=NULL;
		}
	}
	if (n->size_c<MAXSIZES)
	{
		in=0;
		for(i=0;i<n->size_c;i++)
		{
			if (!strcmp(n->size[i],size)) in=1;
		}
		if (!in)
		{
			int v=atoi(size);
			i=n->size_c-1;
			n->size_c++;
			while (i>=0 && atoi(n->size[i])>v)
			{
				strcpy(n->size[i+1],n->size[i]);
				i--;
			}
			strcpy(n->size[i+1],size);
		}
	}
}
void pfontgroup::start(void)
{
	// Fonts-liste einlesen : -*-*-*-*-*-*-*-*-*-*-c-*-*-*
	if (fontlist=XListFonts(o->display(),"-*-*-*-*-*-*-*-*-*-*-*-*-*-*",1000,&totalfonts))
	{
		font_i=0;
		listgr.Block(0);
		fontprev.Font(FONT_GADGET);
		fontprev.Text("\n\nreading fonts...");
	}
}
void pfontgroup::shownames(void)
{
	if (spacing_sel==0)
	{
		spacing.Unlock();
	}
	else if (spacing_sel==1)
	{ // prop
		spacing.Lock();
		spacing.Selected(1);
	}
	else if (spacing_sel==2)
	{ // mono
		spacing.Lock();
		spacing.Selected(2);
	}

	struct font_name *n;
	int s=spacing.Selected(),c=1;

	if (!firstadd)
	{
		names.RemoveAll();
		sizes.RemoveAll();
	}
	slant.Items(leer);
	wght.Items(leer);
	n=(font_name*)allfonts.head;
	while (n->base.next)
	{
		if (s==0 || n->spc==spcs[s] || !firstadd)
		{
			if (!firstadd)
			{
				names.AddAtEnd(n->fontname,n);
				if (s>0 && n->spc!=spcs[s])
					names.LockItem(c);
			}
			else
				names.UnlockItem(c);
		}
		else
		{
			names.LockItem(c);
		}
		c++;
		n=(font_name*)n->base.next;
	}
	if (firstadd)
	{
		if (names.Selected()>0) handle(&names); else sizes.RemoveAll();
	}
	firstadd=1;
}
void pfontgroup::genstring(void)
{ // -*-helvetica-medium-r-*-*-14-*-*-*-p-*-*-*
	struct font_name *n=NULL;
	if (names.Selected())
	{
		n=(font_name*)names.GetData(names.Selected());
	}
	fontstr[0]=0;
	sprintf(fontstr,"-%s-%s-%s-%s-*-*-%s-*-*-*-%c-*-*-*",
				(n?n->vendor:"*"),
				(n?n->name:"*"),
				(n?(n->wght[wght.Selected()]):"*"),
				(n?(n->slant[slant.Selected()]):"*"),
				(sizes.Selected()?((char*)sizes.GetData(sizes.Selected())):"*"),
				(int)spcs[spacing.Selected()]);
	fontname.Default(fontstr);
	o->MCursor(XC_watch);
	if (fontlist)
	{
		fontprev.Font(FONT_GADGET);
		fontprev.Text("\n\nreading fonts...");
	}
	else if (fontprev.Font(fontstr))
	{
		fontprev.Text("abcd ABCD 1234 äöü");
	}
	else
	{
		fontprev.Text("Font not found");
	}
	o->MCursor(-1);
}
void pfontgroup::handle(gadget *g,int m)
{
	if (g==&spacing)
	{
		shownames();
		if (!m) genstring();
	}
	else if (g==&names)
	{
		slant.Items(((font_name*)names.GetData(names.Selected()))->uslant);
		wght.Items(((font_name*)names.GetData(names.Selected()))->uwght);
		slant.Selected(((font_name*)names.GetData(names.Selected()))->start_slant);
		sizes.RemoveAll();
		for(int i=0;i<((font_name*)names.GetData(names.Selected()))->size_c;i++)
		{
			sizes.AddAtEnd(((font_name*)names.GetData(names.Selected()))->size[i],((font_name*)names.GetData(names.Selected()))->size[i]);
		}
		if (!m) genstring();
	}
	else if (g==&sizes)
	{
		if (!m) genstring();
	}
	else if (g==&slant)
	{
		if (!m) genstring();
	}
	else if (g==&wght)
	{
		if (!m) genstring();
	}
	else if (g==&fontname)
	{
		o->MCursor(XC_watch);
		fontname.Input(fontstr);
		if (fontlist)
		{
			fontprev.Font(FONT_GADGET);
			fontprev.Text("\n\nreading fonts...");
		}
		else if (fontprev.Font(fontstr))
		{
			fontprev.Text("abcd ABCD 1234 äöü");
		}
		else
		{
			fontprev.Text("Font not found");
		}
		o->MCursor(-1);

		 // -*-helvetica-medium-r-*-*-14-*-*-*-p-*-*-*
		{
			char name[50]="*",_wght[15],_slant[4],_size[5],vendor[50]="*";
			char fontname[110];
			struct font_name *n;
			int i;
			char *dup=strdup(fontstr),*tk,*c;
			char dummy=' ';

			i=0;
			tk=c=dup;
			while (i<12 && *c)
			{
				if (*c=='-')
				{
					*c=0;
					switch (i)
					{
						case 1:
							strncpy(vendor,tk,sizeof(vendor));
							break;
						case 2:
							strncpy(name,tk,sizeof(name));
							break;
						case 3:
							strncpy(_wght,tk,sizeof(_wght));
							break;
						case 4:
							strncpy(_slant,tk,sizeof(_slant));
							break;
						case 7:
							strncpy(_size,tk,sizeof(_size));
							break;
						case 11:
							dummy=tk[0];
							break;
					}
					tk=c+1;
					i++;
				}
				c++;
			}
			::free(dup);
			if (atoi(_size)>0)
			{
				sprintf(fontname,"%s (%s)",name,vendor);
				if (n=(font_name*)allfonts.FindText(fontname,allfonts.head))
				{
					if (!spacing_sel) spacing.Selected(0);

					names.Selected(allfonts.Find((node*)n));
					handle(&names,1);

					for(i=0;i<n->size_c;i++)
					{
						if (atoi(n->size[i])==atoi(_size))
						{
							sizes.Selected(i+1);
							break;
						}
					}
					for(i=0;i<n->slant_c;i++)
					{
						if (!strcasecmp(_slant,n->slant[i]))
						{
							slant.Selected(i);
							break;
						}
					}
					for(i=0;i<n->wght_c;i++)
					{
						if (!strcasecmp(_wght,n->wght[i]))
						{
							wght.Selected(i);
							break;
						}
					}
				}
			}
		}
	}
}
char *fontgroup::GetFont(void)
{
	return p->fontstr;
}
void fontgroup::SetFont(char *n)
{
	p->fontname.Default(n);
	p->handle(&p->fontname);
}

void fontgroup::Spacing_Fixed(void)
{
	p->spacing_sel=2;
	if (win && !p->fontlist) p->handle(&p->spacing);
}
void fontgroup::Spacing_Proportional(void)
{
	p->spacing_sel=1;
	if (win && !p->fontlist) p->handle(&p->spacing);
}
void fontgroup::Spacing_All(void)
{
	p->spacing_sel=0;
	if (win && !p->fontlist) p->handle(&p->spacing);
}

#endif
