/*  parammen.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <stdlib.h>
#include <string.h>
#include "lexnum.h"
#include "stdyacp.h"
#include "yacio.h"
#include "domenus.h"
#include "menustr.h"
#include "parammen.h"
#include "menuprsl.h"
#include "menuprsy.h"
#include "debug.h"
#include "inconce.h"
#include "classrel.h"
#include "cgidbg.h"
#include "mkstr.h"
#include "sysconst.h"


ParameterizedAction::ParameterizedAction(const char * name,
	CompoundList * list, int index, int wait):
	Name(name),
	List(list),
	ParameterSequenceIndex(index),
	RemoteName(0),
	wait_flag(wait)
{
/*
 *	if (wait_flag) cerr << "ParameterizedAction::ParameterizedAction for `"
 *		<< name << "',\n this = " << (void *) this << " is wait.\n" ;
 *	else cerr << "ParameterizedAction::ParameterizedAction for `"
 *		<< name << "',\n this = " << (void *) this << "\n" ;
 */
}

void ParameterizedActionList::CheckAndAppend(ParameterizedAction * nt)
{
	ParameterizedActionListIterator Next(*this);
	ParameterizedAction * Check ;
	while (Check = Next()) if (!strcmp(nt->Name,Check->Name)) {
		if (nt->ParameterSequenceIndex != Check->ParameterSequenceIndex)
			cerr << "Action routine `" << nt->Name <<
			"'is used with two different parameter sequences.\n" ;
		return ;
	}
	Append(nt);
}


void FoundInt(int)
{
}


struct Double * MakeDouble(const char * text)
{
	return new Double(FloatConvert(text),MakeLitString(text));
}

int ValidParameterType(int Type)
{
	switch(Type) {
case TypeInt:
case TypeDouble:
case TypeString:
case TypeStackIndex:
		return 1;
case TypeName:
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeScaledType:
case TypeParameterizedAction:
		cerr << "Bad type is " << Type << ".\n";
		return 0;
	}
	return 0 ;
}

Compound * MakeParameterList(Compound *Cm, Compound * Cmp)
{
	CompoundList * TheList;
	if (!Cm) TheList = new CompoundList ;
	else if (Cmp) {
		if (Cm->Type != TypeList) DbgError("MakeParemeterList",
			"bad first parameter expecting List");
		TheList = Cm->Item.List ;
		if (!ValidParameterType(Cmp->Type)) DbgError(
			"MakeParameterList", "bad second parameter");
		TheList->Append(Cmp);
	} else {
		if (!ValidParameterType(Cm->Type))
			DbgError("MakeParameterList",
			"bad first parameter expecting Tree");
		TheList = new CompoundList ;
		TheList->Append(Cm);
	}
	return new Compound(TypeList, *(new Object(TheList)));
}


Compound * MakeParameter(const char * String)
{
	return new Compound(TypeString, *(new Object(String)));
}



Compound * MakeStackParameter(int Index)
{
	return new Compound(TypeStackIndex, *(new Object(Index)));
}



Compound * MakeNumber(int Val)
{
	return new Compound(TypeInt, *(new Object(Val)));
}


Compound * MakeNumber(Double *dbl)
{
	return new Compound(TypeDouble, *(new Object(dbl)));
}



Compound * MakeNegNumber(int Val)
{
	return new Compound(TypeInt, *(new Object(-Val)));
}


Compound * MakeNegNumber(Double * dbl)
{
	dbl->DblValue = -dbl->DblValue ;
	char * str = new char [strlen(dbl->String)+1];
	strcpy(str,"-");
	strcat(str,dbl->String);
	delete (char *) dbl->String ;
	dbl->String = str ;
	return new Compound(TypeDouble, *(new Object(dbl)));
}

class ParameterSequence{
	int Size ;
	ItemType * Sequence ;
	int Index ;
public:
	ParameterSequence(int index, CompoundList * list=0) ;
	ParameterSequence(int index, int size) ;
	int GetSize() {return Size;}
	void SetItem(int i, ItemType item) {Sequence[i]=item;}
	ItemType GetItem(int i) {return Sequence[i];}
	int IsSame(CompoundList * list);
	int GetIndex() {return Index;}
	int OutParams(ostream& out, ostream * table);
};



ParameterSequence::ParameterSequence(int index, CompoundList * list)
{
	Index = index ;
	Size = list->Size();
	Sequence = new ItemType[Size];
	Compound * Entry ;
	CompoundListIterator Next(*list);
	int i = 0;
	while (Entry = Next()) Sequence[i++] = Entry->Type ;
}

ParameterSequence::ParameterSequence(int index, int size)
{	
	Index = index ;
	Size=size;
	Sequence = new ItemType[Size];
}

class ParameterSequenceList: public SingleList {
public:
	ErrCode Insert(ParameterSequence * nt) {return SingleList::Insert(nt);}
	ErrCode Append(ParameterSequence * nt) {return SingleList::Append(nt);}
	ParameterSequence * Get()
		{return (ParameterSequence *) SingleList::Get();}
	ParameterSequenceList(){;}
	int Size(){return SingleList::Size();}
	int GetIndex(CompoundList * list);
} ;

class ParameterSequenceListIterator: public SingleListIterator {
public:
	ParameterSequenceListIterator(ParameterSequenceList& df):
		SingleListIterator((SingleList&) df){}
	ParameterSequence * operator()()
		{return (ParameterSequence *) Next();}
};

int ParameterSequenceList::GetIndex(CompoundList * list)
{
	ParameterSequence * Check ;
	ParameterSequenceListIterator Next(*this);
	while (Check = Next()) if (Check->IsSame(list))
		return Check->GetIndex();
	Check = new ParameterSequence(Size(),list) ;
	Append(Check);
	return Check->GetIndex() ;
}

ParameterSequenceList TheActionParameters ;

int ParameterSequence::IsSame(CompoundList * list)
{
	Compound * Entry ;
	CompoundListIterator Next(*list);
	int i = 0;
	while (Entry = Next()) if(Sequence[i++] != Entry->Type) return 0;
	return i == Size ;
}


Value * MakeMenuInit(Compound * InitCall,int type) 
{
	if (InitCall->Type != TypeParameterizedAction)
		DbgError("MakeMenuInit","bad type for InitCall");
	InitValue * Ini = new InitValue(type,InitCall->Item.Action);
	// delete Name ;
	return new Value(Ini);
}

const char *OperConvert(const char * Name) ;

static int MakeActionNameElement(Compound * cmp, char * Where)
{
	const char * String ;
	char buf[32] ;
	switch (cmp->Type) {
case TypeInt:
		sprintf(buf,"%d",cmp->Item.Int);
		String = buf ; 
		break ;
case TypeDouble:
		// if (cmp->Item.Dbl) String = "FLOAT" ;
		String = "FLOAT" ;
		break ;
case TypeName:
case TypeString:
		String = OperConvert(cmp->Item.Str) ;
		break ;
case TypeStackIndex:
		String= "STACK" ;
		break ;
case TypeParameterizedAction: 
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeScaledType:
default:
		DbgError("MakeActionNameElement", "Invalid type");

	}
	int Return = strlen(String) + 1 ;
	if (Where)  {
		strcat(Where,"_");
		strcat(Where,String);
	}
	return Return ;
}

static const char * NameTable[][2] = {
	{">>","RightShift_Op"},
	{"<<","LeftShift_Op"},
	{"*","Multiply_Op"},
	{"/","Divide_Op"},
	{"+","Add_Op"},
	{"-","Subtract_Op"},
	{"&","And_Op"},
	{"|","And_Op"},
	{">","GreaterThan_Op"},
	{"<","LessThan_Op"},
	{"=","Equal_Op"},
	{">=","GreaterEqual_Op"},
	{"<=","LessEqual_Op"},
	{"==","LogicalEqual_Op"},
	{"&&","LogicalAnd_Op"},
	{"||","LogicalOr_Op"},
	{0,0}
};
	

static const char *OperTable(const char * Oper)
{
	for (int i = 0; NameTable[i][0];i++) 
		if (!strcmp(NameTable[i][0],Oper)) return
			NameTable[i][1];
	DbgError("OperTable unknown operator",Oper);
	return 0;
}

const char *OperConvert(const char * Name)
{
	// cout << "OperConvert(" << Name << ")\n" ;
	const char * Oper  = "operator" ;
	int OperLength = strlen(Oper);
	if (strncmp(Name,Oper,OperLength)) return Name ;
	return OperTable(Name+OperLength) ;
}

	
// Make a unique name based on parameter values
void ParameterizedAction::MakeCompoundName()
{
	RemoteName = Name ;
	const char * LocName = Name;
	if (!GetList()->Size()) return ;
	int Length = strlen(LocName)+2;
	CompoundListIterator Next(*(GetList()));
	Compound * cmp ;
	while (cmp = Next()) Length+=MakeActionNameElement(cmp,0);
	CompoundListIterator Next2(*(GetList()));
	char * Result = new char [Length];
	strcpy (Result,LocName);
	strcat (Result,"_");
	Name = Result ;
	while (cmp = Next2()) MakeActionNameElement(cmp,Result);
}
	
	


Value * FoundMenuItem(Value *Cmd,Compound *Act,Value *Typ,
	const char * HelpReference, Value *Init, Value *Str,
	TextFragmentList * Help, const char * HelpFileName) 
{
	if (HelpReference) if (Help) {
		cerr << "There is both a reference to predefined help text\n" <<
			"and actual help text in the definition of `" <<
			Cmd->Name << "'" ;
		OutWhereEnd();
		cerr <<	"The reference will be ignored.\n" ;
		delete (char *) HelpReference ;
		HelpReference = 0;
	} else {
		TheDefinedHelpReferences.Append(HelpReference);
		const char * Temp = MakeHelpTextName(HelpReference);
		HelpReference = Temp ;
	}
	if(!Act) DbgError("FoundMenuItem","NULL Act");
	if (Act->Type != TypeParameterizedAction)
		DbgError("FoundMenuItem", "bad type for Act");
	ParameterizedAction * TheAction = Act->Item.Action ;
	TheAction->MakeCompoundName();

	if (Typ->Token == HELP_FILE) {

		if (!strcmp(Cmd->Name,"help"))
			FoundHelpDefaultFile(TheAction->Name);

	    NewHelpFileName(TheAction->Name) ;
	    if (HelpFileName) {
		cerr << "Help file specified twice for menu choice\n`" <<
			Cmd->Name ;
		cerr << "'" ;
		OutWhereEnd();
		cerr << "The second specification will be ignored.\n" ;
		delete (char *) HelpFileName ;
		HelpFileName = 0 ;
	    }
	} else if (!HelpFileName) {
			*Herr << "No help file specifed for menu choice\n\t`" <<
				Cmd->Name ;
			*Herr << "'" ;
			OutWhereEnd(*Herr);
	}
	if (HelpFileName) NewHelpFileName(HelpFileName) ;
	if (!TempCmdList) TempCmdList = new ConstStringList ;
	TempCmdList->Append(Cmd->Name) ;
	const char * InitName = 0;
	HelpText * HelpList = MakeHelpList(Help);
	int InitValue = 0;
	ParameterizedAction * ActInit = 0;
	if (Init) if (Init->Init) {
		InitName = Init->Init->Action->Name ;
		InitValue = Init->Init->Type ;
		ActInit = Init->Init->Action ;
		// test to see if init is used
		// cerr << "Init " << InitName << "\n" ;
		// exit(1);
	}
	MenuItem * Item = new MenuItem(Cmd->Name,TheAction,
		Typ->Token, ActInit, InitValue,Str->Name,HelpReference,
			HelpList, HelpFileName) ;
/*
	delete Cmd ;
	delete Act ;
	delete Typ ;
	delete Init->Init ;
	delete Init ;
	delete Str ;
*/
	return new Value (Item) ;
}

const char * Template = "#TEMPLATE#" ;

Value * FoundItemTemplate(Compound *Act,Value *Typ,
	const char * HelpReference, Value *Init, Value *Str,
	TextFragmentList * Help, const char * HelpFileName) 
{
	if (HelpReference) if (Help) {
		cerr << "There is both a reference to predefined help text\n" <<
			"and actual help text in the menu item template " ;
		OutWhereEnd();
		cerr << "The reference will be ignored.\n" ;
		delete (char *) HelpReference ;
		HelpReference = 0;
	} else {
		TheDefinedHelpReferences.Append(HelpReference);
		const char * Temp = MakeHelpTextName(HelpReference);
		HelpReference = Temp ;
	}
	if(!Act) DbgError("FoundItemTemplate","NULL Act");
	if (Act->Type != TypeParameterizedAction)
		DbgError("FoundItemTemplate", "bad type for Act");
	ParameterizedAction * TheAction = Act->Item.Action ;
	if (Typ->Token == HELP_FILE) {
	    NewHelpFileName(TheAction->Name) ;
	    if (HelpFileName) {
		cerr << "Help file specified twice for menu item template\n\t" ;
		OutWhereEnd();
		cerr << "The second specification will be ignored.\n" ;
		delete (char *) HelpFileName ;
		HelpFileName = 0 ;
	    }
	}
	/**********
     * 	else if (!HelpFileName) {
	 *	*Herr << "No help file specifed for menu item template\n\t" ;
	 *	OutWhereEnd(*Herr);
	 * }
	 **********/
	if (HelpFileName) NewHelpFileName(HelpFileName) ;
	const char * InitName = 0;
	HelpText * HelpList = MakeHelpList(Help);
	int InitValue = 0;
	ParameterizedAction * ActInit = 0;
	if (Init) if (Init->Init) {
		InitName = Init->Init->Action->Name ;
		InitValue = Init->Init->Type ;
		ActInit = Init->Init->Action ;
	}

	MenuItem * Item = new
		MenuItem(Template,TheAction,Typ->Token,ActInit,
			InitValue, Str->Name,HelpReference,HelpList,
			HelpFileName) ;
/*
	delete Cmd ;
	delete Act ;
	delete Typ ;
	delete Init->Init ;
	delete Init ;
	delete Str ;
*/
	return new Value (Item) ;

}

Compound * MakeActionValue(const char * Name, CompoundList * List,int wait)
{
	// if (wait) cerr << "MakeActionValue wait\n" ;
	if (!List) List = new CompoundList ;
	return new Compound(TypeParameterizedAction,
		* (new Object (new ParameterizedAction(Name,List,
		TheActionParameters.GetIndex(List),wait))));
}

Compound * MakeActionValue(Value * Name, Compound * Param,int wait )
{
	// cerr << "MakeActionValue\n" ;
	if (!Param) DbgError("MakeActionValue","bad Param");
	if (Param->Type != TypeList) DbgError("MakeActionValue","bad Param");
	// cerr << "MakeActionValue returning\n" ;
	return MakeActionValue(Name->Name, Param->Item.List,wait);
}


void OutDeclaration(ostream& out, ParameterizedAction * Act)
{

}

void OutPhony(ostream& out, ParameterizedAction * Act)
{

}

const char * OutParamValue(Compound * param)
{
	const BufSize = 64;
	const char * GetStack = "GetMenuStackName(" ;
	static char Buf[BufSize];
	char buf[32] ;
	const char * Val ;
	switch(param->Type) {
case TypeInt:
		sprintf(Buf,"%d",param->Item.Int);
		return Buf ;
case TypeDouble:
		return param->Item.Dbl->String ;
case TypeString:
		return param->Item.Str;
case TypeStackIndex:
		sprintf(buf,"%d",param->Item.Int);
		if (strlen(buf) + strlen(GetStack) + 2 > BufSize)
			DbgError("OutParamValue","BufSize too small");
		strcpy(Buf,GetStack);
		strcat(Buf,buf);
		return strcat(Buf,")");
case TypeName:
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeScaledType:
case TypeParameterizedAction:
		cerr << "Bad type is " << (int) param->Type << ".\n";
		DbgError("OutParamValue","bad type");
	}
	return  0 ;
}

void OutCallRoutine(ostream& out, ParameterizedAction * Act)
{
	int CharNext = strlen(Act->GetName()) + 8;
	out << "\t" << Act->GetName() << "(" ;
	CompoundListIterator Next(*(Act->GetList()));
	Compound * Param ;
	int FirstTime = 1;
	while (Param = Next()) {
		if (!FirstTime) out << ", " ;
		CharNext += 2;
		const char * String = OutParamValue(Param);
		CharNext += strlen(String);
		if (CharNext > 72) {
			CharNext = 16 + strlen(String);
			out << "\n\t\t";
		}
		out << String ;
	}
	out << ");\n" ;
}

static void AddParameter(ostream& out, int& CharCount,int Index,
	const char * ref, const char * tail)
{
	char Buf[64];
	sprintf(Buf,"%d",Index);
	// LogOut << "Length of Buf = " << strlen(Buf) << "\n" ;
	int NewSpace = strlen(Buf) + strlen(ref) + strlen(tail) ;
	CharCount += NewSpace ;
	if (CharCount > 75) {
		out << "\n\t\t\t" ;
		CharCount = NewSpace + 24 ;
	}
	out << ref << Buf << tail ;
	// LogOut << ref << Buf << tail << "\n" ;

}


int ParameterSequence::OutParams(ostream& out, ostream * OutTable)
{
	out << "case " << Index << ":\n\t\tTheCall(" ;
	int CharCount = 24;
	int IntCount, FloatCount, StringCount, StackCount;
	IntCount = FloatCount = StringCount = StackCount = 0;
	for (int k = 0 ; k < Size; k++) {
		if (k) {
			out << ", " ;
			CharCount+=2;
		}
		switch (Sequence[k]) {
case TypeInt:
			AddParameter(out,CharCount,IntCount++,
				"Params->IntParameters[","]");
			break ;
case TypeDouble:
			AddParameter(out,CharCount,FloatCount++,
				"Params->FloatParameters[","]");
			break ;
case TypeString:
			AddParameter(out,CharCount,StringCount++,
				"Params->StringParameters[","]");
			break ;
case TypeStackIndex:
			AddParameter(out,CharCount,StackCount++,
				"GetMenuStackName(Params->StackParameters[",
				"])");
			break ;
case TypeName:
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeScaledType:
case TypeParameterizedAction:
			cerr << "Bad type is " << (int) Sequence[k] << ".\n";
			DbgError("ParameterSequence::OutParams","bad type");
		}
	}
	out << ");\n\t\tbreak;\n" ;

	if (OutTable) *OutTable << "{" << IntCount << ", " << StringCount
		<< ", " << FloatCount << ", " << StackCount << "}" ;
	return Index ;
}

static void OutFunctionNames(ostream& out,
	ParameterizedActionList ** AllFunctions)
{
	static const char * Cast = "(ParameterizedActionCall) " ;
	int CastLength = strlen(Cast);
	out << "ParameterizedActionCall AllActions[] = {\n\t" ;
	int CharCount = 8;
	int FirstTime = 1;
	for(;*AllFunctions;AllFunctions++) {
		ParameterizedActionListIterator Next(**AllFunctions);
		ParameterizedAction * act ;
		while (act = Next()) {
			const char * Nm = act->GetRemoteName();
			if (!Nm) Nm = act->GetName();
			if (FirstTime) FirstTime = 0;
			else {
				out << ", " ;
				CharCount+=2 ;
			}
			CharCount += strlen(Nm) + CastLength;
			if (CharCount > 75) {
				out << "\n\t" ;
				CharCount = 8 + strlen(Nm) +
					CastLength ;
			}
			out << Cast << Nm;	
		}
	}
	out << "\n};\n\n" ;
}


static void FunctionParamPrototypeOut(ostream& out, CompoundList * List,
	int CharCount)
{
	CompoundListIterator Next(*List);
	Compound * Param ;
	int FirstTime = 1;
	while (Param = Next()) {
		const char * Decl ;
		if (FirstTime) FirstTime = 0;
		else {
			out << ", " ;
			CharCount += 2;
		}
		switch (Param->Type) {
case TypeInt:
			Decl = "int" ;
			break ;
case TypeDouble:
			Decl = "double" ;
			break ;
case TypeString:
case TypeStackIndex:
			Decl = "const char *" ;
			break ;
case TypeName:
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeScaledType:
case TypeParameterizedAction:
			cerr << "Bad type is " << (int) Param->Type << ".\n";
			DbgError("FunctionParamPrototypeOut","bad type");
		}
		CharCount += strlen(Decl);
		if (CharCount > 75) {
			out << "\n\t" ;
			CharCount += 8 + strlen(Decl);
		}
		out << Decl ;
	}
}


static void OutFunctionPrototypes(ostream& out,
	ParameterizedActionList ** AllFunctions)
{
	for (;*AllFunctions;AllFunctions++) {
		ParameterizedActionListIterator Next(**AllFunctions);
		ParameterizedAction * act ;
		while (act = Next()) {
			const char * Name = act->GetRemoteName();
			if (!Name) Name = act->GetName();
			out << "void " << Name << "(" ;
			int CharCount = 6 + strlen(Name) ;
			FunctionParamPrototypeOut(out,act->GetList(),CharCount);
			out << ");\n" ;
		}
	}
}


static void OutExe(ostream & ExeParam,int RemoteFlag =0,
	ParameterizedActionList ** AllFunctions=0)
{
	if (RemoteFlag) {
		ExeParam << "#include \"menucmdd.h\"\n" ;
	} else {
		ExeParam << "#include \"menucmdg.h\"\n" ;
		ExeParam << "#include \"remparm.h\"\n\n" ;
		ExeParam << "#include \"locphony.h\"\n\n" ;
	}
	ExeParam << "#include \"defined.h\"\n" ;
	
	// MenuDriver << "ExecuteCmd Master;\n\n" ;
	ExeParam << "void ExecuteCmd" ;
	if (RemoteFlag) ExeParam << "Dsp" ;
	else ExeParam << "Gui" ;
	ExeParam << "::DoCall()\n{\n" <<
		"\tswitch(Params->ParameterType) {\n" ;
	
	ParameterSequenceListIterator Next(TheActionParameters);
	ParameterSequence * Sequence ;
	int Count = 0;
	ostream * ParamTable = 0;
	if (RemoteFlag) {
		const char * FileName = "tremfnc.h";
		ParamTable = OpenFile("tremfnc.h");
		IncludeOnce(ParamTable,FileName);

		if (!ParamTable) DbgError("OutExe","can't create tab");
		*ParamTable << "#include\"menucmd.h\"\n" <<
			"ParameterLimits RemoteParamLimits[] = {\n\t" ;
	}
	int FirstTime = 1 ;
	while (Sequence = Next()) {
		if (FirstTime) FirstTime = 0 ;
		else if (ParamTable) *ParamTable << ",\n\t" ;
		if (Count++ != Sequence->OutParams(ExeParam, ParamTable))
			DbgError("OutExe","bad sequence");
	}
	if (ParamTable) *ParamTable << "\n};\n\n"  ;
	ExeParam << "\n\t}\n}\n\n" ;
	OutFunctionNames(ExeParam, AllFunctions);
	OutFunctionPrototypes(ExeParam, AllFunctions);
	ostream * Temp = &ExeParam ;
	if (Temp) Temp->flush();
	delete  Temp ;
	IncludeOnce(ParamTable);
	if (ParamTable) ParamTable->flush();
	delete ParamTable ;
}

void OutMasterCall(ParameterizedActionList ** AllFunctions, int RemoteFlag)
{
// Outputs prototype declarations for all functions - to be checked against
// Function header routines - these prototypes occur after each function usage
// to insure that the function definition is NOT missing

	ostream * temp = 0 ;
	char * exeparamd = Concatenate("exeparamd",CPP_SUFFIX);
	char * exeparam = Concatenate("exeparam",CPP_SUFFIX);
	if (RemoteFlag) OutExe(*(temp=OpenRemFile(exeparamd)),RemoteFlag,
		AllFunctions);
	else OutExe(*(temp = OpenLocFile(exeparam)),0,AllFunctions);
	delete exeparam ;
	delete exeparamd ;
}


struct ParamDesc {
	ItemType Type ;
	const char * TypeDec;
	const char * Suffix ;
	int Count ;
	void CondOutName(ostream& out, const char * Base,int& CharCount);
	void OutDefinition(ostream& out, ParameterizedAction * act);
	void OutValue(ostream& out, Compound * Item, int& CharCount);
	int NoParamsThisType(CompoundList * List) ;
};

int ParamDesc::NoParamsThisType(CompoundList * List)
{
	CompoundListIterator Next(*List);
	Compound * Cmp ;
	while (Cmp = Next()) if (Cmp->Type == Type) return 0;
	return 1;
}


void ParamDesc::OutDefinition(ostream& out, ParameterizedAction * act)
{
	Count = 0;
	if (NoParamsThisType(act->GetList())) return ;
	const char * Base = act->GetName();
	out << TypeDec << Base << Suffix << "[] = {\n\t" ;
	CompoundListIterator Next(*(act->GetList()));
	Compound * Cmp ;
	int FirstTime = 1;
	int CharCount = 8;
	while (Cmp = Next()) {
		if (Cmp->Type != Type) continue ;
		Count++;
		if (FirstTime) FirstTime = 0 ;
		else {
			out << ", " ;
			CharCount += 2;
		}
		OutValue(out,Cmp,CharCount);
	}
	out << "\n};\n\n" ;
}

void ParamDesc::OutValue(ostream& out, Compound * Item,int& CharCount)
{
char Buf[64];
const char * Val ;
	int QuoteFlag = 0;
	switch (Item->Type) {
case TypeStackIndex:
case TypeInt:
		sprintf(Buf,"%d",Item->Item.Int);
		Val = Buf ;
		break ;
case TypeDouble:
		Val = Item->Item.Dbl->String;
		break ;
case TypeString:
		Val = Item->Item.Str ;
		QuoteFlag = 1;
		break ;
default:
		DbgError("ParamDesc::OutValue","bad type");
	}
	CharCount += strlen(Val) + QuoteFlag * 2 ;
	if (CharCount > 70) {
		out << "\n\t" ;
		CharCount = 8 + strlen(Val) + QuoteFlag * 2 ;
	}
	if (QuoteFlag) out << "\"" <<  Val << "\"" ;
	else out << Val ;
}


void ParamDesc::CondOutName(ostream& out, const char * Base, int& CharCount)
{
	out << ", " ;
	int Length = Count ? strlen(Base) : 1 ;
	CharCount += 2 + Length ;
	if (CharCount > 75) {
		out << "\n\t" ;
		CharCount = 8 + Length ;
	}
	if (Count) out << Base << Suffix ;
	else out << "0" ;
}


static ParamDesc ParamOpts[] = {
	{TypeInt,	"int ",		"_Int_Params",		0},
	{TypeString,	"char * ",	"_String_Params",	0},
	{TypeDouble,	"double ",	"_Float_Params",	0},
	{TypeStackIndex,"int ",		"_Stack_Params",	0}
};


static void OutMenuCallDefs(ostream& out,
	ParameterizedActionList ** AllFunctions, int RemoteFlag)
{
	int Index = 0 ;
	for (;*AllFunctions;AllFunctions++) {
		ParameterizedActionListIterator Next(**AllFunctions);
		ParameterizedAction * act ;
		while (act = Next()) {
			for (int i = 0 ; i < 4; i++)
				ParamOpts[i].OutDefinition(out,act);
			if (RemoteFlag !=2) out << "static " ;
/*
 *			cerr << "OutMenuCallDefs for `" << act->GetName() <<"', act = " << 
 *				(void *) act << ", wait = " <<
 *				act->wait_flag << "\n" ;
 */
			out << "CommandParameters " << act->GetName() ;
			if (RemoteFlag) out << "_Rem" ;
			else out << "_Loc" ;
			out << "_Call_Struct = {\n\t" ;
			if (RemoteFlag) out << "-" ;
			out << ++Index << ", " <<
				act->ParameterSequenceIndex ;
			int CharCount = 16 ;
			for (i = 0 ; i < 4; i++) 
				ParamOpts[i].CondOutName(out,
					OperConvert(act->GetName()), CharCount);
			if (act->wait_flag) {
				// cerr << "Output for wait\n" ;
				out << ", 1" ;
			}
			out << "\n};\n" ;
		}
	}
}


void OutMenuCalls(ParameterizedActionList ** AllFunctions,
	const char * ExeFile, int RemoteFlag)
{
	if (RemoteFlag !=2)
		if (*AllFunctions) OutMasterCall(AllFunctions,RemoteFlag);
	ostream& MenuCalls = *OpenFile(ExeFile);
	IncludeOnce(&MenuCalls,ExeFile);
	if (!&MenuCalls) DbgError("OutMenuCall","can't create file");

	MenuCalls << "#include \"menucmd.h\"\n" ;

	// Output the CommandParameters Structure for each command

	if (*AllFunctions) OutMenuCallDefs(MenuCalls,AllFunctions,RemoteFlag);
	ostream * Temp = &MenuCalls;
	IncludeOnce(Temp);
	MenuCalls.flush();
	delete Temp ;
}

void ParameterizedActionList::Clear()
{
	ParameterizedActionListIterator Next(*this);
	ParameterizedAction * Act; 
	while (Act = Next()) delete Act ;
}

Compound::~Compound()
{
	switch(Type) {
case TypeInt:
case TypeDouble:
case TypeString:
case TypeName:
case TypeText:
case TypeTerm:
		break ;
case TypeCompound:
		delete Item.Tree ;
		break ;
case TypeDescription:
case TypeList:
		delete Item.List ;
		break ;
case TypeParamFunc:
case TypeSize:
case TypeScaledType:
case TypeStackIndex:
case TypeParameterizedAction:
		break ;
	}
}

CompoundList::~CompoundList()
{
	CompoundListIterator Next(*this);
	Compound * Del ;
	while (Del = Next()) delete Del ;
}

