/*  texrep.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <ctype.h>
#include <string.h>
#include "mkstr.h"

struct TeXMacro {
	const char * Text ;
	const char * Macro ;
};

class ReplaceWithTeX {
	TeXMacro * TheMacros ;
	const char * Special ;

	int IsSpecial(char C);
	int IsSeparator(char C) ;

	const char * GetQuoteReplace(const char * Start, const char * End) ;
	const char * CheckForQuoted(const char * Start) ;
	TeXMacro * CheckForMacro(const char * Start) ;
	TeXMacro * FindReplacement(const char * Word);
public:
	ReplaceWithTeX(TeXMacro * the_macros, const char * spec);
	char * ReplaceMacros(const char * Orig);
	char * ReplaceQuoted(const char * Orig);
	char * Replace(const char * Orig);
};

static TeXMacro TheReplacements[] = {
	{"DSP++", "\\dpp{}"},
	{"ObjectPro++", "\\IntPp{}"},
	{"ObjectProDSP", "\\Dpp{}"},
	{"C++", "\\Cpp{}"},
	{0}
};

static const char * TheSpecialCharacters = "+" ;

ReplaceWithTeX TheReplacer(TheReplacements,TheSpecialCharacters) ;

ReplaceWithTeX::ReplaceWithTeX(TeXMacro * the_macros, const char * spec):
	TheMacros(the_macros),
	Special(spec)
{
}

int ReplaceWithTeX::IsSeparator(char C)
{
	if (!C) return 1 ;
	if (isalnum(C)) return 0 ;
	if (IsSpecial(C)) return 0;
	return 1 ;
}

int ReplaceWithTeX::IsSpecial(char C)
{
	for (const char * Spec = Special; *Spec; Spec++)
		if (C == *Spec) return 1 ;
	return 0 ;
}

TeXMacro * ReplaceWithTeX::FindReplacement(const char * Word)
{
	for (TeXMacro * Ck = TheMacros; Ck->Text; Ck++) 
		if (!strcmp(Ck->Text,Word)) return Ck ;
	return 0 ;
}

static int tex_quote_alnum(char c)
{
	if (c == '\'') return 0 ;
	if (c == ' ') return 1 ;
	return isgraph(c);

}

const char * ReplaceWithTeX::CheckForQuoted(const char * Start)
{
	if (*Start++ != '`') return 0 ;
	for (const char * Pt = Start; *Pt; Pt++) if (!tex_quote_alnum(*Pt)) break ;
	if (*Pt != '\'') return 0 ;
	return Pt ;
}

const char * ReplaceWithTeX::GetQuoteReplace(const char * Start,
	const char * End)
{
	const MaxReplaceString= 64 ;
	static char Buf[MaxReplaceString+1] ;
	const char * Prefix = "\\DppNm{" ;
	const char * Suffix = "}" ;
	int ReplaceLength = End - Start - 1 ;

	int PrefixLength = strlen(Prefix);
	int SuffixLength = strlen(Suffix);

	if (ReplaceLength < 1) {
		Buf[0] = '\0' ;
		return Buf ;
	}
	if (ReplaceLength + PrefixLength + SuffixLength + 1 >=
		MaxReplaceString) return 0 ;
	strcpy(Buf,Prefix);
	strncpy(Buf+PrefixLength,Start+1,ReplaceLength);
	strcpy(Buf+PrefixLength+ReplaceLength,Suffix);
	return Buf ;
}

TeXMacro * ReplaceWithTeX::CheckForMacro(const char * Start)
{
	const MaxWordSize = 32 ;
	char Word[MaxWordSize + 1] ;
	for (const char * Pt = Start; *Pt; Pt++) if (IsSeparator(*Pt)) break;
	int Length = Pt - Start ;
	if (Length < 1) return 0 ;
	if (Length >= MaxWordSize) return 0 ;
	strncpy(Word,Start,Length);
	Word[Length] = '\0' ;
	return FindReplacement(Word);
}

char * ReplaceWithTeX::Replace(const char * Orig)
{
	char * Temp = ReplaceMacros(Orig);
	char * Temp2 = ReplaceQuoted(Temp);
	delete Temp ;
	return Temp2 ;
}

char * ReplaceWithTeX::ReplaceQuoted(const char * Orig)
{
	const MaxLine = 1024 ;
	char Temp[MaxLine] ;
	int PreviousSpace = 1 ;
	int index = 0 ;
	for (const char * Pt = Orig ; *Pt ; Pt++) {
		if (isspace(*Pt) || *Pt == '(') PreviousSpace = 1 ;
		else {
			const char * Replace = 0 ;
			if (PreviousSpace) Replace = CheckForQuoted(Pt) ;
			PreviousSpace = 0 ;
			if (Replace) {
				const char * Sub = GetQuoteReplace(Pt,Replace);
				if (Sub) {
					int Length = strlen(Sub);
					if (Length + index > MaxLine - 2)
						return Concatenate(Orig);
					Pt = Replace ;
					strcpy(Temp+index,Sub);
					index+= Length ;
					continue ;
				}
			}
		}
		if (index > MaxLine -2) return Concatenate(Orig);
		Temp[index++]= *Pt ;
	}
	Temp[index] = '\0' ;
	return Concatenate(Temp);
}

char * ReplaceWithTeX::ReplaceMacros(const char * Orig)
{
	const MaxLine = 1024 ;
	char Temp[MaxLine] ;
	int PreviousSpace = 1 ;
	int index = 0 ;
	int DidReplace = 0 ;
	for (const char * Pt = Orig ; *Pt ; Pt++) {
		if (isspace(*Pt)) PreviousSpace = 1 ;
		else {
			TeXMacro * Replace = 0 ;
/*
 *			if (PreviousSpace)
 *				cerr << "Checking: `" <<  Pt << "'.\n" ;
 */
			if (PreviousSpace) Replace = CheckForMacro(Pt) ;
			PreviousSpace = 0 ;
			if (Replace) {
				int Length = strlen(Replace->Macro) ;
				if (index + Length > MaxLine - 2) return
					Concatenate(Orig) ;
				strcpy(Temp+index,Replace->Macro);
				index += Length ;
				Pt += strlen(Replace->Text) - 1;
				DidReplace = 1 ;
				continue ;
			}
		}
		if (index > MaxLine -2) return Concatenate(Orig) ;
		Temp[index++]= *Pt ;
	}
	Temp[index] = '\0' ;
	if (!DidReplace) return Concatenate(Orig) ;
	// cerr << "Returning `" << Temp << "'.\n" ;
	return Concatenate(Temp);
}
 

char * TeX(const char * Text)
{
	return TheReplacer.Replace(Text);
}
