/*  genmenu.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <fstream.h>
#include "fileios.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "opf.h"
#include "error.h"
#include "debug.h"
#include "domknode.h"
#include "mknodey.h"
#include "genmenu.h"
#include "y.tab.h"
#include "spellfil.h"
#include "textfrag.h"
#include "menunm.h"
#include "member.h"
#include "nodeparm.h"
#include "outfilnm.h"
#include "mkstr.h"


char * MenuDirectory = 0 ;

static MofStream * MenuFile = 0 ;
static MofStream * PullInFile = 0 ;

static MofStream * RemoteHeaderFile = 0 ;
static MofStream * LocalHeaderFile = 0 ;

const char * ClassName = 0;
char * FileName = 0;
char * PullInFileName = 0 ;
char * RemoteFileName = 0 ;
char * LocalFileName = 0 ;

static int allow_default = 1 ;

void FoundNoDefault()
{
	allow_default = 0 ;
}



static int DoEmitMemberMenu()
{
	if (!TheMemberFunctions) return 0;
	if (!TheMemberFunctions->Size()) return 0;
	return 1 ;
}

static int DoEmitMemberMenuItem()
{
	return DoEmitMemberMenu() ;
}


int NodeParameter::IsArray()
{
	if (Size) return 1 ;
	return 0 ;
}

int NodeParameter::IsChangeable()
{
	if (!Type) return 0 ;
	return Type->ChangeableFlag == CHANGEABLE ;
}


int NodeParameterList::AnyChangeable()
{
	NodeParameterListIterator Next(*this);
	NodeParameter * Param ;
	while (Param = Next()) if (Param->IsChangeable()) return 1;
	return 0 ;
}

char ToLower(char c)
{
	if (c == '_') return ' ' ;
	return tolower(c);
}

const char * StrLowerCpy(char * Dest, const char * String)
{
	char * Return = Dest ;
	for (const char * Pt = String; *Pt ; Pt++) *Dest++ = ToLower(*Pt);
	*Dest = '\0' ;
	return Return ;
}

static void CreateFile(MofStream ** Stream, char ** FullName,
	 const char * Dir, const char * Base, const char * Suffix=0)
{
	char * FileName = *FullName ;
	int DirSize = 0 ;
	if (Dir) DirSize = strlen(Dir);
	int Size = DirSize + strlen(Base) +2 ;
	if (Suffix) Size+=strlen(Suffix);
	FileName = new char[Size] ;
	FileName[0] = '\0' ;
	if (DirSize) {
		strcpy(FileName,Dir);
		strcat(FileName,"/");
	}
	strcat(FileName,Base);
	if (Suffix) strcat(FileName,Suffix);
	// *Stream = OpenFile(FileName);
	LineOfstream::HeaderOptions u_c = LineOfstream::None ;
	if (user_copyright_flag) u_c = LineOfstream::UserCopyrightBit ;
	*Stream = new MofStream(FileName,0,0,u_c);
}

static void OpenPullInFile(const char * NodeName, const char * HeaderFileName)
{
	if (PullInFile) return ;
	CreateFile(&PullInFile, &PullInFileName, MenuDirectory,
		InputFileNameBase, "I.h");
	*PullInFile << "\tTargetDataBase->Append(\"" << NodeName << "\", \""
		<< HeaderFileName << "\");\n" ;
}

void OpenNodFile(const char * NodeName, const char * HeaderFileName)
{
	OpenPullInFile(NodeName,HeaderFileName);
	if (MenuFile) return ;
	CreateFile(&MenuFile, &FileName, MenuDirectory, InputFileNameBase,
		".nod");
}

void WriteBaseClass(const char * NodeName, const char * Base)
{
	// OpenNodFile();
	if (!MenuFile) {
		cerr << "WriteBaseClass MenuFile not opened.\n" ;
		exit(1);
	}
	*MenuFile << "{ " << NodeName << " " << Base << " }\n\n" ;
}


static void CloseRemoteFile()
{
	if (RemoteHeaderFile) {
		delete RemoteHeaderFile ;
		RemoteHeaderFile = 0;
		delete RemoteFileName ;
		RemoteFileName = 0;
	}
}

static void CloseLocalFile()
{
	if (LocalHeaderFile) {
		delete LocalHeaderFile ;
		LocalHeaderFile = 0;
		delete LocalFileName ;
		LocalFileName = 0;
	}
}



void CloseMenuFile()
{
	delete PullInFile ;
	PullInFile = 0 ;
	delete PullInFileName ;
	PullInFileName = 0;

	delete MenuFile ;
	MenuFile = 0;
	delete FileName ;
	FileName = 0 ;
	CloseRemoteFile();
	CloseLocalFile();
	
}

static int CheckQuoteOld(MofStream * Stream, int& LastWasKeyWord)
{
	if (LastWasKeyWord) {
		*Stream << "'" ;
		LastWasKeyWord = 0;
		return 1 ;
	}
	return 0;
}

static int CheckQuoteNew(MofStream * Stream, TextFragment * Frag)
{
	if (Frag->Line < 0) {
		*Stream << "`";
		return 1;
	}
	return 0;
}

// Return true if no black is needed and false otherwise
static void CheckQuote(MofStream * Stream, TextFragment * Frag,
	int& LastWasKeyWord, int First)
{
	CheckQuoteOld(Stream,LastWasKeyWord) ;
	// if (!First)  Stream->put(' ') ;
	// cerr << "Stream = " << (void *) Stream << "\n" ;
	// if (!First)  *Stream << " " ;
	LastWasKeyWord = CheckQuoteNew(Stream,Frag);
}

void EmitHelpLine(MofStream * Stream, TextFragmentList * Text)
{
	if (Text) {
		TextFragment * Fragment ;
		TextFragmentListIterator Next(*Text) ;
		int LastWasKeyWord = 0;
		int First = 1;
		while (Fragment = Next()) 
			if (Fragment->Text) {
				CheckQuote(Stream,Fragment,LastWasKeyWord,
					First);
				First = 0;
				// cerr << "`" << Fragment->Text << "'\n" ;
				*Stream << Fragment->Text;
				if (Fragment->Line > -1) 
					AddToSpellFile(Fragment->SpellText);
			}
	}
}

int CharLen(const char * Str)
{
	if (!Str) return 0 ;
	for (int Len = 0; *Str ; Str++) if (*Str != '\t') Len++ ;
		else Len = (1 + Len / 8) * 8 ;
	return Len ;
}

void EmitDescription (TextFragmentList * Frags,MofStream * Stream,
	const char * Init)
{
	if (!Frags) return ;
	TextFragmentListIterator Next(*Frags);
	TextFragment * Frag ;
	
	int InitCharLength = CharLen(Init);
	int Position = InitCharLength ;
	*Stream << Init ;
	int LastWasKeyWord = 0;

	while (Frag = Next()) {
		if (Frag->Text) {
			int SkipPeriod = 0;
			char NextChar = * Frag->Text ;
			switch (NextChar) {
case '.':
case '!':
case '?':
				break;
default :
				NextChar = 0;
				break ;
			}
			int Size=CheckQuoteOld(Stream,LastWasKeyWord);
			Position += Size ;
			int Length = strlen(Frag->Text) ;
			if (Length + Position > 75) {
				if (NextChar) {
					Stream->put(NextChar);
					SkipPeriod = 1 ;
				}
				*Stream << "\n" << Init ;
				Position = InitCharLength ;
			} else if (Position > InitCharLength) {
				if(!NextChar) { 
					*Stream << " " ;
					Position ++ ;
				}
			}
			LastWasKeyWord = Size=CheckQuoteNew(Stream,Frag);
			if (SkipPeriod) *Stream << (Frag->Text+1) ;
			else *Stream << Frag->Text ;
			Position += Size + Length;
		}
	}
}

static void DefaultHelp()
{
	*MenuFile << "HelpFile : Default\n" ;
}



enum InstanceOpt {InstanceGeneric, InstanceInstance, InstanceSet};

struct EmitNodeParameter {
	const char * NodeName ;
	NodeParameterList * TheNodeParameters ;
	Description * TheNodeDescription ;
	const char * Prefix ;
	const char * MenuPrefix; // used for variables only
	const char * CmtUpper ;
	const char * CmtLower ;
	const char * Where ;
	InstanceOpt InstanceFlag ;
	EmitNodeParameter(const char * Name,
		NodeParameterList * List, Description * Desc) ;
	void SetToInstanceOptions() ;
	void SetToInstanceSetOptions() ;
	void SetToInstanceVarOptions() ;
	void SetToGenericVariable() ;
	void WriteParamItem(NodeParameter *) ;
	void WriteVariableParamItem(NodeParameter *) ;
	void WriteParamData() ;
	void WriteVariableData();
};

EmitNodeParameter::EmitNodeParameter(const char * Name,
	NodeParameterList * List, Description * Desc)
{
	InstanceFlag = InstanceGeneric;
	NodeName = Name;
	TheNodeParameters = List;
	Prefix = "Param";
	CmtUpper= "Object" ;
	CmtLower = "object" ;
	Where = "Remote" ;
	TheNodeDescription = Desc ;
}

void EmitNodeParameter::SetToInstanceSetOptions()
{
	InstanceFlag = InstanceSet;
	MenuPrefix = Prefix = "SetInstanceVariable" ;
	CmtUpper = "Object Instance" ;
	CmtLower = "object instance" ;
	Where = "RemoteOptions" ;
}

void EmitNodeParameter::SetToGenericVariable()
{
	Prefix = "Param" ;
	MenuPrefix = "Variable" ;
	Where = "Remote" ;
}

void EmitNodeParameter::SetToInstanceVarOptions()
{
	InstanceFlag = InstanceInstance;
	MenuPrefix = "InstanceVariable" ;
	Prefix = "InstanceParam" ;
	CmtUpper = "Object Instance" ;
	CmtLower = "object instance" ;
	Where = "RemoteOptions" ;
}

void EmitNodeParameter::SetToInstanceOptions()
{
	InstanceFlag = InstanceInstance;
	Prefix = "InstanceParam" ;
	CmtUpper = "Object Instance" ;
	CmtLower = "object instance" ;
	Where = "RemoteOptions" ;
}

void EmitNodeParameter::WriteVariableParamItem(NodeParameter * TheParameter)
{
	const char * ParamName = TheParameter->Name ;

	const char * DescribeNodeInstanceParameter ;
	switch(InstanceFlag) {
case InstanceInstance:
		DescribeNodeInstanceParameter = "DescribeParamInstance" ;
		break ;
case InstanceGeneric:
		DescribeNodeInstanceParameter = "DescribeParam" ;
			Concatenate(NodeName,ParamName,Prefix,"Describe");
		// *MenuFile << NodeName << " " ;
		break ;
case InstanceSet:
		DescribeNodeInstanceParameter = "ExecuteSetParameter" ;

		*MenuFile << "set " << ParamName <<
			", " << DescribeNodeInstanceParameter << "(\"" <<
			NodeName << "\", " ;
		if (InstanceFlag != InstanceGeneric) *MenuFile << "[2], " ;
		*MenuFile << " \"" <<  ParamName << "\")" << "=" <<
			Where << "\t: " << "Change value of variable `" <<
			ParamName << "' for an instance of `" << NodeName
			<< "'{\n" ;
		EmitDescription(TheParameter->FullDescription, MenuFile, "\t");
		*MenuFile << " }\nHelpFile:Default\n" ;
		return ;
default:
		DbgError("WriteVariableParamItem","bad InstanceFlag");
	}
	*MenuFile << ParamName <<
		", " << DescribeNodeInstanceParameter << "(\"" <<
		NodeName << "\", " ;
	if (InstanceFlag != InstanceGeneric) *MenuFile << "[2], " ;
	*MenuFile << "\"" <<  ParamName << "\")"
		<< "=" << Where <<"\t: "
		<< "Changeable variable `" << ParamName << "' of `" <<
		NodeName << "' " << CmtLower <<
		" {\n" ;
	EmitDescription(TheParameter->FullDescription, MenuFile, "\t");
	*MenuFile << " }\nHelpFile:Default\n" ;
}

void MemberFunction::WriteMemberItemGenericExecute(MofStream& Out)
{
	const char * h = "Default" ;
	if (the_help_file) h = the_help_file ;
	// Out << "exec " << Name << 
	char * wait = "" ;
	if (wait_flag) wait = "Wait" ;
	Out << Name << ",ExecuteMemberFunction" <<
		"( [4], [2], \"" << Name << "\")" << wait << "=Remote,\n" <<
		"\tHelpMemberExecute=HelpText" <<
		"\t: Execute selected member of `"
		<< NodeName << "'\nHelpFile:" << h << "\n\n" ;
}

void MemberFunction::WriteMemberItemGenericDescribe(MofStream& Out)
{
	const char * h = "Default" ;
	if (the_help_file) h = the_help_file ;
	// Out << " desc " ;
	Out << Name  << ", " << OperConvert(Name) ;
	EmitNodeMenuMemberName(MenuFile,NodeName);
	Out << "=Menu\t: Describe member `"
		<< Name << "' of `" << NodeName << "' {\n" ;
	EmitDescription(FullDescription, MenuFile, "\t");
	Out << " }\nHelpFile:" << h << "\n" ;
}



void EmitNodeParameter::WriteParamItem(NodeParameter * TheParameter)
{
	const char * ParamName = TheParameter->Name ;

	const char * DescribeNodeInstanceParameter ;
	switch(InstanceFlag) {
case InstanceInstance:
		DescribeNodeInstanceParameter = "DescribeParamInstance" ;
		break ;
case InstanceGeneric:
		DescribeNodeInstanceParameter = "DescribeParam" ;
		break ;
default:
		DbgError("WriteParamItem","bad InstanceFlag");
	}
	*MenuFile << ParamName <<
		", " << DescribeNodeInstanceParameter << "(\"" <<
			NodeName << "\", " ;
		if (InstanceFlag == InstanceInstance) *MenuFile << "[2], " ;
	*MenuFile << "\"" << ParamName << "\") =" << Where <<"\t: "
		<< "Parameter `" << ParamName << "' of `" 
		<< NodeName << "' " << CmtLower << " {\n" ;
	EmitDescription(TheParameter->FullDescription, MenuFile, "\t");
	*MenuFile << " }\nHelpFile:Default\n" ;
}


void EmitNodeParameter::WriteVariableData()
{
	if(!TheNodeParameters->AnyChangeable()) return ;

	*MenuFile << "History Menu { " << NodeName << MenuPrefix << "Menu\t: "
		<< "Menu of Variables for " << NodeName << " " << CmtUpper ;
	*MenuFile << "\n\n" ;

	NodeParameterListIterator Next(*TheNodeParameters);
	NodeParameter * TheParameter ;
	while (TheParameter = Next()) if (TheParameter->IsChangeable())
		WriteVariableParamItem(TheParameter) ;

	*MenuFile << "}\n\n" ;

}

void EmitNodeParameter::WriteParamData()
{
	if (!TheNodeParameters) return ;
	if (!TheNodeParameters->Size()) return ;
	*MenuFile << "History Menu { " << NodeName << Prefix << "Menu\t: "
		<< "Menu of Parameters for `" << NodeName << "' " << CmtUpper ;
	*MenuFile << "\n\n" ;

	NodeParameterListIterator Next(*TheNodeParameters);
	NodeParameter * TheParameter ;
	while (TheParameter = Next()) {
		WriteParamItem(TheParameter) ;
	}

	*MenuFile << "}\n\n" ;

}


void MemberFunction::EmitSelectMemberParamToDescribeMenu(MofStream& Out,
	const char * NodeName)
{
	if (!Parameters) return ;
	if (!Parameters->Size()) return ;
	Out << "History Menu { " << NodeName << OperConvert(Name) <<
		"MemberParamMenu"
		<< "\t: Select parameter of `" << NodeName <<
		"' member `" << Name << "' to describe\n" ;

	NodeParameterListIterator Next(*Parameters);
	NodeParameter * Param ;
	while (Param = Next()) {
		Out << Param->Name <<
		",DescribeMemberFunctionParameter(\"" << NodeName <<
		"\", [2], \"" << Param->Name << "\")" <<
		"=Remote,\n\tMemberParamDescribeHelp=HelpText\t: "
		<< "Select this parameter of `" << NodeName <<
		"' member `" << Name << "' to describe\n" ;
		const char * h = "Default" ;
		if (the_help_file) h = the_help_file ;
		Out << "HelpFile:" << h << "\n" ;
		//	DefaultHelp();
	}
	Out << "\n}\n\n" ;

}


void EmitSelectMemberToExecute(const char * NodeName,
	const char * MenuType)
{
	if (!DoEmitMemberMenuItem()) return ;
	*MenuFile << MenuType ;
	if (BaseSwitch) *MenuFile << " Orphan" ;
	*MenuFile << " Menu { Select" << NodeName <<
		"MemberExecute\t: Select a member of this `"
		<< NodeName << "' to execute\n" ;
	MemberFunctionListIterator Next(*TheMemberFunctions);
	MemberFunction * Member ;
	while (Member = Next())
		Member->WriteMemberItemGenericExecute(*MenuFile) ;
	*MenuFile << "}\n\n" ;

}

static void EmitSelectMemberToDescribeMenu(const char * NodeName,
	const char * MenuType)
{
	if (!DoEmitMemberMenu()) return ;
	*MenuFile << MenuType ;
	if (BaseSwitch) *MenuFile << " Orphan" ;
	*MenuFile << " Menu { Select" << NodeName <<
		"MemberDescribe\t: Select a member of `" << NodeName <<
		"' to describe\n" ;
	MemberFunctionListIterator Next(*TheMemberFunctions);
	MemberFunction * Member ;
	while (Member = Next())
		Member->WriteMemberItemGenericDescribe(*MenuFile) ;
	*MenuFile << "}\n\n" ;

}


void EmitDescribeMembersMenu(const char * NodeName, const char * MenuType)
{

	if (!DoEmitMemberMenu()) return ;
	EmitSelectMemberToDescribeMenu(NodeName,MenuType);

	// Upon entering this menu we will have selected the member
	// function to describe


	MemberFunction * Member ;
	MemberFunctionListIterator Next(*TheMemberFunctions);
	while (Member = Next()) {
		*MenuFile << "History Menu { " <<
			OperConvert(Member->GetName()) ;
		EmitNodeMenuMemberName(MenuFile,NodeName);
		*MenuFile << "\t:Describe member `" <<
			Member->GetName() << "' of `"  ;
/*
 *		if (ClassName) if (*ClassName) *MenuFile << ClassName <<
 *			"' `" ;
 */
		*MenuFile << NodeName << "'\n\n" ;
	
		// This does the actual description by calling a remote routine
		*MenuFile << "desc " << Member->GetName() << "," <<
			"MemberFunctionDescribe(\""
			<< NodeName <<
			"\", [1])=Remote,\nMemberHelp=HelpText" <<
			"\t: Describe selected member of `"
			<< NodeName << "'\n" ;
		const char * h = "Default" ;
		if (Member->help_file()) h = Member->help_file();
		*MenuFile << "\nHelpFile:" << h << "\n" ;
	
		// This goes to a menu to select the parameter
		if (Member->AnyParameters()) {
			*MenuFile << "param " << Member->GetName() << "," << 
				NodeName << OperConvert(Member->GetName()) <<
				"MemberParamMenu=Menu,\n" <<
				"\tMemberParamDescribeHelp=HelpText\t: " <<
				"Describe the parameters of member `"
				<< Member->GetName() << "'\n" ;
			*MenuFile << "\nHelpFile:" << h << "\n" ;
		}
		*MenuFile << "}\n\n" ;
	

		// Emit the parameter menus for all member functions
		Member->EmitSelectMemberParamToDescribeMenu(*MenuFile,NodeName);
	}

}

static const char * InstanceAccessSuffix = "InstanceAccessMenu" ;

	
static void EmitInstancesMenu(const char * NodeName)
{
	*MenuFile << "Multiple Use Dynamic Select Menu { " ;
	EmitNodeMenuInstancesName(MenuFile,NodeName);
	*MenuFile << "\t: Select an Instance of `" << NodeName  << "'" ;
	if (!DoEmitMemberMenu()) 
		*MenuFile << " to describe or delete" ;

	*MenuFile << "\n\nTemplate," << NodeName << InstanceAccessSuffix
		<< "=Menu\t" <<
		": Select this instance of `" << NodeName <<
		"'\n}\n\n" ;
}

	
static void EmitMemberInstanceMenuItem(const char * NodeName)
{
	*MenuFile << "exec, " ;
	if (DoEmitMemberMenuItem()) *MenuFile << "Select" << NodeName
		<< "MemberExecute" ;
	else *MenuFile << "Orphan" ;
	*MenuFile << "=Menu,\n\tHelpMemberExecute=HelpText\t: "
		<< "Select a member of `" <<
		NodeName << "' to execute\n" ;
	DefaultHelp() ;
}


static void EmitInstanceOperationMenu(NodeParameterList * TheNodeParameters,
	const char * NodeName)
{
	*MenuFile << "History Menu { " << NodeName <<
		InstanceAccessSuffix ;
	if (DoEmitMemberMenuItem())
		*MenuFile << ": Operations on an instance of " ;
	else *MenuFile << ": Describe or delete an instance of " ;
	*MenuFile << " object `" << NodeName <<"'\n" ;

	*MenuFile << "desc," <<
		"DescribeNodeInstance(\"" << NodeName << "\",[1])" <<
		"=Remote,\n\tNodeInstanceDescribeHelp=HelpText\t: "
		<< "Describe this instance of `" << NodeName << "'\n" ;
	DefaultHelp();


	if (TheNodeParameters->Size()) {
		*MenuFile << "param," << NodeName <<
			"InstanceParamMenu=Menu,\n\tParamInstanceDescribeHelp"
			<< "=HelpText\t: "
			<< "Describe parameters of this `"
			<< NodeName << "'\n" ;
		DefaultHelp();
	}

	EmitMemberInstanceMenuItem(NodeName) ;

	if(TheNodeParameters->AnyChangeable()) {
		*MenuFile << "variables," << NodeName <<
			"InstanceVariableMenu=Menu," <<
			"\n\tVariableInstanceDescribeHelp=HelpText\t: "
			<< "Describe variables of this `"
			<< NodeName << "'\n" ;
		DefaultHelp();

		*MenuFile << "set," << NodeName <<
			"SetInstanceVariableMenu=Menu," <<
			"\n\tVariableInstanceDescribeHelp=HelpText\t: "
			<< "Set variable values of this `"
			<< NodeName << "'\n" ;
		DefaultHelp();
	}

	*MenuFile << "delete,DeleteNodeInteractiveEntity(\""
		<< NodeName <<
		"\", [1])=Remote,\n\tNodeDeleteHelp=HelpText\t: "
		<< "Delete this `" << NodeName
		<< "'\n" ;
	DefaultHelp();
	*MenuFile << "\n}\n\n" ;
	EmitSelectMemberToExecute(NodeName) ;
}

static void EmitMainHelp(const char * MainHelp, const char * NodeName)
{
	if (MainHelp) *MenuFile << ",\n\t" << NodeName << MainHelp
		<< "=HelpText" ;
	*MenuFile << "\t: " ;
}


static void EmitChangeableParametersMenuItem(
	NodeParameterList * TheNodeParameters, const char * NodeName)
 {
 	if(!TheNodeParameters->AnyChangeable()) return ;
	*MenuFile << "variables," << NodeName <<
		"VariableMenu=Menu,\n\tNodeVariableHelp=HelpText\t: " <<
		"Changeable variables of `" << NodeName << "'\n" ;
	DefaultHelp() ;
}




static void EmitMemberMenuItem(const char * NodeName)
{
	*MenuFile << "members, " ;
	if (DoEmitMemberMenuItem()) *MenuFile << "Select" << NodeName <<
		"MemberDescribe" ;
	else * MenuFile << "Orphan" ;
	*MenuFile << "=Menu,\n\tMemberMenuHelp=HelpText\t: " <<
		"Members of `" << NodeName << "'\n" ;
	DefaultHelp() ;
}

int DefaultInstance = 1 ;

void NoDefaultInstance()
{
	DefaultInstance = 0 ;
}


static void EmitDefaultExample(const char * NodeName,
	NodeParameterList * TheNodeParameters)
{
	*PullInFile << "\textern void " << NodeName << "NodesInit();\n" ;
	*PullInFile << "\t" << NodeName << "NodesInit();\n" ;
	if (!DefaultInstance) return ;
	*MenuFile << "Init {\n" ;
	*MenuFile << "#include \"" << ObjProUsr << "/" << HeaderName << "\"\n\t" ;
	*MenuFile << NodeName << "Def = new " <<
		NodeName << "(\""  << NodeName << "Def\"" ;
	NodeParameterListIterator Next(*TheNodeParameters);
	NodeParameter * Param;
	while (Param = Next()) {
		*MenuFile << ",\n\t\t" ;
		Param->EmitDefaultValue(*MenuFile);
	}
	*MenuFile << ");\n} " ;
	*MenuFile << NodeName << "Def" ;
	int OutNames = 0 ;

	NodeParameterListIterator Next2(*TheNodeParameters);
	int Out = strlen(NodeName)+5;
	int First = 1 ;
	while (Param = Next2()) if (Param->ClassType) {
		if (!First) *MenuFile << ", " ;
		else * MenuFile << "= " ;
		First = 0;
		Out += 2;
		if (Out > 64) {
			*MenuFile << "\n\t" ;
			Out = 8;
		}
		if (Param->Default->Type != TypeName)
			DbgError("EmitDefaultExample",
				"bad default type");

		*MenuFile << Param->Default->Item.Str ;
	}
	*MenuFile << " ;\n\n" ;
}
	
void WriteNodeAndParameterMenus( const char * NodeName,
	NodeParameterList * TheNodeParameters, Description * TheNodeDescription)
{
	if (!TheNodeDescription) return ;
	const char * MenuName = TheNodeDescription->MenuName ;
	if (!MenuName) {
		cerr << "No menu specifed for object `" << NodeName <<
			"'.\n" ;
		return ;
	}

	EmitDefaultExample(NodeName,TheNodeParameters) ;

	char * MainHelp = 0;
	if (TheNodeDescription->Full) {
		MainHelp = "MainHelpDefinition" ;
		*MenuFile<< "HelpDefinition { " << NodeName << MainHelp << "\n";
		EmitDescription(TheNodeDescription->Full,MenuFile,"\t");
		*MenuFile << "\n}\n\n" ;
	} 


	*MenuFile << "Add To Menu { " << TheNodeDescription->MenuName << "\n" ;
	*MenuFile << NodeName << "," ;
	EmitNodeMenuName(MenuFile,NodeName);
	*MenuFile << "=Menu" ;
	EmitMainHelp(MainHelp,NodeName) ;
	const char * LowerNodeName = StrLowerCpy(new char[strlen(NodeName)+1],
		NodeName);
	const char * help = LowerNodeName ;
	if (TheNodeDescription->HelpFileName) help =
		TheNodeDescription->HelpFileName;
	EmitHelpLine(MenuFile, TheNodeDescription->HelpLine);
	*MenuFile << "\nHelpFile : " << help << "\n" ;
	*MenuFile << "\n}\n\n" ;

	*MenuFile << "History Menu { " << NodeName << "NodeOptMenu" ;
	*MenuFile << "\t: " ;
	*MenuFile << "Options for `" << NodeName << "'\n\n" ;

	*MenuFile << "help" << "," << help << "=HelpFile" ;
	EmitMainHelp(MainHelp,NodeName) ;
	*MenuFile << "Explain the use of `" << NodeName << "'\n\n" ;

/****************************
 *	*MenuFile << "desc," << 
 *		"NodeDescribe(\"" << NodeName << "\")" << "=Remote" ;
 *	EmitMainHelp(MainHelp,NodeName) ;
 *	*MenuFile << "Describe the use and parameters of `" <<
 *		NodeName << "'\n\n" ;
 *	DefaultHelp() ;
 *******************************/

	if (TheNodeParameters->Size()) {
		*MenuFile <<  "param," << NodeName <<
			"ParamMenu=Menu,\n\tNodeParamHelp=HelpText\t: " <<
			"Parameters of `" << NodeName << "'\n" ;
		DefaultHelp() ;
	}
	EmitChangeableParametersMenuItem(TheNodeParameters,NodeName) ;


	EmitMemberMenuItem(NodeName);


	*MenuFile << "instance," ;
	EmitNodeMenuInstancesName(MenuFile,NodeName);
	*MenuFile << "=DynamicMenu,\n\tNodeInstanceHelp=HelpText\t: "
		<< "Describe or delete an instance of `" << NodeName << "'\n" ;
	DefaultHelp();

	if (allow_default) {
		*MenuFile << "create default,CreateDefaultNodeInteractiveEntity(\"" <<
			NodeName << "\")=Remote,\n\tNodeCreateDefaultHelp=HelpText\t: "
			<< "Create instance of `" << NodeName <<
			"' with default parameters\n" ;
		DefaultHelp();
	}

	*MenuFile << "create,CreateNodeInteractiveEntity(\"" << NodeName <<
		"\")=Remote,\n\tNodeCreateHelp=HelpText\t: "
		<< "Create instance of `" << NodeName << "'\n" ;
	DefaultHelp();
	*MenuFile << "}\n\n" ;

}

void WriteMenuData( const char * NodeName,
	NodeParameterList * TheNodeParameters, Description * TheNodeDescription)
{
	if (!BaseSwitch) WriteNodeAndParameterMenus(NodeName,TheNodeParameters,
		TheNodeDescription);

	EmitDescribeMembersMenu(NodeName);

	if (BaseSwitch) EmitSelectMemberToExecute(NodeName) ;
	else {
		// create structure for instance menu output
		EmitNodeParameter ParamOut(NodeName,TheNodeParameters,

		TheNodeDescription);
		EmitInstancesMenu(NodeName);
		EmitInstanceOperationMenu(TheNodeParameters,NodeName);
		// Write parameters menu for generic description
		ParamOut.WriteParamData();
		ParamOut.SetToGenericVariable() ;
		ParamOut.WriteVariableData();

		const char * InstSuf = " inst" ;

		// Write parmeters menu for instance description
		ParamOut.SetToInstanceOptions();
		ParamOut.WriteParamData();
	
		if (TheNodeParameters->AnyChangeable()) {
			ParamOut.SetToInstanceVarOptions();
			ParamOut.WriteVariableData();
		
			ParamOut.SetToInstanceSetOptions();
			ParamOut.WriteVariableData();
		}
	}

		// delete LowerNodeName ;
}


