/*  gentex.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <fstream.h>
#include <stdlib.h>
#include "outtok.h"
#include "gentex.h"
#include "domknode.h"
#include "textfrag.h"
#include "nodeparm.h"
#include "outfilnm.h"
#include "member.h"
#include "debug.h"
#include "y.tab.h"
#include "ndconst.h"
#include "yacoper.h"
#include "texutil.h"
#include "mkstr.h"
#include "stdyc.h"
#include "opf.h"
#include "copyright.h"

TeXDocumentation * TheTeXDocumentation = 0 ;


TeXFile::TeXFile(const char * BaseName):
	FileName(Concatenate(BaseName,".tex")),
	Stream(OpenFile(FileName,"documentation")),
	Out(new OutTokens(&Stream,0,""," ","",80,1000000))
{
	AddCopyright& add = AddCopyright::add_copyright() ;
	add.write_short(Stream,FileName,user_copyright_flag,
		AddCopyright::created_by) ;
}

TeXFile::~TeXFile()
{
	// cerr << "TeXFile::dtor\n" ;
	Out->FlushLine();
	delete (char *) FileName ;
	delete (ostream *) &Stream ;
	// delete Out ;
	
}


TeXDocumentation::TeXDocumentation(const char * BaseName,const char * dir_name):
	Full(Concatenate(dir_name,"/",BaseName)),
	Short(Concatenate(dir_name,"s/",BaseName)),
	Out(Full.GetOut()),
	Ot(Short.GetOut()),
	MemberHeaderOut(0)
{
}

TeXDocumentation::~TeXDocumentation()
{
	// cerr << "TeXDocumentation::dtor\n" ;
}

void TeXDocumentation::OutNodeName()
{
	if (!NodeName) {
		cerr << "TeXDocumentation::OutNodeName no node name.\n" ;
		exit(1);
	}
	Out.NextTeXttOut(NodeName) ;

}

static void EmitMemberPreamble(OutTokens& Out)
{
	Out.NewLine();
	if (TheMemberFunctions->Size() == 1) Out.NextFillOut(
	"Following is the member function of this node.");
	else Out.NextFillOut(
	"Following are the member functions of this node.");
	Out.NewLine();
	Out.NewLine();
}

void TeXDocumentation::FoundMemberFunction(MemberFunction * TheMember)
{
	if (!MemberHeaderOut) {
		EmitMemberPreamble(Out);
		EmitMemberPreamble(Ot);
		MemberHeaderOut = 1 ;
	}
	TheMember->BriefOutTeX(Ot);
	TheMember->OutTeX(Out);
}


void TeXDocumentation::ShortFoundNode(NodeParameterList * TheNodeParameters,
	Description * Desc)
{
	Ot.NextConcatToken("\\subsubsection{");
	Ot.NextTeXttOut(NodeName);
	Ot.NextOutToken("}");
	Ot.TeXIndexEntry(NodeName);
	VSpace(Ot);

	Ot.NewLine();
	if (Desc->HelpLine) {
		Ot.NextOut("Synopsis:");
		Desc->HelpLine->OutTeXEndDot(Ot);
	} else Desc->Full->OutTeX(Ot);
	VSpace(Ot);
	
	if (!Desc->HelpLine) return ;

	int Size = TheNodeParameters->Size() ;
	if (Size) {
		Ot.NextOutToken("The parameter");
		if (Size > 1) Ot.NextConcat("s") ;
		Ot.NextOut("for");
		Ot.NextTeXttOut(NodeName);
		Ot.NextFillOut(Size == 1 ? "is:" : "are:");
		Ot.FlushLine();
		TheNodeParameters->BriefOutTeX(Ot);
	} else {
		Ot.NextFillOut("This node has no parameters.");
		Ot.FlushLine();
		Ot.NewLine() ;
	}
	
}

void TeXDocumentation::FoundNode(const char * node_name,
	NodeParameterList * TheNodeParameters, Description * Desc)
{
	NodeName = node_name ;
	ShortFoundNode(TheNodeParameters,Desc);

	Out.NextConcatToken("\\subsection{");
	OutNodeName();
	Out.NextOutToken("}");
	Ot.TeXIndexEntry(NodeName);
	Out.FlushLine();
	Out.NewLine();

	Out.NextConcatToken("\\markright{");
	OutNodeName();
	Out.NextOutToken("}");
	VSpace(Out);

	if (Desc->HelpLine) {
		Out.NextOut("Synopsis:");
		Desc->HelpLine->OutTeXEndDot(Out);
		VSpace(Out);
	}

	Desc->Full->OutTeX(Out);
	VSpace(Out);

	if (!Desc->HelpLine) return ;
	// Base function should not have any parameters
	
	int Size = TheNodeParameters->Size() ;
	if (Size) {
		Out.NextOutToken("The parameter");
		if (Size > 1) Out.NextConcat("s") ;
		Out.NextOut("for");
		OutNodeName();
		Out.NextFillOut(Size == 1 ? "is:" : "are:");
		Out.FlushLine();
		TheNodeParameters->OutTeX(Out) ;
	} else {
		Out.NextFillOut("This node has no parameters.");
		Out.FlushLine();
		Out.NewLine() ;
		Out.NewLine() ;
	}
}


int Compound::IsValueDefined()
{
	switch (Type) {
case TypeInt:
case TypeDouble:
case TypeString:
case TypeTerm:
		return 1 ;
case TypeName:
case TypeText:
case TypeCompound:
case TypeDescription:
case TypeSize:
case TypeParameter:
case TypeList:
case TypeParamFunc:
case TypeScaledType:
		break ;
	default :
		// cerr << "Compound::IsValueDefined bad type " << Type << "\n";
		// DbgError("QUITTING","now");
		break ;
	}
	return 0 ;
}

void Compound::TeXOutList(OutTokens& Out)
{
	Out.NewLine();
	Out.NewLine();
	Out.NextOut("\\begin{tabular}{rrrr}");
	Out.NewLine();
	CompoundList * TheList = Item.List ;
	CompoundListIterator Next(*TheList);
	Compound * OneElement ;
	int Count = 0 ;
	while (OneElement = Next()) {
		OneElement->TeXOut(Out,0) ;
		if (++Count >= 4) {
			Count = 0 ;
			Out.NextOut(" \\\\") ;
			Out.NewLine();
		} else Out.NextOut(" & ");
	}
	if (Count) Out.NextOut(" \\\\") ;
	Out.NewLine();
	Out.NextOut("\\end{tabular}");
	Out.NewLine();
	Out.NewLine();
}

void Compound::TeXOut(OutTokens& Out, int VarType)
{
/*
 *	cerr << "Compound::TeXOut VarType = " << VarType <<
 *		", Type = " << Type << "\n" ;
 */
	switch (Type) {
case TypeInt:
		Out.NextOut(Item.Int);
		return ;
case TypeDouble:
		Out.NextTeXOut(Item.Dbl->String);
		return ;
case TypeString:
		Out.NextTeXDblQuoteOut(Item.Str) ;
		return ;
case TypeTerm:
		if (!VarType) DbgError("Compound::TeXOut","VarType bad");
		Out.NextTeXOut(StringArrayBound(Item.Terminal,VarType));
		return ;
case TypeList:
		// List of values
		TeXOutList(Out);
		break ;
case TypeName:
case TypeText:
case TypeCompound:
case TypeDescription:
case TypeSize:
case TypeParameter:
case TypeParamFunc:
case TypeScaledType:
	default :
		cerr << "Compound::TeXOut bad type " << (int) Type << "\n";
		DbgError("QUITTING","now");
	}
}

const char * TeXOutType(NodeParameter * Param)
{
	const BufSize = 64 ;
	static char Buf[BufSize];
	const char * Base = "ERROR" ;
	if (Param->Type) Base = WhatTypeString(Param->Type->Type,
		DataDecType) ;
	else if (Param->ClassType) Base = Param->ClassType ;
	else CantContinue("TexOutType", "bad Param");
	if (strlen(Base) > BufSize - 4) DbgError("TeXOutType",
		"string too long");
	strcpy(Buf,Base);
	if (Param->Size || Param->ClassType) if (Param->Size) strcat(Buf,"*");
	if (*Buf) for (char * Pt = Buf+strlen(Buf)-1; Pt>=Buf;Pt--)
		if (*Pt == ' ') *Pt = '\0' ; else break ;
	return Buf ;
}

const char * StringArrayBound(int Terminal,int Type, int * no_scale)
{
	if (Terminal == MIN_POS) return "1" ;
	if (Terminal == MAX_NEG) return "-1" ;
	switch (Type) {
case SC_MACH_WORD:
		if (no_scale) *no_scale= 1 ;
case MACH_WORD:
		if (Terminal == MAX) return "DEF_MACH_WORD_MAX" ;
		if (Terminal == MIN) return "DEF_MACH_WORD_MIN" ;
	break ;
case ACC_MACH_WORD:
		if (Terminal == MAX) return "DEF_ACC_MACH_WORD_MAX" ;
		if (Terminal == MIN) return "DEF_ACC_MACH_WORD_MIN" ;
	break ;
case INT32:
		if (Terminal == MAX) return "2147483647" ;
		if (Terminal == MIN) return "-2147483647" ;
	break ;
case INT16:
		if (Terminal == MAX) return "32767" ;
		if (Terminal == MIN) return "-32767" ;
	break ;
case DOUBLE:
		// if (Terminal == MAX) return FloatFormat(DBL_MAX) ;
		// if (Terminal == MIN) return FloatFormat(DBL_MIN) ;
		if (Terminal == MAX) return LARGE_DOUBLE_STRING;
		if (Terminal == MIN) return LARGE_NEGATIVE_DOUBLE_STRING;
	break ;
default:
		cerr << "Bad type is " << Type << "\n" ;
		DbgError("StringArrayBound","bad Type");
	}
	DbgError("StringArrayBound","bad value");
	return "THIS IS NOT POSSIBLE" ;
}

void CantContinue(const char * Routine, const char * Msg)
{
	yyerror(Msg);
	DbgError(Routine,Msg);
}


