/* This file is part of
 * ======================================================
 * 
 *           LyX, the High Level Word Processor
 * 	 
 *	    Copyright (C) 1995 Matthias Ettrich
 *
 *======================================================*/

/* Change log:
 * 
 *  14/11/1995,   Pascal Andreé <andre@via.ecp.fr>
 *  Modified for external style definition. 
 * 
 *  15/11/1995,   Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
 *  Modified to use binary search and a small pseudo lexical analizer.
 *  
 *  29/03/1996,  Dirk Niggeman
 *  Created classes LyXTextClass & LyXLayout.
 * 
 *  30/03/1996,  asierra
 *  Created class LyxLex and improved the lexical analizer. 
 */

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if defined(sgi) && !defined(__GNUC__)
#include <bstring.h>
#include <strings.h>
#endif

#include "definitions.h"
#include "layout.h"
#include "paths.h"
#include "lyxlex.h"

extern void WriteAlert(const char* s1, const char* s2, const char* s3);

/* global variables : textclass tab and number */
LyXTextClassList lyxstyle;

//  The order of the LayoutTags enum is no more important. [asierra300396]

/* tags indexes */
enum _LayoutTags {
        // Font sizes     
        LT_TINY=1, LT_SMALL, LT_NORMAL, LT_LARGE, LT_LARGER, LT_LARGEST, 
        LT_GIANT, LT_HUGE,
	
     	LT_ALIGN, LT_ALIGNPOSSIBLE, LT_BAR, LT_BASELINE, LT_BLOCK, LT_BOLD, 
	LT_MARGIN, LT_BOTTOMSEP, LT_CENTER, LT_CENTERED_TOP_ENVIRONMENT, LT_COLUMNS, LT_COMMAND, 
	LT_COUNTER_CHAPTER, LT_COUNTER_ENUMI, LT_COUNTER_ENUMII, 
	LT_COUNTER_ENUMIII, LT_COUNTER_ENUMIV, LT_COUNTER_PARAGRAPH, 
	LT_COUNTER_SECTION, LT_COUNTER_SUBPARAGRAPH, LT_COUNTER_SUBSECTION, 
	LT_COUNTER_SUBSUBSECTION, 
	LT_DEFAULTFAMILY, LT_DEFAULTSERIES, LT_DEFAULTSHAPE, LT_DEFAULTSIZE,
	LT_DYNAMIC, LT_EMPTY, LT_END, LT_ENDFONT, 
	LT_ENVIRONMENT, LT_ENVIRONMENT_DEFAULT, LT_FAMILY, LT_FANCYHDR, LT_FILL_BOTTOM, LT_FILL_TOP, 
	LT_FIRST_COUNTER, LT_FIRST_DYNAMIC, LT_FONT, LT_FORMULA, 
	LT_FORMULA_LATEX, LT_FREE_SPACING, LT_HEADINGS, LT_ITALIC,
	LT_ITEM_ENVIRONMENT, LT_ITEMSEP, LT_LABEL_BOTTOMSEP, LT_LABELFONT, LT_LABELINDENT, 
	LT_LABELSEP, LT_LABELSTRING, LT_LABELTYPE,
	LT_LATEX, LT_LATEXCLASS, LT_LATEXNAME, LT_LATEXTYPE, LT_LAYOUT, 
	LT_LEFT, LT_LEFTMARGIN, LT_LIST_ENVIRONMENT , LT_MANUAL, 
	LT_MAXCOUNTER, LT_MEDIUM, LT_MODERN, LT_NEWLINE, LT_NEXTNOINDENT, 
	LT_NO_BAR, LT_NO_LABEL, LT_NO_LATEX, LT_OPTIONS, LT_PAGESTYLE, 
	LT_PARAGRAPH, LT_PARINDENT, LT_PARSEP, LT_PARSKIP, LT_PLAIN, 
	LT_PROTECTED, LT_RIGHT, LT_RIGHT_ADDRESS_BOX, LT_RIGHTMARGIN, 
	LT_ROMAN, LT_SANS, LT_SENSITIVE, LT_SERIES, LT_SHAPE, LT_SIDES, 
	LT_SIZE, LT_SMALLCAPS, LT_STATIC, LT_STYLE, 
	LT_TOP_ENVIRONMENT, LT_TOPSEP, LT_TYPEWRITER, LT_UP, 
	LT_UNDERBAR,
	LT_LAST
};


// This table is sorted alphabetically [asierra 30March96]
static keyword_item layoutTags[LT_LAST-1] = {
	{ "align",                 LT_ALIGN },
	{ "alignpossible",         LT_ALIGNPOSSIBLE },
	{ "bar",                   LT_BAR },
	{ "baselinestretch",       LT_BASELINE },
	{ "block",                 LT_BLOCK },
	{ "bold",                  LT_BOLD },
	{ "bottomsep",             LT_BOTTOMSEP },
	{ "center",                LT_CENTER },
	{ "centered_top_environment",      LT_CENTERED_TOP_ENVIRONMENT },
	{ "columns",               LT_COLUMNS },
	{ "command",               LT_COMMAND },
	{ "counter_chapter",       LT_COUNTER_CHAPTER },
	{ "counter_enumi",         LT_COUNTER_ENUMI },
	{ "counter_enumii",        LT_COUNTER_ENUMII },
	{ "counter_enumiii",       LT_COUNTER_ENUMIII },
	{ "counter_enumiv",        LT_COUNTER_ENUMIV },
	{ "counter_paragraph",     LT_COUNTER_PARAGRAPH },
	{ "counter_section",       LT_COUNTER_SECTION },
	{ "counter_subparagraph",  LT_COUNTER_SUBPARAGRAPH },
	{ "counter_subsection",    LT_COUNTER_SUBSECTION },
	{ "counter_subsubsection", LT_COUNTER_SUBSUBSECTION },
	{ "defaultfamily",               LT_DEFAULTFAMILY },
	{ "defaultseries",               LT_DEFAULTSERIES },
	{ "defaultshape",               LT_DEFAULTSHAPE },
	{ "defaultsize",               LT_DEFAULTSIZE },
	{ "dynamic",               LT_DYNAMIC },
	{ "empty",                 LT_EMPTY },
	{ "end",                   LT_END },
	{ "endfont",               LT_ENDFONT },
	{ "environment",          LT_ENVIRONMENT },
	{ "environment_default",          LT_ENVIRONMENT_DEFAULT },
	{ "family",                LT_FAMILY },
	{ "fancyhdr",              LT_FANCYHDR },
	{ "fill_bottom",           LT_FILL_BOTTOM },
	{ "fill_top",              LT_FILL_TOP },
	{ "first_counter",         LT_FIRST_COUNTER },
	{ "first_dynamic",         LT_FIRST_DYNAMIC },
	{ "font",                  LT_FONT },
	{ "formula",               LT_FORMULA },
	{ "formula_latex",         LT_FORMULA_LATEX },
	{ "freespacing",	   LT_FREE_SPACING },
	{ "giant",                 LT_GIANT },
	{ "headings",              LT_HEADINGS },
	{ "huge",                  LT_HUGE },
	{ "italic",                LT_ITALIC },
	{ "item_environment",     LT_ITEM_ENVIRONMENT },
	{ "itemsep",               LT_ITEMSEP },
	{ "labelbottomsep",             LT_LABEL_BOTTOMSEP },
	{ "labelfont",             LT_LABELFONT },
	{ "labelindent",           LT_LABELINDENT },
	{ "labelsep",              LT_LABELSEP },
	{ "labelstring",           LT_LABELSTRING },
	{ "labeltype",             LT_LABELTYPE },
	{ "large",                 LT_LARGE },
	{ "larger",                LT_LARGER },
	{ "largest",               LT_LARGEST },
	{ "latex",                 LT_LATEX },
	{ "latexclass",             LT_LATEXCLASS },
	{ "latexname",             LT_LATEXNAME },
	{ "latextype",             LT_LATEXTYPE },
	{ "layout",                LT_LAYOUT },
	{ "left",                  LT_LEFT },
	{ "leftmargin",            LT_LEFTMARGIN },
	{ "list_environment",     LT_LIST_ENVIRONMENT },
	{ "manual",                LT_MANUAL },
	{ "margin",                LT_MARGIN },
	{ "maxcounter",            LT_MAXCOUNTER },
	{ "medium",                LT_MEDIUM },
	{ "modern",                LT_MODERN },
	{ "newline",               LT_NEWLINE },
	{ "nextnoindent",          LT_NEXTNOINDENT },
	{ "no_bar",                LT_NO_BAR },
	{ "no_label",              LT_NO_LABEL },
	{ "no_latex",              LT_NO_LATEX },
	{ "normal",                LT_NORMAL },
	{ "options",               LT_OPTIONS },
	{ "pagestyle",             LT_PAGESTYLE },
	{ "paragraph",             LT_PARAGRAPH },
	{ "parindent",             LT_PARINDENT },
	{ "parsep",                LT_PARSEP },
	{ "parskip",               LT_PARSKIP },
	{ "plain",                 LT_PLAIN },
	{ "protected",             LT_PROTECTED },
	{ "right",                 LT_RIGHT },
	{ "right_address_box",     LT_RIGHT_ADDRESS_BOX },
	{ "rightmargin",           LT_RIGHTMARGIN },
	{ "roman",                 LT_ROMAN },
	{ "sans",                  LT_SANS },
	{ "sensitive",             LT_SENSITIVE },
	{ "series",                LT_SERIES },
	{ "shape",                 LT_SHAPE },
	{ "sides",                 LT_SIDES },
	{ "size",                  LT_SIZE },
	{ "small",                 LT_SMALL },
	{ "smallcaps",             LT_SMALLCAPS },
	{ "static",                LT_STATIC },
	{ "style",                 LT_STYLE },
	{ "tiny",                  LT_TINY },
	{ "top_environment",      LT_TOP_ENVIRONMENT },
	{ "topsep",                LT_TOPSEP },
	{ "typewriter",            LT_TYPEWRITER },
	{ "underbar",              LT_UNDERBAR },
	{ "up",                    LT_UP },
};


/* gets textclass number from name */
char LyXTextClassList::NumberOfClass(const char* textclass) 
{
	int i = 0;
   
	while (i < num_textclass &&
	       !StringEqual(textclass, ar [i].name))
		i++;
   
	if (i >= num_textclass)
		i = 0;
   
	return i;
}


/* gets layout structure from number and textclass number */
LyXLayout *LyXTextClassList::Style(char textclass, char layout) 
{
	if (ar) {
		if (layout < ar[textclass].number_of_defined_layouts)
			return &ar[textclass].style[layout];
		else {
			return &ar[textclass].style[0];
		};
	} else return dummy_textclass->style;
	
}


/* gets layout number from name and textclass number */
//fix this dabn100
char LyXTextClassList::NumberOfLayout(char textclass, const char* name) 
{
	int i = 0;
	if (ar) {
		while (i < ar[textclass].number_of_defined_layouts &&
	        	!StringEqual(name, ar[textclass].style[i].name))
			i++;
   	}
	if ((!ar) || (i >= ar[textclass].number_of_defined_layouts)) {
		if (StringEqual(name, "dummy"))
			i = LYX_DUMMY_LAYOUT;
		else
			i = 0;
	} 
	return i;
}


/* gets a layout (style) name from number and textclass number */
char* LyXTextClassList::NameOfLayout(char textclass, char layout) 
{
	if (!ar) {
		if (layout < 1) return "dummy";
		else return "@@end@@";
        }
	if ((layout < ar[textclass].number_of_defined_layouts))
	  return ar[textclass].style[layout].name;
	else if (layout == LYX_DUMMY_LAYOUT)
	  return "dummy";
	else
	  return "@@end@@";
}


/* gets a textclass name from number */
char* LyXTextClassList::NameOfClass(char number) 
{
	if (num_textclass == 0) { 
	   if (number == 0) return "dummy";
	   else return "@@end@@";
	}
	if (number < num_textclass)
		return ar[number].name;
	else
		return "@@end@@";
}

/* gets a textclass latexname from number */
char* LyXTextClassList::LatexnameOfClass(char number) 
{
	if (num_textclass == 0) { 
	   if (number == 0) return "dummy";
	   else return "@@end@@";
	}
	if (number < num_textclass)
		return ar[number].latexname;
	else
		return "@@end@@";
}


/* gets a textclass structure from number */
LyXTextClass * LyXTextClassList::TextClass(char textclass) 
{
	if (ar) {
		if (textclass < num_textclass)
			return &ar[textclass];
		else
			return &ar[0];
	} else return dummy_textclass;
}


/* gets a font from given file */
static int ReadFont(LyXLexClass lexrc, LyXFont& font)
{
	int family = LYX_ENVIRONMENT_DEFAULT;
	int series = LYX_ENVIRONMENT_DEFAULT;
	int shape = LYX_ENVIRONMENT_DEFAULT;
	int size = LYX_ENVIRONMENT_DEFAULT;
	int latex = LYX_NO_LATEX;
	int bar = LYX_NO_BAR;

	int error = 0;

	while (lexrc.IsOK() && !error) {
	       
	      switch(lexrc.lex()) {

		case -2:                                    /* empty line */
			break;

		case -1:                                    /* parse error */
			fprintf(stderr, "Line %d: Parse Error: Unknown tag %s.\n", 
				lexrc.GetLineNo(), lexrc.text());
			error = 1;
			break;

		case LT_ENDFONT:                            /* end of structure */
			error = -1;
			break;

		case LT_FAMILY:                             /* font family definition */
		        switch (lexrc.lex()) {
			case LT_ROMAN:
				family = LYX_ROMAN_FAMILY;
				break;
			case LT_SANS:
				family = LYX_SANS_FAMILY;
				break;
			case LT_TYPEWRITER:
				family = LYX_TYPEWRITER_FAMILY;
				break;
			case LT_MODERN:
				family = LYX_MODERN_FAMILY;
				break;
			case LT_ENVIRONMENT_DEFAULT:
				family = LYX_ENVIRONMENT_DEFAULT;
				break;
			}
			break;

		case LT_SERIES:                             /* font series definition */
			
			switch (lexrc.lex()) {
			case LT_MEDIUM:
				series = LYX_MEDIUM_SERIES;
				break;
			case LT_BOLD:
				series = LYX_BOLD_SERIES;
				break;
			case LT_ENVIRONMENT_DEFAULT:
				series = LYX_ENVIRONMENT_DEFAULT;
				break;
			}
			break;

		case LT_SHAPE:                             /* font shape definition */
		        switch (lexrc.lex()) {
			case LT_UP:
				shape = LYX_UP_SHAPE;
				break;
			case LT_ITALIC:
				shape = LYX_ITALIC_SHAPE;
				break;
			case LT_SMALLCAPS:
				shape = LYX_SMALLCAPS_SHAPE;
				break;
			case LT_ENVIRONMENT_DEFAULT:
				shape = LYX_ENVIRONMENT_DEFAULT;
				break;
			}
			break;

		case LT_SIZE:                              /* font size definition */
		        switch (lexrc.lex()) {
			case LT_TINY:
				size = LYX_SIZE_TINY;
				break;
			case LT_SMALL:
				size = LYX_SIZE_SMALL;
				break;
			case LT_NORMAL:
				size = LYX_SIZE_NORMAL;
				break;
			case LT_LARGE:
				size = LYX_SIZE_LARGE;
				break;
			case LT_LARGER:
				size = LYX_SIZE_LARGER;
				break;
			case LT_LARGEST:
				size = LYX_SIZE_LARGEST;
				break;
			case LT_HUGE:
				size = LYX_SIZE_HUGE;
				break;
			case LT_GIANT:
				size = LYX_SIZE_GIANT;
				break;
			case LT_ENVIRONMENT_DEFAULT:
				size = LYX_ENVIRONMENT_DEFAULT;
				break;
			}
			break;

		case LT_LATEX:                             /* font latex flag */
		        switch (lexrc.lex()) {
			case LT_NO_LATEX:
				latex = LYX_NO_LATEX;
				break;
			case LT_LATEX:
				latex = LYX_LATEX;
				break;
			case LT_FORMULA:
				latex = LYX_FORMULA_LATEX;
				break;
			case LT_PROTECTED:
				latex = LYX_PROTECTED_LATEX;
				break;
			case LT_FORMULA_LATEX:
				latex = LYX_PROTECTED_FORMULA_LATEX;
				break;
			}
			break;

		case LT_BAR:                             /* font bar definition */
		        switch (lexrc.lex()) {
			case LT_NO_BAR:
				bar = LYX_NO_BAR;
				break;
			case LT_UNDERBAR:
				bar = LYX_UNDER_BAR;
				break;
			}
			break;

		default:                                    /* context error */
			fprintf(stderr, "Line %d: Context Error : Tag %s not allowed in font.\n", 
				lexrc.GetLineNo(), lexrc.text());
			error = 1;
			break;
		}
	}

	if (error == -1) error = 0;
	if (!error) font = GetLyXFont(family, series, shape, size, latex, bar);
   
	return error;
}


 //constructor for layout
LyXLayout::LyXLayout ()
{
	static LyXFont dummy_font = GetLyXFont(LYX_ENVIRONMENT_DEFAULT,
					       LYX_ENVIRONMENT_DEFAULT,
					       LYX_ENVIRONMENT_DEFAULT, 
					       LYX_ENVIRONMENT_DEFAULT, 
					       LYX_NO_LATEX, LYX_NO_BAR);
	name = StringCopy("");
	margintype = MARGIN_STATIC;
	latextype = LATEX_PARAGRAPH;
	latexname = StringCopy ("");
	font = dummy_font;
	labelfont = dummy_font;
	nextnoindent = 0;
	leftmargin = StringCopy ("");
	rightmargin = StringCopy ("");
	labelsep = StringCopy ("");
	labelindent = StringCopy ("");
	parindent = StringCopy ("");
	parskip = 0.0;
	itemsep = 0;
	topsep = 0.0;
	bottomsep = 0.0;
	labelbottomsep = 0.0;
	parsep = 0;
	align = LYX_ALIGN_BLOCK;
	alignpossible = LYX_ALIGN_BLOCK;
	labeltype = LABEL_NO_LABEL;
	baselinestretch = 1.5;
	labelstring = StringCopy ("");
	fill_top = 0;
	fill_bottom = 0;
	newline_allowed = 1;
	free_spacing = 0;
}


LyXLayout::~LyXLayout ()
{
	delete [] name;
	delete [] latexname;
	delete [] leftmargin;
	delete [] rightmargin;
	delete [] labelsep;
	delete [] labelindent;
	delete [] parindent;
	delete [] labelstring;
}


void LyXLayout::Copy (LyXLayout &l)
{
	name = StringReplace (name, l.name);
	margintype = l.margintype;
	// latextype = LATEX_PARAGRAPH;
	latextype = l.latextype;
	latexname = StringReplace (latexname, l.latexname);
	font = l.font;
	labelfont = l.labelfont;
	nextnoindent = l.nextnoindent;;
	leftmargin = StringReplace (leftmargin, l.leftmargin);
	rightmargin = StringReplace (rightmargin, l.rightmargin);
	labelsep = StringReplace (labelsep, l.labelsep);
	labelindent = StringReplace (labelindent, l.labelindent);
	parindent = StringReplace (parindent, l.parindent);
	parskip = l.parskip;
	itemsep = l.itemsep;
	topsep = l.topsep;
	bottomsep = l.bottomsep;
	labelbottomsep = l.labelbottomsep;
	parsep = l.parsep;
	align = l.align;
	alignpossible = l.alignpossible;
	labeltype = l.labeltype;
	baselinestretch = l.baselinestretch;
	labelstring = StringReplace (labelstring, l.labelstring);
	fill_top = l.fill_top;
	fill_bottom = l.fill_bottom;
	newline_allowed = l.newline_allowed;
	free_spacing = l.free_spacing;
}


/* reads a layout definition from file */
int LyXLayout::Read (LyXLexClass lexrc)
{
	int error=0;

	/* parse style section */
	while (lexrc.IsOK() && !error) {   // !feof(file) && !error
		switch(lexrc.lex()) {

		case -2:
			break;

		case -1:                                    /* parse error */
			fprintf(stderr,
				"Line %d: Parse Error : Unknown tag %s.\n",
				lexrc.GetLineNo(), lexrc.text());
			error = 1;
			break;

		case LT_END:                                /* end of structure */
			error = -1;
			break;

		case LT_MARGIN:                             /* margin style definition */
		       
			switch(lexrc.lex()) {
			case LT_STATIC:
				margintype = MARGIN_STATIC;
				break;
			case LT_MANUAL:
				margintype = MARGIN_MANUAL;
				break;
			case LT_DYNAMIC:
				margintype = MARGIN_DYNAMIC;
				break;
			case LT_FIRST_DYNAMIC:
				margintype = MARGIN_FIRST_DYNAMIC;
				break;
			case LT_RIGHT_ADDRESS_BOX:
				margintype = MARGIN_RIGHT_ADDRESS_BOX;
				break;
			default:
				margintype = 0;
				break;
			}
			break;

		case LT_LATEXTYPE:                          /* latex style definition */
		        switch (lexrc.lex()) {
			case LT_PARAGRAPH:
				latextype=LATEX_PARAGRAPH;
				break;
			case LT_COMMAND:
				latextype=LATEX_COMMAND;
				break;
			case LT_ENVIRONMENT:
				latextype=LATEX_ENVIRONMENT;
				break;
			case LT_ITEM_ENVIRONMENT:
				latextype=LATEX_ITEM_ENVIRONMENT;
				break;
			case LT_LIST_ENVIRONMENT:
				latextype=LATEX_LIST_ENVIRONMENT;
				break;
			default:
				latextype=0;
				break;
			}
			break;

		case LT_FONT:
			ReadFont(lexrc, font);
			break;

		case LT_LABELFONT:
			ReadFont(lexrc, labelfont);
			break;

		case LT_NEXTNOINDENT:                       /* indent next paragraph ? */
			if (lexrc.next() && lexrc.GetInteger())
				nextnoindent = true;
			else
				nextnoindent = false;
			break;

		case LT_LATEXNAME:                          /* latex name */
		        if (lexrc.next())
		                latexname = lexrc.GetString();
			break;

		case LT_LABELTYPE:                            /* label type */
		        switch (lexrc.lex()) {
			case LT_NO_LABEL:
				labeltype = LABEL_NO_LABEL;
				break;
			case LT_MANUAL:
				labeltype = LABEL_MANUAL;
				break;
			case LT_TOP_ENVIRONMENT:
				labeltype = LABEL_TOP_ENVIRONMENT;
				break;
			case LT_CENTERED_TOP_ENVIRONMENT:
				labeltype = LABEL_CENTERED_TOP_ENVIRONMENT;
				break;
			case LT_STATIC:
				labeltype = LABEL_STATIC;
				break;
			case LT_SENSITIVE:
				labeltype = LABEL_SENSITIVE;
				break;
			case LT_COUNTER_CHAPTER:
				labeltype = LABEL_COUNTER_CHAPTER;
				break;
			case LT_COUNTER_SECTION:
				labeltype = LABEL_COUNTER_SECTION;
				break;
			case LT_COUNTER_SUBSECTION:
				labeltype = LABEL_COUNTER_SUBSECTION;
				break;
			case LT_COUNTER_SUBSUBSECTION:
				labeltype = LABEL_COUNTER_SUBSUBSECTION;
				break;
			case LT_COUNTER_PARAGRAPH:
				labeltype = LABEL_COUNTER_PARAGRAPH;
				break;
			case LT_COUNTER_SUBPARAGRAPH:
				labeltype = LABEL_COUNTER_SUBPARAGRAPH;
				break;
			case LT_COUNTER_ENUMI:
				labeltype = LABEL_COUNTER_ENUMI;
				break;
			case LT_COUNTER_ENUMII:
				labeltype = LABEL_COUNTER_ENUMII;
				break;
			case LT_COUNTER_ENUMIII:
				labeltype = LABEL_COUNTER_ENUMIII;
				break;
			case LT_COUNTER_ENUMIV:
				labeltype = LABEL_COUNTER_ENUMIV;
				break;
			}
			break;

		case LT_LEFTMARGIN:                         /* left margin type */

		        if (lexrc.next())
				leftmargin = lexrc.GetString();
			break;			

		case LT_RIGHTMARGIN:                        /* right margin type */
			if (lexrc.next())
				rightmargin = lexrc.GetString();
			break;

		case LT_LABELINDENT:                        /* label indenting flag */
			if (lexrc.next())
				labelindent = StringReplace(labelindent, lexrc.text());
			break;

		case LT_PARINDENT:                          /* paragraph indent. flag */
			if (lexrc.next())
				parindent = lexrc.GetString();
			break;

		case LT_PARSKIP:                            /* paragraph skip size */
			if (lexrc.next())
				parskip = lexrc.GetFloat();
			break;

		case LT_ITEMSEP:                            /* item separation size */
			if (lexrc.next())
				itemsep = lexrc.GetFloat();
			break;

		case LT_TOPSEP:                             /* top separation size */
			if (lexrc.next())
				topsep = lexrc.GetFloat();
			break;

		case LT_BOTTOMSEP:                          /* bottom separation size */
			if (lexrc.next())
				bottomsep = lexrc.GetFloat();
			break;

		case LT_LABEL_BOTTOMSEP:                          /* label bottom separation size */
			if (lexrc.next())
				labelbottomsep = lexrc.GetFloat();
			break;

		case LT_LABELSEP:                           /* label separator */
			if (lexrc.next()) {
				char *temp = labelsep = lexrc.GetString();
				while ((temp=strchr(labelsep, 'x'))!=NULL) 
					*temp=' ';
			}
			break;

		case LT_PARSEP:                             /* par. separation size */
			if (lexrc.next())
				parsep = lexrc.GetFloat();
			break;

		case LT_FILL_TOP:                             /* fill top flag */
			if (lexrc.next())
				fill_top = lexrc.GetInteger();
			break;

		case LT_FILL_BOTTOM:                          /* fill bottom flag */
			if (lexrc.next())
				fill_bottom = lexrc.GetInteger();
			break;

		case LT_NEWLINE:                            /* newlines allowed ? */
			if (lexrc.next())
				newline_allowed = lexrc.GetInteger();
			break;

		case LT_ALIGN:                              /* paragraph align */
			switch (lexrc.lex()) {
			case LT_BLOCK:
				align = LYX_ALIGN_BLOCK;
				break;
			case LT_LEFT:
				align = LYX_ALIGN_LEFT;
				break;
			case LT_RIGHT:
				align = LYX_ALIGN_RIGHT;
				break;
			case LT_CENTER:
				align = LYX_ALIGN_CENTER;
				break;
			case LT_FORMULA:
				align = LYX_ALIGN_FORMULA;
				break;
			case LT_LAYOUT:
				align = LYX_ALIGN_LAYOUT;
				break;
			}
			break;

		case LT_ALIGNPOSSIBLE:                      /* paragraph allowed align */
		{	alignpossible = 0;
		      
                        int lineno = lexrc.GetLineNo();
		        do {
			        switch (lexrc.lex()) {
				case LT_BLOCK:
					alignpossible |= LYX_ALIGN_BLOCK;
					break;
				case LT_LEFT:
					alignpossible |= LYX_ALIGN_LEFT;
					break;
				case LT_RIGHT:
					alignpossible |= LYX_ALIGN_RIGHT;
					break;
				case LT_CENTER:
					alignpossible |= LYX_ALIGN_CENTER;
					break;
				case LT_FORMULA:
					alignpossible |= LYX_ALIGN_FORMULA;
					break;
				case LT_LAYOUT:
					alignpossible |= LYX_ALIGN_LAYOUT;
					break;
				}
			} while (lineno==lexrc.GetLineNo());
		        break;
		}		
		case LT_BASELINE:                           /* base line stretch */
			if (lexrc.next())
				baselinestretch = lexrc.GetFloat();;
			break;

		case LT_LABELSTRING:                        /* label string definition */
			if (lexrc.next())
				labelstring = lexrc.GetString();
			break;

		case LT_FREE_SPACING:	/* Allow for free spacing. */
			if (lexrc.next())
				free_spacing = lexrc.GetInteger();
			break;

		default:                                    /* context error */
			fprintf(stderr, "Line %d: Context Error : Tag %s not allowed in layout.\n",
				lexrc.GetLineNo(), lexrc.text());
			error = 1;
			break;
		}
	}
  

	if (error== -1) error = 0;
	return error;
}


LyXTextClass::LyXTextClass()
{
        name = StringCopy ("");
        latexname = StringCopy ("");
	//style = new LyXLayout [100];
	style = NULL; //*)calloc(100, sizeof(LyXLayout));
	options = StringCopy("");
	columns = 1;
	sides = 1;
	pagestyle = PAGESTYLE_PLAIN;
	maxcounter = LABEL_COUNTER_CHAPTER;
	defaultfamily = LYX_ROMAN_FAMILY;
	defaultseries = LYX_MEDIUM_SERIES;
	defaultshape = LYX_UP_SHAPE;
	defaultsize = LYX_SIZE_NORMAL;
         number_of_defined_layouts = 0;
 }


 //this is not a proper copy.
 //It just references the style rather than copying it! 
void LyXTextClass::Copy (LyXTextClass &l)
{
	name = StringReplace (name, l.name);
	latexname = StringReplace (latexname, l.latexname);
	//just one.
	delete style;
	style = l.style; //just aliases NO COPY 
	options = StringReplace (options, l.options);
	columns = l.columns;
	sides = l.sides;
	pagestyle = l.pagestyle;
	maxcounter = l.maxcounter;
	defaultfamily = l.defaultfamily;
	defaultseries = l.defaultseries;
	defaultshape = l.defaultshape;
	defaultsize = l.defaultsize;
	number_of_defined_layouts = l.number_of_defined_layouts;
}


LyXTextClass::~LyXTextClass()
{
       //char* name;
       //style = new LyXLayout; 
       //we can't delete the style here because otherwise 
       //our list classes wouldn't work
       //delete style;
	delete [] options;
	delete [] name;
	delete [] latexname;
}


/* reads a textclass structure from file */
int LyXTextClass::Read (char *filename)
{
	LyXLexClass lexrc(layoutTags, sizeof(layoutTags)/sizeof(keyword_item));
	int error = 0;

        lexrc.setFile(filename);
	if (!lexrc.IsOK()) return -2; 

	LyXLayoutList l;
	LyXLayout * tmpl;

	/* parsing */
	while (lexrc.IsOK() && !error) {
		switch(lexrc.lex()) {
		case -2:
			break;
			
		case -1:                                 
			fprintf(stderr, "Line %d: Parse Error : Unknown tag %s.\n",
				lexrc.GetLineNo(), lexrc.text());
			error = 1;
			break;
			
		case LT_STYLE:
			if (lexrc.next()) {
			        char* temp=lexrc.GetString();
			   	tmpl = new LyXLayout;
				tmpl->name = temp;
				while ((temp=strchr(tmpl->name, '_')) != NULL)
					*temp = ' ';
				if (!tmpl->Read(lexrc)) {
				  l.Add (tmpl);
			          //NB we  don't delete because we 
				  //just pass it in.... 
				} else {	
				       fprintf(stderr, "Line %d: Parse Error : Error parsing style %s.\n",
						lexrc.GetLineNo(), lexrc.text());
					error = 1;
					delete tmpl;  //we delete dead ones here
				}
			}
			else {
				fprintf(stderr, "Line %d: Parse Error : No name given for style.\n", lexrc.GetLineNo());
				error = 1;
			}
			break;
			
		case LT_OPTIONS:
		        if (lexrc.next())
		                options = lexrc.GetString();
		        break;
			
		case LT_LATEXCLASS:
		        if (lexrc.next())
				latexname =
				  StringReplace(latexname, lexrc.GetString());
			break;

		case LT_COLUMNS:
			if (lexrc.next())
				columns = lexrc.GetInteger();
			break;
			
		case LT_SIDES:
			if (lexrc.next())
				sides = lexrc.GetInteger();
			break;
			
		case LT_PAGESTYLE:
			switch (lexrc.lex()) {
			case LT_PLAIN:
				pagestyle = PAGESTYLE_PLAIN;
				break;
			case LT_HEADINGS:
				pagestyle = PAGESTYLE_HEADINGS;
				break;
			case LT_FANCYHDR:
				pagestyle = PAGESTYLE_FANCYHDR;
				break;
			case LT_EMPTY:
				pagestyle = PAGESTYLE_EMPTY;
				break;
			}
			break;
			
		case LT_DEFAULTFAMILY:
		        switch (lexrc.lex()) {
			case LT_ROMAN:
				defaultfamily = LYX_ROMAN_FAMILY;
				break;
			case LT_SANS:
				defaultfamily = LYX_SANS_FAMILY;
				break;
			case LT_TYPEWRITER:
				defaultfamily = LYX_TYPEWRITER_FAMILY;
				break;
			case LT_MODERN:
				defaultfamily = LYX_MODERN_FAMILY;
				break;
			}
			break;

		case LT_DEFAULTSERIES:                             /* font series definition */
			
			switch (lexrc.lex()) {
			case LT_MEDIUM:
				defaultseries = LYX_MEDIUM_SERIES;
				break;
			case LT_BOLD:
				defaultseries = LYX_BOLD_SERIES;
				break;
			}
			break;

		case LT_DEFAULTSHAPE:                             /* font shape definition */
		        switch (lexrc.lex()) {
			case LT_UP:
				defaultshape = LYX_UP_SHAPE;
				break;
			case LT_ITALIC:
				defaultshape = LYX_ITALIC_SHAPE;
				break;
			case LT_SMALLCAPS:
				defaultshape = LYX_SMALLCAPS_SHAPE;
				break;
			}
			break;

		case LT_DEFAULTSIZE:                              /* font defaultsize definition */
		        switch (lexrc.lex()) {
			case LT_TINY:
				defaultsize = LYX_SIZE_TINY;
				break;
			case LT_SMALL:
				defaultsize = LYX_SIZE_SMALL;
				break;
			case LT_NORMAL:
				defaultsize = LYX_SIZE_NORMAL;
				break;
			case LT_LARGE:
				defaultsize = LYX_SIZE_LARGE;
				break;
			case LT_LARGER:
				defaultsize = LYX_SIZE_LARGER;
				break;
			case LT_LARGEST:
				defaultsize = LYX_SIZE_LARGEST;
				break;
			case LT_HUGE:
				defaultsize = LYX_SIZE_HUGE;
				break;
			case LT_GIANT:
				defaultsize = LYX_SIZE_GIANT;
				break;
			}
			break;

		case LT_MAXCOUNTER:
			switch (lexrc.lex()) {
			case LT_COUNTER_CHAPTER:
				maxcounter = LABEL_COUNTER_CHAPTER;
				break;
			case LT_COUNTER_SECTION:
				maxcounter = LABEL_COUNTER_SECTION;
				break;
			case LT_COUNTER_SUBSECTION:
				maxcounter = LABEL_COUNTER_SUBSECTION;
				break;
			case LT_COUNTER_SUBSUBSECTION:
				maxcounter = LABEL_COUNTER_SUBSUBSECTION;
				break;
			case LT_COUNTER_PARAGRAPH:
				maxcounter = LABEL_COUNTER_PARAGRAPH;
				break;
			case LT_COUNTER_SUBPARAGRAPH:
				maxcounter = LABEL_COUNTER_SUBPARAGRAPH;
				break;
			case LT_COUNTER_ENUMI:
				maxcounter = LABEL_COUNTER_ENUMI;
				break;
			case LT_COUNTER_ENUMII:
				maxcounter = LABEL_COUNTER_ENUMII;
				break;
			case LT_COUNTER_ENUMIII:
				maxcounter = LABEL_COUNTER_ENUMIII;
				break;
			case LT_COUNTER_ENUMIV:
				maxcounter = LABEL_COUNTER_ENUMIV;
				break;
			}
			break;
			
		default:
			fprintf(stderr, "Line %d: Parse Error : Out of context tag %s.\n", 
				lexrc.GetLineNo(), lexrc.text());
			break;
		}
	}	
		
        if (error==-2) error = 0;
	if (error) {
		//free(textclass.style);
		//delete style;
		number_of_defined_layouts = 0;
		l.Clean(); //wipe any we may have found
	}
	else {
 		//revise this dabn100
		//style = (LyXLayout *)realloc(style, 
		//				       layout*sizeof(LyXLayout));
		style = l.ToAr();
		number_of_defined_layouts = l.GetNum();
	}
	
	return error;
}


LyXLayoutList::LyXLayoutList()
{
  l = NULL;
  eol = NULL;
  num_layouts = 0;
}


LyXLayoutList::~LyXLayoutList()
{
  //don't do anything. the layouts will be extracted by ToAr.
  //destruction is done by Clean in emergencies
}


int LyXLayoutList::GetNum ()
{
  return num_layouts;
}


void LyXLayoutList::Add (LyXLayout *lay)
{
  LyXLayoutL * tmp = new LyXLayoutL;
  tmp->layout = lay;
  tmp->next = NULL;
  if (!eol) l = tmp; 
  else eol->next = tmp;
  eol = tmp;
  num_layouts++;
}


LyXLayout * LyXLayoutList::ToAr ()
{
   LyXLayoutL * lp, * op;
   int idx = 0;
   LyXLayout* ar = new LyXLayout [num_layouts];
   lp = l;
   while (lp) {
     ar[idx].Copy (*lp->layout);
     idx++;
     delete lp->layout;
     op = lp;
     lp = lp->next;
     delete op;
   }
   return ar;
}


//wipe up any dead layouts
void LyXLayoutList::Clean ()
{
   LyXLayoutL * lp, * op;
   lp = l;
   while (lp) {
     delete lp->layout;
     op = lp;
     lp = lp->next;
     delete op;
   }
}


LyXTextClassList::LyXTextClassList()
{
  l = NULL;
  eol = NULL;
  num_textclass = 0;
  dummy_textclass = new LyXTextClass;
  dummy_textclass->number_of_defined_layouts = 1;
  dummy_textclass->style = new LyXLayout;
  dummy_textclass->style->name = 
	StringReplace (dummy_textclass->style->name, "dummy");
}


LyXTextClassList::~LyXTextClassList()
{
  delete dummy_textclass->style;
  delete dummy_textclass;
 //don't do anything. the classes will be extracted by ToAr.
}


int LyXTextClassList::GetNum ()
{
  return num_textclass;
}


void LyXTextClassList::Add (LyXTextClass *t)
{
  LyXTextClassL * tmp = new LyXTextClassL;
  tmp->textclass = t;
  tmp->next = NULL;
  if (!eol) l = tmp; 
  else eol->next = tmp;
  eol = tmp;
  num_textclass++;
}


void LyXTextClassList::ToAr ()
{
   LyXTextClassL * lp, *op;
   int idx = 0;
   ar = new LyXTextClass [num_textclass];
   lp = l;
   while (lp) {
     ar[idx].Copy (*lp->textclass);
     idx++;
     delete lp->textclass; //note we don't delete layouts here at all
     op = lp;
     lp = lp->next;
     delete op;
   }
}


/* gets LyX textclass config from file */
int LyXTextClassList::Read (const char *path)
{
        char * real_file;
	char * tmppath;
	char buffer[256];
	char *temp;
	FILE *file;
	int error = 0;
	char classfilename [] = "textclass.def";
	char searchpath [] = "./:$$LyX/layouts:./layouts";
	LyXTextClass *tmpl;
	// first try cwd, then LYX_DIR/layouts, then cwd/layouts
	real_file = FileOpenSearch (path, searchpath, classfilename, NULL);
	if (!real_file) {
		fprintf(stderr,
			"GetLyXTextClass: unable to open textclass file. Exiting.\n");

		WriteAlert("LyX wasn't able to find it's layout descriptions!\n",
			   "Either it wasn't compiled with the right lyx_dir path",
			   "or the libs are not installed correctly. Sorry, but it has to exit:-( ");

		return -1;
		// this causes LyX to end...not really a desirable behaviour. Lgb
		}
	
	if (!(file = fopen(real_file, "r"))) {
		fprintf(stderr,"GetLyXTextClass: unable to open textclasse file `%s',\n",
			real_file);
		delete [] real_file;
 		return -1;
	}
	tmppath = NameToPath (NULL, real_file);
	delete [] real_file;
	
	while (!feof(file) && !error) {
		BZERO(buffer, sizeof(buffer));
		if ((fgets(buffer, sizeof(buffer), file)!=NULL) && (buffer[0]!='#')) {
			while ((temp=strchr(buffer, '\n'))!=NULL) 
				*temp=' ';

			/* get rid of comments */
			if ((temp = strchr(buffer, '#'))!=NULL) 
				*temp=0;

			temp = strtok(buffer, " \t");
			/* ignore blank and whitespace-only lines */
			if (temp==NULL) continue;
    	                tmpl = new LyXTextClass;
			tmpl->name = 
				StringReplace(tmpl->name,temp);
			tmpl->latexname = 
				StringReplace(tmpl->latexname,temp);
			temp = strtok(NULL, " \t");
			if (temp==NULL) error = 1;
			else { 
			   	real_file = AddName(NULL, tmppath, temp);
				if (tmpl->Read (real_file)) {
					fprintf(stderr,
						"GetLyXTextClass: error"
						" from ReadTextClass: %s\n",
						real_file);
					error = 1;
 					delete tmpl; 
				}
				else {
					//textclass++;
  					Add (tmpl);
					delete [] real_file;
				}
			}
		}
	}
	delete [] tmppath;
	if (error) {
		num_textclass = 0;
		//delete lyxstyle;
	} else {
		ToAr();
		//revise this dabn100
		//lyxstyle = (LyXTextClass *) realloc(lyxstyle, 
		//				    textclass*sizeof(LyXTextClass));
	}
	
	fclose(file);
	return error;
}


void LyXSetStyle(const char *path) 
{
	int e;
	if (lyx_debug_level)
	fprintf(stderr, "LyXSetStyle : parsing configuration...\n");
	
	if ((e=lyxstyle.Read(path))!=0) {
		fprintf(stderr,
			"LyXSetStyle : an error occured during parsing.\n"
			"              Exiting. [%d]\n", e);
		exit(1);
	}
	if (lyx_debug_level)
	fprintf(stderr, "LyXSetStyle : configuration parsed.\n");
}
