/*  textrans.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */

#include <ctype.h>
#include <string.h>
#include <stream.h>
#include "texutil.h"
#include "textrans.h"
#include "textfrag.h"
#include "outtok.h"
#include "texspec.h"
#include "cgidbg.h"

TeXTranslate TranslateToTeX ;


static TeXMathTranslation  TheTeXMathTranslation[] = {
	{ '^', "$\\wedge$"},
	{ '<', "$<$"},
	{ '>', "$>$"},
	{ '|', "$|$"},
	{ ']', "$]$"},
	{ '[', "$[$"},
	{ '*', "$\\times$"},
	{0}
};

TeXTranslate::TeXTranslate():
	TeXMathTrans(TheTeXMathTranslation),
	Buffer(0),
	BufferCount(0),
	CheckMacroTail(0),
	Size(0)
{
}

static const char * CheckTail(const char * String)
{
	static const char * TeXMacroTail[] = {
		"{}","~",0};
	for (const char ** Check = TeXMacroTail; *Check ; Check++) {
		const char * Str = String ;
		for (const char * ptr = *Check ; *ptr ; ptr++)
			if (*(Str++) != *ptr) break ;
		if (!*ptr) {
			// LogOut << "Returning `" << *Check << "'\n" ;
			return *Check ;
		}
	}
	return 0 ;
}


const char * TeXTranslate::IsTeXMathTranslatable(char C)
{
	for (const TeXMathTranslation * Check = TeXMathTrans; Check->C;
		Check++) if (Check->C == C) return Check->Translation ;
	return 0 ;
}

void TeXTranslate::ExpandBuffer()
{
	int NewSize = 128 ;
	if (Size) NewSize = Size + (Size >> 1) ;
	char * Temp = new char[NewSize] ;
	for (int i = 0 ; i < Size; i++) Temp[i] = Buffer[i] ;
	for(;i<NewSize;i++) Temp[i] = '\0' ;
	delete Buffer ;
	Buffer = Temp ;
	Size = NewSize ;
}

void TeXTranslate::AppendChar(char C)
{
	if (BufferCount+3 > Size) ExpandBuffer();
	Buffer[BufferCount++] = C ;
}

void TeXTranslate::Append(const char * str)
{
	for (const char *Ptr = str; *Ptr; Ptr++) AppendChar(*Ptr);
}

int TeXTranslate::InList(char Check, const char * TheList)
{
	for (const char * ListChar = TheList; *ListChar ; ListChar++)
		if(*ListChar == Check) return 1;
	return 0 ;
}



int TeXTranslate::RequireTranslate(const char * Text)
{
	for (const char * Check = Text ; *Check; Check++) 
		if (IsSpecial(*Check)) return 1 ;
	return 0 ;
}


static int do_not_translate(const char * ck)
{
	static const char * forbidden[] = {
		"const char *",
		"char *",
		"int *",
		"int32 *",
		"-*",
		0
	};
	for (const char **ag =  forbidden; *ag;ag++) {
		int length = strlen(*ag);
		if (!strncmp(*ag,ck,length)) return length ;
	}
	return 0 ;
}


const char * TeXTranslate::DoTeXTranslate(const char * Fragment)
{
	if (!RequireTranslate(Fragment)) return Fragment ;
	ClearBuffer();
	char C ;
	int ExitMath = 0 ;
	const char * Temp ;
	for (const char * ToTranslate = Fragment; *ToTranslate; ToTranslate++) {
		int skip = do_not_translate(ToTranslate) ;
		for (int i = 0 ; i < skip ; i++) AppendChar(*ToTranslate++);
		if (skip) {
			ToTranslate-- ;
			continue ;
		}
		if (CheckMacroTail) {
			const char * Tail = CheckTail(ToTranslate);
			if (Tail) {
				ToTranslate+= strlen(Tail) - 1 ;
				Append(Tail);
				continue ;
			}
		}
		CheckMacroTail = 0 ;
		C = *ToTranslate ;
		if (ExitMath) if (!isalnum(C)) {
			if (ExitMath) AppendChar('$');
			ExitMath = 0 ;
		}
		if (C == '$') if (ToTranslate[1] == '$')
			if (ToTranslate[2]) if (isalpha(ToTranslate[2])) {
			Append("$$");
			ToTranslate++ ;
			continue ;
		}
		if (IsSpecial(C)) if(IsEscapable(C)) AppendChar('\\');
		else if(Temp = IsTeXMathTranslatable(C)) {
			Append(Temp);
			continue ; 
		} else {
			if (C== '\\') {
				const char * MacroWord =
					TheTeXWordTranslator.
					IsTeXMacro(ToTranslate) ;
				if (MacroWord) {
					if (TheTeXWordTranslator.
						IsMathTeXMacro(ToTranslate)) {
						ExitMath = 1 ;
						AppendChar('$');
					} 
					Append(MacroWord) ;
					ToTranslate+=strlen(MacroWord)-1;
					CheckMacroTail = 1 ;
					continue ;
				}
			}	
			cerr << "Cannot translate character `"
				<< C << "' in fragment \n`"  <<
				Fragment << "'.\n" ;
			continue ;
		}
		AppendChar(C);
	}
	if (ExitMath) AppendChar('$');
	AppendChar('\0');
	// cerr << "Translated Buffer is `" << Buffer << "'\n" ;
	return Buffer ;
}

/*
 * void TeXOutFragmentList(OutTokens& Out, TextFragmentList * TextList)
 * {
 *	TextFragment * Fragment ;
 *	TextFragmentListIterator Next(*TextList);
 *	while (Fragment = Next())  {
 *		const char * Trans = TranslateToTeX.DoTeXTranslate(
 *			Fragment->Text);
 *		if (Fragment->Line <0) Out.NextTeXttOut(Trans) ;
 *		else Out.NextFillOut(Trans);
 *	}
 * }
 */

