/*
 *  nodeparm.C from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */
#include <stream.h>
#include <fstream.h>
#include "fileios.h"
#include <string.h>
#include "debug.h"
#include "domknode.h"
#include "mknodey.h"
#include "member.h"
#include "mknodelx.h"
#include "nodeparm.h"
#include "ctorinit.h"
#include "textfrag.h"
#include "outtok.h"
#include "gentex.h"

static const char * VarType(ItemType type)
{
	switch (type) {
case TypeInt:
		return "integer" ;
case TypeDouble:
		return "floating point" ;
case TypeString:
		return "string" ;
case TypeName:
		return "name" ;
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeSize:
case TypeParameter:
case TypeParamFunc:
case TypeScaledType:
	default :
		DbgError("VarType","bad type");
	}
}

static void VoidValueObjectOut(MofStream& Out, int Type, const char * StrScaleFac,
	Compound * Value, const char * Name)
{
	Out << "\tstatic " ;
	if (IsVoidNumericType(Type)) Out << " Cast" ;
	Out << WhatTypeString(Type) << Name << " =\n\t\t" ;
	if (IsVoidNumericType(Type)) Out << "{" ;
	EmitScaledValue(Value,StrScaleFac,Type) ;
	if (IsVoidNumericType(Type)) Out << "}" ;
	Out << " ;\n\n" ;
}

static void EmitDataForDec(MofStream& Out,int Type, const char * DefAryName,
	int header)
{
	if (header) Out << "\textern " ;
	Out << WhatTypeString(Type,DataPhonyDecType) <<
		"TheDataFor" << DefAryName << "[]" ;
}

static void ScalarArrayDataOut(MofStream& Out, int IntType,
	const char * DefaultObject,
	const char * DefaultName)
{
	Out << "\n\tstatic ArrayData " << DefaultName << " = {-1, Dec"
		<< DecTypeSuffix(IntType)
		<< ",\n\t\t(void *) &" << DefaultObject << "};\n\n" ;
}

static void ArrayParamOut(MofStream& Out, NodeParameter * Param)
{
	ScaledType * Type = Param->Type ;
	char * DefaultName ;
	Compound& Default = *(Param->Default) ;

	Double * ScaleFac = Type->Value ;
	const char * StrScaleFac = 0 ;
	if (ScaleFac) StrScaleFac = ScaleFac->String ; 
	int IntType = Type->Type ;

	if (Default.Type == TypeList) {
		DefaultName = MakeDefaultArrayName ( NodeName, Param->Name);
		// DefaultArrayOut(Param,DefaultName);
		// values are output earler so they can be external
	} else {
		char * DefaultObject =
			MakeCompoundName(NodeName,Param->Name,"DefaultObject");
		DefaultName = MakeCompoundName ( NodeName, Param->Name,
			"DefaultValue");
		VoidValueObjectOut(Out,IntType,StrScaleFac,&Default,
			DefaultObject);
		ScalarArrayDataOut(Out,IntType,DefaultObject,DefaultName);
	}

	char * LowerName = MakeCompoundName (
		NodeName, Param->Name, "LowerArrayBound");
	VoidValueObjectOut(Out,IntType,StrScaleFac,Param->Lower,LowerName);
	

	char * UpperName = MakeCompoundName (
		NodeName, Param->Name, "UpperArrayBound");
	VoidValueObjectOut(Out,IntType,StrScaleFac,Param->Upper,UpperName);

	ArraySize * Size = Param->Size ;

	Out << "\tstatic ArrayParam " << NodeName << Param->Name <<
		"Param = {\n\t\t" << "Dec" << DecTypeSuffix(IntType) <<
		", &" << DefaultName << ",\n\t\t0, 0, (void *) &" <<
		LowerName << ", 0,\n\t\t(void *) &" << UpperName ;
	if (Size) Out << ", " << Size->Lower << ", " << Size->Upper ;
	Out << "};\n" ;

	delete LowerName ;
	delete UpperName ;
	delete DefaultName ;
}

static int CheckVarType(ItemType Expect, ItemType Found)
{
	if (Expect == Found) return 1 ;
	if (Expect == TypeDouble && Found == TypeInt) return 1 ;
	cerr << "Expecting variable type " << VarType(Expect) << " and found "
		<< VarType(Found) << ".\n" ;
	cerr << "Bad variable type.\n" ;
	// DbgError("CheckVarType","bad type");
	return 0;
}

static void ValueOut(MofStream& Out, Compound * Value,ItemType TestType)
{
	CheckVarType(TestType, Value->Type) ;
	switch (Value->Type) {
case TypeDouble:
		Out << " " << Value->Item.Dbl->String ;
		return ;
case TypeInt:
		Out << " " << Value->Item.Int ;
		return ;
case TypeName:
case TypeString:
		Out << " \"" << Value->Item.Str << "\"" ;
		return ;
case TypeText:
case TypeTerm:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeParamFunc:
case TypeSize:
case TypeParameter:
case TypeScaledType:
	default :
		DbgError("ValueOut","bad type");
	}
}


static void ParamValueOut(MofStream& Out,Compound * ParamVal, ItemType TestType,
	double IntLargest, const char * BaseName)
{
	Out << ", " ;
	switch (ParamVal->Type) {
case TypeInt:
case TypeDouble:
case TypeString:
		Out << " 0, " ;
		ValueOut(Out,ParamVal,TestType);
		return ;
case TypeParamFunc:
		{
		const char * Return = MakeParameterFunctionName(BaseName);
		Out << "&" << Return ;
		Out << "_Struct, 0" ;
		delete (void *) Return ;
		return ;
		}
case TypeTerm:
		{
		int TermSym = ParamVal->Item.Int ;
		int NegativeLim = TermSym == MIN || TermSym == MAX_NEG ;
		int PositiveLim = TermSym == MAX || TermSym == MIN_POS ;
		int BigLim = TermSym==MAX || TermSym == MIN ;
		if (NegativeLim || PositiveLim) {
			Out << "0, " ;
			if (NegativeLim) Out << "-" ;
			if (TestType == TypeInt) {
				if (BigLim) Out << (double) IntLargest ;
				else Out << 1 ;
			} else if (TestType == TypeDouble) {
				if (BigLim) Out << LARGE_DOUBLE ;
				else Out << 1.e-100 ;
			} else break ;
			return ;
		}
		}
case TypeName:
case TypeText:
case TypeCompound:
case TypeDescription:
case TypeList:
case TypeSize:
case TypeParameter:
case TypeScaledType:
default :
		break ;
	}
	DbgError("ParamValueOut","bad type");
}

void NodeParameter::Init()
{
	Name=0 ;
	ClassType = 0 ;
	Default = 0 ;
	HelpLine = 0 ;
	FullDescription = 0 ;
	Lower=Upper= 0;
	Type = 0 ;
	LegalCheck = 0 ;
	FirstDefault = 0 ;
	Size = 0 ;
	SubroutineDefault=0 ;
}

NodeParameter::NodeParameter(const char * typ, const char * name,
	const char * def, TextFragmentList * menu, TextFragmentList * full)
{
	Init();
	// cout << "Creating NodeParameter `" << name << "'.\n" ;
	ClassType = typ;
	Name = name ;
	Default = new Compound(TypeName, *(new Object(def))) ;
	// cout << "Default->Type = " << Default->Type << "\n" ;
	HelpLine = menu;
	FullDescription = full;
}

NodeParameter::NodeParameter(const char * ClassName, const char * name)
{
	Init();
	ClassType = ClassName ;
	Name = name ;
}
NodeParameter::NodeParameter(const char * name)
{
	Init();
	Name = name ;
}

NodeParameter::NodeParameter(ScaledType * typ, const char * name)
{
	ClassType = 0 ;
	Name = name ;
	Default = 0 ;
	HelpLine = 0 ;
	FullDescription = 0 ;
	Lower=Upper= 0;
	Type = typ ;
	LegalCheck = 0 ;
	FirstDefault = 0 ;
	Size = 0 ;
}

NodeParameter::NodeParameter(ScaledType * typ, const char * name,
	Compound * low, Compound * def, Compound * up, TextFragmentList * menu,
	TextFragmentList * full, ArraySize * s)
{
	// cout << "NodeParameter constructor\n" ;
	ClassType = 0;
	Type = typ;
	Name = name ;
	Lower = low ;
	Default = def;
	Upper = up;
	HelpLine = menu;
	FullDescription = full;
	Size=s;
	LegalCheck = 0 ;
	FirstDefault = 0 ;
}

NodeParameter::~NodeParameter()
{
	delete[] (void *) Name;
	delete[] (void *) Lower;
	delete Default;
	delete Upper ;
	delete HelpLine;
	delete FullDescription;
	delete Size ;
	delete Type;
}


static void ParamSelectTypeOut(MofStream& Out,int Type)
{
	switch(Type) {
case INT:
case INT16:
case INT32:
		Out << "IntP" ;
		break ;
case DOUBLE:
		Out << "FloatP" ;
		break ;
case STRING:
		Out << "StringP" ;
		break ;
case -1:
		Out << "EntityP" ;
		break ;

default:
		if (IsVoidNumericType(Type)) {
			Out << "ArrayP" ;
			break ;
		}
		cerr << " Bad type = " << Type << "\n" ;
		DbgError("ParamSelectTypeOut","unknown or invalid type");
	}
}

void NodeParameter::EmitSetNodeParameterValue(MofStream& Out,
	const char *NodeName, int& Index)
{
	int ThisType = -1 ;
	if (Type) ThisType = Type->Type;
	int VoidType = 0;
	if (ThisType > -1) VoidType = IsVoidNumericType(ThisType);
	char buf[32];
	sprintf(buf,"%d",Index++);
	const char * ParamName = MakeCompoundName(Name,"_",buf);
	const char * ParamPtr = 0;
	if (VoidType && !Size) {
		if (ThisType < 0) DbgError(
			"NodeParameter::EmitSetNodeParameter","bad void type" );
		ParamPtr = MakeCompoundName(ParamName,"_Ptr");
		Out << "\t\t" << WhatTypeString(this,1) << " * " << ParamPtr <<
			" = new " ;
		Out << WhatTypeString(ThisType) ;
		Out << ";\n\t\t" << ParamPtr << " = &" << ParamName << ";\n" ;

	}
	Out << "\t\tIntEnt" << NodeName <<
		"->GetOneParameter(\"" << Name << "\")->\n\t\t\t" ;
	if (Size) Out<< "ArrayP" ;
	else ParamSelectTypeOut(Out,ThisType) ;
	Out << "->CurrentValue = " ;
	if (Size) {
		if (ThisType < 0) DbgError(
			"NodeParameter::EmitSetNodeParameter","bad array type");
		Out << "\n\t\t(new ArrayData)->SetArrayData(" <<
			Name << "_Length_" << Index++ << ", Dec"
			<< DecTypeSuffix(ThisType)
			<< ", " << ParamName << ");\n" ;
		
		delete (void *) ParamName ;
		return ;
	}
	if (VoidType) {
		Out << "\n\t\t(new ArrayData)->SetArrayData(-1" <<
			", Dec" << DecTypeSuffix(ThisType)
			<< ", (void *) " << ParamPtr << ");\n" ;
		delete (void *) ParamPtr ;
	} else Out << ParamName << ";\n" ;
}
	
void NodeParameter::EmitDefaultValue(MofStream& Out)
{
	if (Size) {
		char * DefaultName =
			MakeDefaultArrayName ( NodeName, Name);
		Out << "(" << WhatTypeString(this) << ") TheDataFor" <<
			DefaultName << ", " << GetDefaultArraySize(this);
		delete DefaultName ;
		return ;
	}
	int TheType = 0 ;
	if (Type) TheType = Type->Type ;
	if (TheType) Default->EmitValue(&Out);
	else {
		if (IsReference(ClassType)) Out << "*" ;
		Out << " " << Default->Item.Str ;
	}
}

void NodeParameter::EmitParamCheckFunc(MofStream& Out, CheckFuncPlace Place)
{
	if (!Type) return ;
	if (Default) DoEmitParamCheckFunc(Out, Type->Type,Name,Default,Place);
	if (Lower) DoEmitParamCheckFunc(Out, Type->Type,Name,Lower,Place);
	if (Upper) DoEmitParamCheckFunc(Out, Type->Type,Name,Upper,Place);

}

void NodeParameter::ParamOut(MofStream& Out, const char * BaseName)
{
/*
 *	cerr << "ParamOut for `" << BaseName << "' - SubroutineDefault = "
 *		<< SubroutineDefault << "\n" ;
 */
	if (IsVoidNumericType(this)) {
		ArrayParamOut(Out,this);
		return ;
	}
	
	Out << "\tstatic " ;
	int32 Big = 0;
	ItemType TestType ;
	if (!Type) {
		TestType = TypeName ;
		// cout << "Param is `" << Name << "'\n" ;
		Out << "EntityParam " << NodeName << OperConvert(BaseName) <<
			Name << "Param = {\n\t\t" ;
		if (!SubroutineDefault) ValueOut(Out,Default,TestType);
		else Out << "0" ;
		Out << ", \"" << ClassType << "\", 0, 0" ;
		if (SubroutineDefault) {
			if (Default->Type != TypeName)
			DbgError("NodeParameter::ParamOut","bad default");
			Out << ", " << Default->Item.Str ;
		}
		Out << "};\n" ;
		return ;
	} else switch(Type->Type) {
case INT16:
		Big = LARGE_16 ;
case INT:
case INT32:
		TestType = TypeInt ;
		if (!Big) Big = LARGE_32 ;
		Out << "IntParam " ;
		break ;
case DOUBLE:
		TestType = TypeDouble ;
		Out << "FloatParam " ;
		break ;
case STRING:
		TestType = TypeString ;
		Out << "StringParam " << NodeName << BaseName << Name <<
			"Param = {\n\t\t" ;
		if (Default->Type == TypeInt)
			ValueOut(Out,Default,TypeInt);
		else ValueOut(Out,Default,TestType);
		Out << ", 0, 0" ;
		Out << "};\n" ;
		return ;
default:
		DbgError("ParamOut","unknown or invalid type");
	}
	Out << NodeName << BaseName << Name << "Param = {\n\t\t" ;
	ValueOut(Out,Default,TestType);
	Out << ", 0" ;
	ParamValueOut(Out,Lower,TestType,Big,Name);
	ParamValueOut(Out,Upper,TestType,Big,Name);
		Out << "};\n" ;
}

void NodeParameter::CompleteArrayEltForArray(MofStream& Out,
	const char * NodeName)
{
	Out << "&" << NodeName << Name << "Param" ;
	EmitFirstDefault(Out);
	Out << "},\n\n" ;
}

void NodeParameter::EmitCheckFunctionDefiniton(MofStream& Out,
	const char * NodeName)
{
	if (!LegalCheck) return ;
	Out << "static int " << MakeLegalCheckName(NodeName) <<
		"_Func(CheckAction TheAction,\n" <<
		"\tOneParameter * TheParam, const OneParameter **,"
		<< "OutTokens *)\n{\n" ;
	EmitCppCode(LegalCheck);
	Out << "\n}\n\n" ;
	Out << "static DoCheckFunc " << MakeLegalCheckName(NodeName) <<
		" = {" << MakeLegalCheckName(NodeName) << "_Func,  0};\n\n";
}


const char * NodeParameter::MakeLegalCheckName(const char * NodeName)
{
	const BufSize = 256;
	static char Buf[BufSize+1];
	strcpy(Buf,NodeName);
	strcat(Buf,"_");
	strcat(Buf,Name);
	strcat(Buf,"_");
	strcat(Buf,"CheckLegalThis");
	return Buf ;
}


void NodeParameter::DefaultArrayOut(MofStream& Out, MofStream& Hout,
	const char * DefAryName)
{
	if (!Default) DbgError("DefaultArrayOut", "NULL default");
	if (Default->Type != TypeList) DbgError("DefaultArrayOut",
		"Default not a list");

	CompoundList * TheDefaults = Default->Item.List ;
	if (!TheDefaults->Size()) DbgError("DefaultArrayOut",
		"Null default list");
	if (Default->Type != TypeList) DbgError("DefaultArrayOut","bad type");

	int ThisType = -1 ;
	if (Type) ThisType = Type->Type ;

	EmitDataForDec(Hout,ThisType,DefAryName,1) ;

	Hout << ";\n\n" ;
	EmitDataForDec(Out,ThisType,DefAryName,0) ;
	Out << " = {\n" ;

	Double * ScaleFac = Type->Value ;
	const char * StrScaleFac = 0 ;
	if (ScaleFac) StrScaleFac = ScaleFac->String ; 

	Compound * Value ;
	int count = 0 ;

 	int32 DefaultSize = TheDefaults->Size();
	while (Value = TheDefaults->Get()) {
		if (count) Out << ", " ;
		if ( StrScaleFac || !(count % 5) ) Out << "\n\t\t" ;
		count++;
		EmitScaledValue(Value,StrScaleFac,ThisType);
	}

 	TheDefaults->Append(new Compound(TypeInt, *(new Object(DefaultSize))));
 	// Save size of array for later access (to define a default instatnce)
 
	Out << "\n\t};\n\n" ;


	Out << "\tstatic ArrayData " << DefAryName << " = { " <<
		DefaultSize << ", Dec" << DecTypeSuffix(ThisType)
		<< ",\n\t\t(void *) TheDataFor" << DefAryName << "};\n\n" ;
}

const MaxPositionIndex = 4 ;

int NodeParameter::PositionOneParameter() const
{
	if (Size) return 4 ;
	if (!Type) return 3 ; // Entity
	
	int TheType = Type->Type ;
// int float string entity array
//  0    1     2      3     4
	switch(TheType) {
case INT:
case INT16:
case INT32:
		return 0;
case DOUBLE:
		return 1 ;
case SC_CX_MACH_WORD:
case CX_MACH_WORD:
case SC_MACH_WORD:
case MACH_WORD:
case SC_CX_ACC_MACH_WORD:
case CX_ACC_MACH_WORD:
case SC_ACC_MACH_WORD:
case ACC_MACH_WORD:
case COMPLEX:
		return MaxPositionIndex;
case STRING:
		return 2;
default:
		cerr << "Bad type = " << TheType << "\n" ;
		DbgError("PositionOneParameter","unknown type");
		return -1;
	}
}

void NodeParameter::ParamArrayEltOut(MofStream& Out, const char * NodeName)
{
	int ThisType = -1 ;
	if (Type) ThisType = Type->Type ;
	TextFragmentList * Text = HelpLine ;
	Out << "\t\t{\"" << Name << "\", " ;
	if (!LegalCheck) Out << "0";
	else Out << "&" << MakeLegalCheckName(NodeName);
	Out << ", " ;
	if (Text) Out << "\n\t\t\t" ;
	EmitQuotedHelpLine(Out,Text);
	if (Text) Out << ",\n\t\t\t" ; else Out << ", " ;
	int UseVoidPtr = IsVoidNumericType(this);
	if (UseVoidPtr) {
		Out << "0, 0, 0, 0,\n\t\t\t" ;
		CompleteArrayEltForArray(Out,NodeName);
		return ;
	}
	if (ThisType> -1) switch (ThisType) {
case INT16:
case INT32:
		break ;
case STRING:
		Out << "0, " ;
case DOUBLE:
		Out << "0, " ;
		break ;
default:
		DbgError("ParamArrayEltOut","bad type");

	} else Out << "0, 0, 0, " ;
	Out << "&" << NodeName << Name << "Param",
	EmitFirstDefault(Out);
	Out << "},\n" ;
}

void NodeParameter::EmitFirstDefault(MofStream& Out)
{
	int PositionIndex = PositionOneParameter();
	if (IsFirstDefault()) {
		for (int i=PositionIndex+1;i<MaxPositionIndex+1;i++)
			Out << ", 0" ;
		Out << ", 1" ;
	}

}

void NodeParameter::EmitInteractiveMemberParameter(MofStream& Out,
	const char * Pre)
{
/*
 *	cerr <<"EmitInteractiveMemberParameter - `" << Name << "'.\n" ;
 *	cerr << "Type = " << Type << ", Position = " <<
 *		PositionOneParameter() << "\n" ;
 */
	Out << "\t\t{\"" << Name << "\", 0, " ;
	EmitQuotedHelpLine(Out,HelpLine);
	Out << "\n\t\t\t, " ;
	for (int i = 0 ; i < PositionOneParameter();i++) Out<<"0, ";
	Out << "&" << NodeName << Pre << Name << "Param" ;
	EmitFirstDefault(Out);
	Out << "},\n" ;
}

void NodeParameter::EmitInteractiveGetValueKernel(MofStream& Out,
	const char * Pre)
{
	int PositionIndex = PositionOneParameter();
	for (int i = 0 ; i < PositionIndex;i++) Out<<"0, ";
	Out << "&" << NodeName << Pre << Name << "Param" ;
	EmitFirstDefault(Out);
	Out << "},\n\t\t\t{0}\n\t};\n" ;
}

void NodeParameter::EmitInteractiveGetValue(MofStream& Out, const char * Prefix)
{
	const char * Pre = Prefix ? Prefix : "" ;
	Out << "\tstatic OneParameter " << Pre << Name ;
	Out << NodeName << "List[] = {\n" ;
	Out << "\t\t{\"" << Name << "\", 0, " ;
	EmitQuotedHelpLine(Out,HelpLine);
	Out << ",\n\t\t\t " ;
	EmitInteractiveGetValueKernel(Out,"") ;

	Out << "\tUserParameters * " << Pre << Name << "MemberParam" <<
		" = new UserParameters\n\t\t(" << Pre <<
		Name << NodeName << "List);\n\n" ;

	Out << "\tProcedure * " << Pre << "MemberProc" << 
		Name << " = new Procedure(\"" << Pre << Name
		<< "\", " << Pre << Name <<
		",\n\t\t " << Pre << Name << "MemberParam, \"" ;
	if (!strcmp(Pre,"Set")) Out << "void" ;
	else Out << WhatTypeString(this);
	Out << "\");\n" ;

}

void NodeParameter::EmitMemberEntry(MofStream& Out, const char * NodeName,
	const char * Pre)
{
	const char * Prefix = Pre ? Pre : "" ;
	EmitEntry(Out,Name,NodeName,Prefix);
}

void NodeParameter::EmitCallGetParameter(MofStream& Out)
{
	EmitBaseGetParameter(Out,"Param->");
}


void NodeParameter::EmitGetParameter(MofStream& Out)
{
	EmitBaseGetParameter(Out,"IntNode.");
}

void NodeParameter::EmitBaseGetParameter(MofStream& Out, const char * Where)
{
	Out << "\t\t" << WhatTypeString(this) << Name <<
		" =\n\t\t\t" ;
	if (IsVoidNumericType(this)) {
		if (!Size) Out << "*" ;
		Out << "(" << WhatTypeString(this,1) ;
		if (!Size) Out << "*" ;
		Out << " ) " ;
	}
	if (!Type) {
		int ClassLength = strlen(ClassType) ;
		Out << "(" << ClassType << " )" ;
		if (ClassType[ClassLength-1] != '*') {
			const BufSize = 128 ;
			char Buf[BufSize+1] ;
			if (ClassLength > BufSize)
				DbgError("NodeParameter::EmitBaseGetParameter",
				"class name too long");
			strcpy(Buf,ClassType);
			if (Buf[ClassLength-1] == '&') Buf[ClassLength-1]='\0';
			Out << "*(" << Buf << " *)" ;
		}
	}
	Out << Where << "Get" ;
	if (Size) Out << "Array" ;
	else if (Type) Out << GetOneParType(Type->Type) ;
	else Out << "Entity" ;
	Out << "ParameterValue(\"" << Name << "\");\n";
	if (Size) Out << "\t\tint32 " << Name <<
		"_Length =\n\t\t\tIntNode.GetLengthArray" <<
		// << GetOneParType(Type->Type) 
		"ParameterValue(\"" << Name << "\");\n";
}

void NodeParameterList::CheckAtMostOneFirstDefault()
{
	NodeParameterListIterator Next(*this);
	NodeParameter * Parm ;
	NodeParameter * FoundFirst = 0 ;
	int FirstExtra = 1;
	while (Parm = Next()) if (!Parm->IsFirstDefault()) {
		if (FoundFirst) {
			Parm->FirstDefault = 1 ;
			// cerr << "Also setting for `" << Parm->Name << "'.\n";
		}
	} else if (!FoundFirst) FoundFirst = Parm;
	else {
		if (FirstExtra) {
			FirstExtra = 0 ;
/*
 *			cerr <<
 *			"First occurence of `FirstDefault' is for parameter `"
 *				<< FoundFirst->Name << "'.\n" ;
 */
		}
		yyerror("more than one parameter marked `FirstDefault'");
	}
}

void NodeParameter::OutTeX(OutTokens& Out)
{
	// cerr << "NodeParameter for " << Name << "\n" ;
	Out.NextOut("\\item{");
	Out.NextTeXttOut(Name);
	Out.NextConcat(": ");
	HelpLine->OutTeXEndDot(Out) ;
	Out.TeXIndexEntry(Name);
	Out.FlushLine();
	Out.NewLine();

	FullDescription->OutTeX(Out);
	Out.FlushLine();
	Out.NewLine();

	if (FirstDefault) {
		Out.NextFillOut( "This is the first default parameter.");
		Out.FlushLine();
	}
	Out.NextTeXttOut(Name);
	Out.NextFillOut("is of type");
/*
 *	cerr << "Calling WhatTypeString(this, " << DataDecPrefixType <<
 *		")\n" ;
 */
	Out.NextTeXttOut(TeXOutType(this));
	Out.NextConcat(".");
	if (Type) if (Type->ChangeableFlag) Out.NextFillOut(
		"This parameter can be changed interactively.");

	if (Size) {
		Out.NextTeXttOut(Name);
		Out.NextFillOut("is an array of size");
		Out.NextFillOut("$\\geq$");
		Out.NextOut(Size->Lower);
		Out.NextOut("and $\\leq$");
		Out.NextOut(Size->Upper);
		Out.NextConcat(".");
		Out.NextFillOut(
		"The following table contains the default array values.");
		Out.NewLine();
		// cerr << "Array default\n" ;
		Default->TeXOut(Out,Type->Type);
		Out.FlushLine();
		Out.NewLine();
	} else if (Default) {
		int emit = Default->IsValueDefined() ;
		if (!Type) emit = IsReference(ClassType) ;
		if (emit) {
			Out.NextFillOut("The default value is");
			if (Type) Default->TeXOut(Out,Type->Type);
			else Out.NextTeXttOut(Default->Item.Str) ;
			Out.NextConcatCond('.');
		}
		if (Lower) if (Lower->IsValueDefined()) {
			Out.NextTeXttOut(Name);
			Out.NextFillOut("must be $\\geq$");
			Lower->TeXOut(Out,Type->Type);
			Out.NextFillOut("and $\\leq$");
			Upper->TeXOut(Out,Type->Type);
			Out.NextConcatCond('.');
			Out.FlushLine();
			Out.NewLine();
		}
	}

	if (LegalCheck) {
		Out.NextTeXttOut(Name);
		Out.NextFillOut("must be legal in this context.");
		Out.FlushLine();
		Out.NewLine();
	}
	Out.NextConcat("}");
	Out.NewLine();

}

void NodeParameterList::OutTeX(OutTokens& Out)
{
	Out.NextFillOut("\\begin{itemize}");
	Out.FlushLine();
	
	NodeParameter * OneParameter ;
	NodeParameterListIterator Next(*this);

	while (OneParameter = Next()) OneParameter->OutTeX(Out);

	Out.NextFillOut("\\end{itemize}");
	Out.FlushLine();
}



void NodeParameterList::BriefOutTeX(OutTokens& Ot)
{
	Ot.NextFillOut("\\begin{itemize}");
	Ot.FlushLine();
	
	NodeParameter * OneParameter ;
	NodeParameterListIterator Next(*this);

	while (OneParameter = Next()) {
		Ot.NextOut("\\item{");
		Ot.NextTeXttOut(OneParameter->Name) ;
		Ot.NextConcat(": ");
		OneParameter->HelpLine->OutTeXEndDot(Ot);
		Ot.NextConcat("}");
		Ot.TeXIndexEntry(OneParameter->Name) ;
		Ot.FlushLine();
	}
	Ot.NextFillOut("\\end{itemize}");
	Ot.FlushLine();
}

