#include <stdlib.h>
#include "table.h"
#include "outtok.h"
#include "linlist.h"
#include "stdyac.h"
// #include "yacoper.h"

struct FormatTranslate {
	const char * Roff ;
	char TeX ;
	int Translate(char C);
} ;

int FormatTranslate::Translate(char C)
{
	for (const char * CharCk = Roff; *CharCk; CharCk++)
		if (C == *CharCk) return TeX ;
	return -1 ;
}

static FormatTranslate LocTheFormatTranslations[] = {
	{"lL",'l'},
	{"rR",'r'},
	{"cC",'c'},
	{"nN",'\0'},
	{"aA",'\0'},
	{"sS",'\0'},
	{0,0}
};


RoffTable::RoffTable(OutTokens& out, const char * caption,
	const char * lab):
	Caption(caption),
	Label(lab),
	Options(0),
	Format(0),
	Items(0),
	ItemCount(0),
	ItemIndex(0),
	TheFormatTranslations(LocTheFormatTranslations),
	SaveIndex(0),
	Out(out)
{
}

void RoffTable::Vspace()
{
	Out.FlushLine();
	Out.NewLine();
	Out.NextOut("\\vspace{.1in}");
	Out.FlushLine();
	Out.NewLine();
}

RoffTable::~RoffTable()
{
	delete Options ;
	delete (char*) Format ;
	delete Items ;
}


int RoffTable::CheckIndex(int Index)
{
	if (Index >= ItemCount) {
		cerr << "RoffTable::CheckIndex overflow\n" ;
		exit(1);
	}
	return Index ;
}

const char * RoffTable::ConvertFormat()
{
	static const char Default = 'c' ;
	char * Conversion = new char[ItemCount+1];
	int Index = 0 ;
	FormatTranslate * Ck ;
	if (!Format) {
		cerr << "ConverFormat none\n" ;
		exit(1);
	}
	for (const char * F = Format ; *F; F++) {
		for (Ck = TheFormatTranslations ; Ck->Roff; Ck++) {
			int Translation = Ck->Translate(*F) ;
			if (Translation < 0) continue ;
			if (!Translation) {
				yyerror("unsupported format character");
				Translation = Default ;
			} 
			Conversion[CheckIndex(Index++)] =  Translation ;
			break ;
		}
		if (!Ck->Roff) {
			cerr << "Unknown character is `" << *F <<
				"'.\n'" ;
			cerr  << "Format is `" << Format << "'.\n" ;
			yyerror("unknow format character");
			Conversion[CheckIndex(Index++)] = Default ;
		}
	}
	if (Index != ItemCount) {
		yyerror("format string too short");
		while (Index < ItemCount)
			Conversion[CheckIndex(Index++)] = Default ;
	}
	Conversion[ItemCount] = '\0' ;
	return Conversion ;
}

void RoffTable::AddIndex(int index)
{
	if (SaveIndex < SaveIndexingSize) SaveIndexing[SaveIndex++]=index ;
}

int RoffTable::IndexThisItem()
{
	// 0 Table entry indicates entire table other wise
	// otherwise online columns specifed (if negative use tt format)
	if (!LineCount) return 0 ;

	for (int i = 0 ; i < SaveIndex;i++) {
		if (!SaveIndexing[i]) return 1 ;
		int Check = ItemIndex + 1 ;
		if (SaveIndexing[i] == Check) return 1 ;
		if (SaveIndexing[i] == -Check) return -1 ;
	}
	return 0 ;
}

void RoffTable::AddOption(const char * option)
{
	AddToList(option, (void **)Options);
}

void RoffTable::AddFormat(const char * format)
{
	if (Format) {
		yyerror("two table format lines");
		return ;
	}
	int Length = strlen(format) ;
	if (format[Length-1] == '.') {
		char * Temp = new char[Length];
		strncpy(Temp,format,Length-1);
		Temp[Length-1] = '\0' ;
		delete (char *) format ;
		format = Temp ;
	} else yyerror("format not ended with `.'");
	Format = format ;
	Init();
	const char * LaTeXFormat = ConvertFormat();
	if (!Caption) Vspace(); else {
		Out.FlushLine();
		Out.NextOut("\\begin{table}");
		Out.NewLine();
	}
	Out.NextOut("\\begin{center}");
	Out.NewLine();
	Out.NextConcatToken("\\begin{tabular}{|");
	Out.NextConcatToken(LaTeXFormat);
	Out.NextOutToken("|} \\hline");
	Out.FlushLine();
	LineCount = 0 ;
}
void RoffTable::ClearItems()
{
	for (int i = 0 ; i < ItemCount;i++) Items[i] = 0 ;
	ItemIndex = 0 ;
}

void RoffTable::Init()
{
	if(!Format) {
		yyerror("table format missing");
		exit(1);
	}	
	ItemCount = strlen(Format);
	if (!ItemCount) {
		yyerror("format with no entries");
		exit(1);
	}
	Items = new char * [ItemCount] ;
	ClearItems();
	ItemIndex = 0 ;
}

void RoffTable::NextEntry(const char * Entry)
{
	if (ItemIndex >= ItemCount) {
		cerr << "Index = " << ItemIndex << ", Count = " <<
			ItemCount << "\n" ;
		yyerror("too many table entrys");
		exit(1);
	}
	if (Items[ItemIndex]) {
		yyerror("two items with no separator");
		exit(1);
	}
	Items[ItemIndex] = Entry ;
}

void RoffTable::Tab()
{
	ItemIndex++;
}

static void IndexOut(OutTokens& Out,const char * Text)
{
	Out.NextConcatToken("\\Index{");
	Out.NextConcatToken(Text);
	Out.NextOutToken("}");
}

static void IndexttOut(OutTokens& Out,const char * Text)
{
	Out.NextConcatToken("\\DppNm{");
	Out.NextConcatToken(Text);
	Out.NextOutToken("}");
}

void RoffTable::EndOfLine()
{
	for (ItemIndex = 0 ; ItemIndex < ItemCount ; ItemIndex++)
		if (Items[ItemIndex]) break ;
	if (ItemIndex == ItemCount) return ;
	for (ItemIndex = 0 ; ItemIndex < ItemCount ; ItemIndex++) {
		if (ItemIndex) Out.NextOut("&");
		if (Items[ItemIndex]) {
			int Ck = IndexThisItem() ;
			if (!Ck) Out.NextFillOut(Items[ItemIndex]);
			else if (Ck> 0) IndexOut(Out,Items[ItemIndex]);
			else IndexttOut(Out,Items[ItemIndex]);
		}	
	}
	Out.NextOut("\\\\");
	if (!LineCount++) Out.NextOut("\\hline");
	Out.NewLine();
	ClearItems();
}

void RoffTable::EndOfTable()
{
	EndOfLine();
	Out.NextOut("\\hline");
	Out.FlushLine();
	Out.NextOut("\\end{tabular}");
	Out.NewLine();
	Out.NextOut("\\end{center}");
	if (Caption) {
		Out.NewLine();
		Out.NextConcatToken("\\caption{");
		Out.NextConcatToken(Caption);
		Out.NextOutToken("}");
		if (Label) {
			Out.FlushLine();
			Out.NextConcatToken("\\label{");
			Out.NextConcatToken(Label);
			Out.NextOutToken("}");
			Out.FlushLine();
			Out.NextOut("\\end{table}");
		}
		Out.FlushLine();
	} else Vspace();
}


