#include "ObjProGen/cpyrght_exe.h"
#include <fstream.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "stdyac.h"
#include "totex.h"
#include "strtlex.h"
#include "outfilnm.h"
#include "outtok.h"
#include "lexnum.h"
#include "linlist.h"
#include "table.h"
#include "textrans.h"
#include "mkstr.h"
#include "texutil.h"
#include "copyright.h"

static ofstream * OutFile ;
static OutTokens * OutTok ;

int CaptionOn = 0 ;

#ifndef YYDEBUG
int yydebug = 0 ;
#endif

int ListDepth = 0 ;
int InItem = 0 ;

const MaxDepth = 100 ;
const char * ListTypes [MaxDepth] ;

void ListTextLine(const char * Line)
{
	if (!ListDepth) {
		yyerror("list line not in list");
		exit(1);
	}
	if (!InItem)  {
		yyerror("list line not in item");
		exit(1);
	}
	OutTok->NextFillOut(Line);
}


void CheckEndLastItem()
{
	if (InItem) OutTok->NextConcat("}");
	InItem = 0 ;
}

void BeginListItem()
{
	CheckEndLastItem();
	OutTok->FlushLine();
	OutTok->NextFillOut("\\item{");
	InItem = 1 ;
}

void BeginList(const char * Type)
{
	CheckEndLastItem();
	if (ListDepth >= MaxDepth -2 ) {
		yyerror("lists nested too deply");
		exit(1);
	}
	ListTypes[ListDepth++] = Type ;
	OutTok->FlushLine();
	OutTok->NextConcatToken("\\begin{");
	OutTok->NextConcatToken(Type);
	OutTok->NextOutToken("}");
	OutTok->FlushLine();
}

void BeginLetteredList()
{
	BeginList("itemize");
}

void BeginNumberedList()
{
	BeginList("enumerate");
}

void EndList()
{
	CheckEndLastItem();
	OutTok->FlushLine();
	OutTok->NextConcatToken("\\end{");
	OutTok->NextConcatToken(ListTypes[--ListDepth]);
	OutTok->NextOutToken("}");
	OutTok->FlushLine();
}

void NewParagraph()
{
	OutTok->FlushLine();
	OutTok->NewLine();
}


void Section(int depth,const char* Title)
{
	int Depth = depth + 1 ; // format at a lower level for tex
	if (Depth >= MaxTeXSectionDepth()) {
		yyerror("section depth too large");
		exit(1);
	}
	OutTok->FlushLine();
	OutTok->NextConcatToken("\\");
	OutTok->NextConcatToken(GetTeXSectionName(Depth));
	OutTok->NextConcatToken("{");
	OutTok->NextOutToken(Title);
	OutTok->NextOutToken("}");
	OutTok->FlushLine();
	if (strlen(Title) < MaxTeXLengthToIndex) {
		OutTok->NextOutToken("\\index{");
		OutTok->NextOutToken(Title);
		OutTok->NextOutToken("}");
		OutTok->FlushLine();
	}
}

RoffTable * TheCurrentTable = 0;

void TableEnd()
{
	Dbg cerr << "TableEnd\n" ;
	if (!TheCurrentTable) {
		yyerror("not table to end");
		exit(1);
	}
	TheCurrentTable->EndOfTable();
	delete TheCurrentTable ;
	TheCurrentTable = 0 ;
}

void TableOptions(TableOptionSelect opt,const char* param)
{
	switch(opt) {
case TableOptionCenter:
		return ;
case TableOptionExpand:
case TableOptionBox:
case TableOptionAllBox:
case TableOptionDoubleBox:
case TableOptionTab:
case TableOptionLineSize:
case TableOptionDelim:
case TableOptionInvalid:
defsult:
		yyerror("Unsupported table option") ;
	}
	Dbg cerr << "TableOptions(,\"" << param << "\")\n" ;
}

void CheckTable(const char * Msg)
{
	if (!TheCurrentTable) {
		yyerror(Msg);
		exit(1);
	}
}

static const MaxTableSize = 100 ;
static int IndexTable[MaxTableSize] ;
int TableIndex = 0 ;

void ClearCaptionIndexTable()
{
	TableIndex = 0 ;
}
	
void IndexColumn(int index) 
{
	if (index < MaxTableSize -2) IndexTable[TableIndex++] = index;
}



void Caption(const char *Caption, const char * Lab)
{
	if (TheCurrentTable) {
		yyerror("caption occured while table active");
		return ;
	}
	TheCurrentTable = new RoffTable(*OutTok,Caption,Lab);
	for (int i = 0 ; i < TableIndex ; i++)
		TheCurrentTable->AddIndex(IndexTable[i]);
	TableIndex = 0 ;
}

TableOptionSelect ExpandOption(const char* option )
{
	if (!strcmp(option,"center")) return TableOptionCenter ;
	// cerr << "ExpandOptions(\"" << option << "\")\n" ;
	return TableOptionInvalid ; // none supported yet
}

void TableFormat(const char* format)
{
	Dbg cerr << "TableFormat`" << format << "'\n" ;
	if (!TheCurrentTable)
		TheCurrentTable = new RoffTable(*OutTok);
	TheCurrentTable->AddFormat(format);
}

void TableNewLine()
{
	Dbg cerr << "TableNewLine\n" ;
	CheckTable("end of table line and no table");
	TheCurrentTable->EndOfLine();
}

void TableEntry(const char* Entry)
{
	Dbg cerr << "TableEntry\n" ;
	CheckTable("table entry and no table");
	TheCurrentTable->NextEntry(Entry);
}

void FoundTab()
{
	CheckTable("tab in table and no table");
	TheCurrentTable->Tab();
}

void VerbatimLine(const char* Text)
{
	OutTok->FlushLine();
	OutTok->NextOut(Text);
	OutTok->FlushLine();
}

void EmptyVerbatim()
{
	OutTok->FlushLine();
	OutTok->NewLine();
	OutTok->FlushLine();
}

void FlushTextLine(const char* Text)
{
	OutTok->FlushLine();
	OutTok->NextOut(Text);
	OutTok->FlushLine();
}

void TextLine(const char* Text)
{
	OutTok->NextFillOut(Text);
}

void Verbatim(int Start)
{
	static int VerbatimOn = 0 ;
	if (VerbatimOn) if (Start) {
		yyerror(".NF occurs while previous .NF is active");
		return ;
	}
	if (!VerbatimOn) if (!Start) {
		yyerror(".FI occurs when fill is already active") ;
		return ;
	}
	OutTok->FlushLine();
	if (Start) OutTok->NextOut("\\begin{verbatim}");
	else OutTok->NextOut("\\end{verbatim}");
	OutTok->FlushLine();
	VerbatimOn = Start ;
}

void EmitEmbeddedReference(const char*,int)
{
	cerr << "EmitEmbeddedReference called.\n" ;
}

char SpellFileName[32] ; 


char * InputFileName = 0 ;



static void Usage(const char * Pgm)
{
	cerr << "Usage is: " << Pgm << " [-d] [-w dir] [-c] [-u] file\n" ;
	cerr << "`-d' specifes debugging mode.\n" ;
	cerr << "`file' is a roff input file.\n" ;
	cerr << "`-w dir' specified directory for output file.\n" ;
	cerr << "`-c' adds Mountain Math copyright notice.\n" ;
	cerr << "`-u' adds Mountain Math and user copyright notice.\n" ;
	cerr << "Suffix `.roff' will be appended to the name if missing.\n" ;
	exit (1);
}

main(int argc,char ** argv)
{
	int c;
	int errflg = 0;
	const char * OutputDirectory = 0;
	const char * OutputFileName = 0 ;
	int copyright = 0 ;
	int user_copyright = 0 ;

	while (( c = getopt(argc,argv,"cudw:")) != EOF) switch(c) {
case 'u':
		user_copyright = 1 ;
case 'c':
		copyright = 1 ;
		break ;
case 'd':
		yydebug= 1;
		break ;
case 'w':
		OutputDirectory = MakeLitString(optarg);
		break ;
default:
		errflg++;
		break ;
	}
	if (errflg) {
		cerr << "Invalid command line.\n" ;
		Usage(argv[0]);
	}
	int OneName = 0;
	for (; optind < argc; optind++) {
		if (OneName) {
			cerr << "Only one input file is allowed.\n" ;
			Usage(argv[0]);
		}
		OneName = 1;
		InputFileName = new char[strlen(argv[optind])+1];
		strcpy(InputFileName,argv[optind]);
		InputFileName = AddSuffix(InputFileName,".roff");
		FILE * Temp = freopen(InputFileName,"r",stdin);
		if (!Temp) {
			cerr << "Cannot open input file `" << InputFileName <<
				"'\n" ;
			exit(2);
		}
	}
	if (!InputFileName) Usage(argv[0]);
	CurrentFileName = InputFileName ;

	OutputFileName = AddSuffix(RemoveSuffix(InputFileName,".roff"),
		".tex");
	if (OutputDirectory) OutputFileName =
		ReplaceDirectory(OutputDirectory,OutputFileName);
	OutFile = new ofstream(OutputFileName);
	if (!OutFile->good()) {
		cerr << "Cannot create output file `" << OutputFileName
			<< "'.\n" ;
		Usage(argv[0]);
	}
	AddCopyright::add_copyright().write_short(*OutFile,OutputFileName,
		user_copyright); 
	OutTok = new OutTokens(OutFile,0,""," ","",60,1000000) ;

		
	
	int Success = ParseMain();
	OutTok->FlushLine();
	delete OutFile ;
	if (!Success) exit(1);
	exit(0);
}

