/*  outtok.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <fstream.h>
#include <stdio.h>
#include <stdlib.h>
#include "outtok.h"
#include "usercom.h"
#include "debug.h"
#include "myfloat.h"
#include "textrans.h"
#include "texspec.h"
#include "cgidbg.h"
// #include "cgidbg.h"

// void TestAlloc(const char * msg);

static int Strlen(const char * Str)
{
	int Return = 0 ;
	for (; *Str; Str++) if (*Str == '\t') Return+=8;
		else Return++ ;
	return Return ;
}

void OutTokens::CommonInit()
{
	LineCount=0;
	TokenBufSize = 0;
	TheToken = 0 ;
	LastCharOut =0;
}

OutTokens::OutTokens (
	OutCon * out_con ,
	enum OutputType Type,
	int init,
	const char *ter,
	const char *sep,
	const char * inis,
	int lw,
	int lh,
	ReturnOption quit,
	SpecialOptions * Spec):
	Options(Spec),
	out(0),
	page_number(0)
{
	// LogOut << "Calling Init(" << Type << ")\n" ;
	Init(Type,out_con) ;
	LineTerminator = ter;
	Separator = sep ;
	Initator = inis ;
	LineOut = init ;
	LineWidth = lw - 1 - Strlen(LineTerminator) ;
	LinesInScreen = lh ;
	QuitOption = quit ;
	CommonInit();
}

OutTokens::OutTokens (
	enum OutputType Type,
	int init,
	const char *ter,
	const char *sep,
	const char * inis,
	int lw,
	int lh,
	ReturnOption quit,
	SpecialOptions * Spec):TheToken(0),
	Options(Spec),
	page_number(0)
{
	// LogOut << "Calling Init(" << Type << ")\n" ;
	Init(Type) ;
	LineTerminator = ter;
	Separator = sep ;
	Initator = inis ;
	LineOut = init ;
	LineWidth = lw - 1 - Strlen(LineTerminator) ;
	LinesInScreen = lh ;
	QuitOption = quit ;
	CommonInit();
}

OutTokens::OutTokens (
	ostream * o,
	int init,
	const char *ter,
	const char *sep,
	const char * inis,
	int lw,
	int lh,
	ReturnOption quit,
	SpecialOptions * Spec):
	Options(Spec),
	out(0),
	page_number(0)
{
	// LogOut << "Opening OutTokens for stream\n" ;
	Out = OutputUndefined; 	// set to undefined
	Check(o) ;
	LineTerminator = ter;
	Separator = sep ;
	Initator = inis ;
	LineOut = init ;
	LineWidth = lw - 1 - Strlen(LineTerminator) ;
	LinesInScreen = lh ;
	QuitOption = quit ;
	CommonInit();
}

int OutTokens::ReturnOr(int con)
{
	const char * outtoktotalparts = "outtoktotalparts" ;
	switch (QuitOption) {
case ReturnPage:
		if (!con || con &1) {
			*out <<
				"\\end{verbatim}\n\\caption{\\outtokcaption (part " <<
					++page_number << " of \\" << outtoktotalparts  << "{})}\n" ;
			if (page_number == 1) *out << "\\label{\\outtoklabel}\n" ;
			*out << "\\end{figure}\n" ;
		}
		if (!con || con&2) *out << "\\begin{figure}\n\\begin{verbatim}\n" ;
		if (con&4) {
			const char * ottok_mac_def = "ottok_mac_def" ;
			ofstream mac_out(ottok_mac_def);
			if (!mac_out.good()) {
				cerr << "Cannot create`" << ottok_mac_def << "'.\n" ;
				exit(1);
			}
			mac_out << "\\renewcommand{\\" << outtoktotalparts << "}{" <<
				page_number << "}\n" ;
		}
		return 1 ;
case ReturnIgnore:
		return 1;
case ReturnQuitOption:
		return ReturnOrQuit(Out);
case ReturnWait:
		ReturnToContinue(Out);
	}
	return 1;
}

int OutTokens::NewPage()
{
	int Return = 1;
	if (LineOut) Return = NewLine();
	if (!Return) return 0;
	if (LineCount) Return = ReturnOr();
	LineCount = 0;
	return Return ;
	
}

int OutTokens::FlushLine()
{
	if (LineOut) return NewLine();
	return 1 ;
}
	
void OutTokens::InitiateLine()
{
	TerminateLine();
	LineOut = Strlen(Initator);
	if (!Initator) return ;
	if (!*Initator) return ;
	*out << Initator ;
	LastCharOut = Initator[strlen(Initator)-1] ;
}
	
int OutTokens::TerminateLine()
{
	if (LineOut) {
		*out << LineTerminator ;
		return NewLine();
	}
	return 1 ;
}

int OutTokens::NewLine()
{
	int Return = 1;
	LineOut = 0;
	*out << "\n" ;
	LastCharOut = '\n' ;
	LineCount++ ;
	if (LineCount >= LinesInScreen) {
		Return =ReturnOr() ;
		LineCount = 0;
	}
	return Return ;
}

int OutTokens::NextTeXDblQuoteOut(const char * o)
{
	int Return = 1;
	if (!o) o = "__NULL!!" ;
	else o = TeXString(o) ;
	char Sep[2] ;
	if (LineOut) strcpy(Sep," ") ; else Sep[0]= '\0' ;
	LineOut+= Strlen(o) + Strlen(Sep) + 4 ;
	if (LineOut > LineWidth) {
		Return = NewLine() ;
		if (!Return) return 0;
		LineOut = Strlen(o) + 4 ;
		*out << "``" << o << "''" ;
		LastCharOut = '\'' ;
		return Return ;
	}
	*out << Sep << "``" << o  << "''" ;
	LastCharOut = '\'' ;
	return Return ;
}

int OutTokens::NextDblQuoteOut(const char * o)
{
	int Return = 1;
	if (!o) o = "NULL!!" ;
	char Sep[2] ;
	if (LineOut) strcpy(Sep," ") ; else Sep[0]= '\0' ;
	LineOut+= Strlen(o) + Strlen(Sep) + 2 ;
	if (LineOut > LineWidth) {
		Return = NewLine() ;
		if (!Return) return 0;
		LineOut = Strlen(o) + 2 ;
		*out << "\"" << o << "\"" ;
		LastCharOut = '"' ;
		return Return ;
	}
	*out << Sep << "\"" << o  << "\"" ;
	LastCharOut = '"' ;
	return Return ;
}

int OutTokens::NextQuoteOut(const char * o)
{
	int Return = 1;
	if (!o) o = "NULL!!" ;
	char Sep[2] ;
	if (LineOut) strcpy(Sep," ") ; else Sep[0]= '\0' ;
	LineOut+= Strlen(o) + Strlen(Sep) + 2 ;
	if (LineOut > LineWidth) {
		Return = NewLine() ;
		if (!Return) return 0;
		LineOut = Strlen(o) + 2 ;
		*out << "`" << o << "'" ;
		LastCharOut = o[strlen(o)-1] ;
		return Return ;
	}
	*out << Sep << "`" << o  << "'" ;
	LastCharOut = '\'' ;
	return Return ;
}

int OutTokens::NextOut(const char * o)
{
	int Return = 1;
	if (!o) o = "NULL!!" ;
	if (!LineOut) {
		*out << o ;
		LineOut = Strlen(o) ;
		LastCharOut = o[LineOut];
		return Return ;
	}
	LineOut+= Strlen(o) + Strlen(Separator) ;
	if (LineOut > LineWidth) {
		*out << LineTerminator ;
		Return = NewLine() ;
		if (!Return) return 0;
		LineOut = Strlen(o) + Strlen(Initator);
		*out << Initator << o ;
		LastCharOut = o[strlen(o)-1] ;
		return Return ;
	}
	*out << Separator << o ;
	LastCharOut = o[strlen(o)-1] ;
	return Return ;
}

int OutTokens::NextWrite(const char * o)
{
	int Return = 1;
	if (!o) o = "NULL!!" ;
	LineOut+= Strlen(o) ;
	if (LineOut > LineWidth) {
		*out << LineTerminator ;
		Return = NewLine() ;
		if (!Return) return 0;
		LineOut = Strlen(o) + Strlen(Initator);
		*out << Initator << o ;
		LastCharOut = o[strlen(o)-1] ;
		return Return ;
	}
	*out << o ;
	LastCharOut = o[strlen(o)-1] ;
	return Return ;
}

int OutTokens::NextFillOut(const char * o,int ConcatFlag)
{
	// TestAlloc("Enter NextFillOut");
	int Return = 1;
	if (!o) o = "NULL!!" ;
	char Sep[2] ;
	if (LineOut && !ConcatFlag) strcpy(Sep," ") ; else Sep[0]= '\0' ;
	int Lng = Strlen(o) + Strlen(Sep) ;
	LineOut+= Lng ;
	int SkipFirst = ConcatFlag ;
	if (LineOut > LineWidth) {
		LineOut -= Lng ;
		int BufSz = Lng ;
		char * Buf = new char [BufSz+1];
		char * Word = new char[BufSz+1] ;
		{
			memset(Word,'\0',BufSz);
			memset(Buf,'\0',BufSz);
			strcpy (Buf,o);
			istrstream ReadWord(Buf,BufSz);
			// LogOut << "NextConcat o = `" << o << "'\n" ;
			// TestAlloc("while");
			while (ReadWord.good()) {
				// TestAlloc("start loop body") ;
				Word[0] = '\0' ;
				ReadWord  >> Word;
				// TestAlloc("after read");
				// LogOut << "word `" << Word << "'\n" ;
				if (!*Word) break ;
				if (LineOut && !SkipFirst) strcpy(Sep," ") ;
					else Sep[0]= '\0' ;
				SkipFirst = 0 ;
				LineOut += Strlen(Word) + Strlen(Sep) ;
				if (LineOut > LineWidth) {
					Return = NewLine() ;
					if (!Return) return 0 ;
					LineOut = Strlen(Word) ;
					*out << Word ;
				} else *out << Sep << Word ;
				LastCharOut = Word[strlen(Word)-1] ;
				// TestAlloc("end loop body");
			}
		}
		// TestAlloc("before delete");
		delete Buf ;
		delete Word ;
		// TestAlloc("after delete");
	} else {
		*out << Sep << o ;
		LastCharOut = o[strlen(o)-1] ;
	}
	// TestAlloc("exit");
	return Return ;
}

int OutTokens::NextConcatCond(char C)
{
	if (C == LastCharOut) return 0 ;
	char Temp[2];
	Temp[0] = C ;
	Temp[1] = '\0' ;
	NextConcat(Temp) ;
	return 1 ;
}

int OutTokens::NextConcat(const char * o)
{
	int Return = 1;
	if (!o) o = "NULL!!" ;
	LineOut+= Strlen(o) ;
	*out << o ;
	LastCharOut = o[strlen(o)-1] ;
	return Return ;
}
void OutTokens::Flush()
{
	// LogOut << "out flush\n" ;
	if (out) if (out->good()) out->flush();
	// LogOut << "exit\n" ;
}

OutTokens::~OutTokens()
{
	Flush();
	delete TheToken ;
	delete Options;
}

void OutTokens::AllocateTheToken()
{
	char * Temp = new char[TokenBufSize];
	if (TheToken) {
		strcpy(Temp,TheToken) ;
		delete TheToken ;
	}
	else Temp[0] = '\0' ;
	TheToken = Temp ;
}

int OutTokens::NextConcatCondToken(char C)
{
	if (TheToken) if (TheToken[strlen(TheToken)-1] == C) return 0;
	char Temp[2];
	Temp[0] = C ;
	Temp[1] = '\0' ;
	NextConcatToken(Temp);
	return 1 ;
}

void OutTokens::NextConcatToken(const char * o)
{
	int Size = Strlen(o) + 1 ;
	if (TheToken) Size += Strlen(TheToken) ;
	if (Size >= TokenBufSize) {
		TokenBufSize = 80 + Size ;
		AllocateTheToken() ;
	}
	strcat(TheToken,o);
}

int OutTokens::NextOutToken(const char * o)
{
	int Return = 1 ;
	if (o) NextConcatToken(o);
	if (TheToken) if (TheToken[0]) {
		Return=NextOut(TheToken);
		TheToken[0] = '\0' ;	
	}
	return Return ;
}

static char NumBuf[80] ;

void OutTokens::NextConcatToken(int Val)
{
	sprintf(NumBuf,"%d",Val);
	NextConcatToken(NumBuf);
}

int OutTokens::NextOut(int Val)
{
	sprintf(NumBuf,"%d",Val);
	return NextOut(NumBuf);
}
	
int OutTokens::NextOut(double Val)
{
	sprintf(NumBuf,FloatFormat(Val),Val);
	return NextOut(NumBuf);
}

int OutTokens::NextConcat(int Val)
{
	sprintf(NumBuf,"%d",Val);
	return NextConcat(NumBuf);
}

int OutTokens::NextTeXttOut(const char * o)
{
	return NextTeXOut(o,"tt");
}

int OutTokens::NextTeXitOut(const char * o)
{
	return NextTeXOut(o,"it");
}

int OutTokens::NextTeXbfOut(const char * o)
{
	return NextTeXOut(o,"bf");
}

int OutTokens::NextTeXOut(const char * o)
{
	return NextOut(TranslateToTeX.DoTeXTranslate(o)) ;
}

int OutTokens::NextTeXOut(const char * o, const char * TeXType)
{
	NextConcatToken("{\\");
	NextOutToken(TeXType);
	NextConcatToken(TranslateToTeX.DoTeXTranslate(o)) ;
	return NextOutToken("}");
}


int OutTokens::TeXIndexEntry(const char * Name)
{
	NextConcatToken("\\index{");
	NextConcatToken(TeXString(Name));
	return NextOutToken("}");
}

