/*  ctorinit.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <fstream.h>
#include <stdio.h>
#include "fileios.h"
#include <string.h>
#include "ctorinit.h"
#include "debug.h"
#include "buftype.h"
#include "genmenu.h"
#include "timenum.h"
#include "myfloat.h"
#include "texutil.h"
#include "mkstr.h"

static const char * arith_type = "(ArithType::ArithCapabilities)ArithType::" ;

struct BaseClassTexDescribe {
	UsrObjParmType type ;
	const char * class_name ;
	const char * description ;
	const char ** notes ;
};

const char * scale_notes = "Ordinarily plots are dynamically scaled \
and these limits are set to allow this." ;

const char * plot_sample_notes ="The current plotting nodes either \
fix the number of samples in a plot at the block size or allow \
the user to change the number of samples if the data is not blocked.\
In some cases these can be overridden with options to fix the \
samples of blocks per plot." ;

const char * arith_type_notes ="The arithmetic types are given in \
Table~\\PageRef{Sec:ArithType}. The default and Min {\\tt enum} values \
are prefixed with {\\tt ArithType}. This was removed to save space \
in the table.";

const char * stream_notes="The stucture that describes data streams is \
documented in Section~\\PageRef{Sec:StreamStr}. The default value for \
streams is {\\tt new StreamStr(}{\\it name in table}{\\tt )}. The \
constructor was removed from the table (only the parameter was left) \
to save space and \
\\DppNm{StreamNotInitialize} was shortened tp \\DppNm{NotInitialized}." ;

const char * buffer_type_notes= "Currently only \\Index{circular buffers} \
(\\DppNm{CircBufDes}) are supported." ;

const char * timing_type_notes = "The {\\tt TIMING\\_TYPE} default, min and \
max {\\tt enum} values have {\\tt TimingType} as a prefix. This was deleted \
from the table to save space." ;

const char * overlap_notes = "Any overlapped data must be stored internally. \
The node will not be called until sufficient input is availible for the first \
execution. After that the overlapped data may be overwritten on the input \
buffer." ;

const char * delta_out_notes = "\\DppNm{DELTA\\_OUT} is used to set \
the output link parameter \\DppNm{IncrementOut}. Sorry!" ;

BaseClassTexDescribe base_class_tex_describe[] = {
	{DfDouble,"MAXIMUM_X","maximum X plot value",&scale_notes},
	{DfDouble,"MAXIMUM_Y","maximum Y plot value",&scale_notes},
	{DfDouble,"MINIMUM_X","minimum X plot value",&scale_notes},
	{DfDouble,"MINIMUM_Y","minimum Y plot value",&scale_notes},
	{DfDouble,"XY_SAMPLES_PER_PLOT","number of samples in an eye plot",
		&plot_sample_notes},
	{DfEntity,"ARITH_TYPE_IN","input arithmetic type",&arith_type_notes},
	{DfEntity,"ARITH_TYPE_OUT","output arithmetic type",&arith_type_notes},
	{DfEntity,"DYNAMIC_TYPE","fixed or dynamic input data type"},
	{DfEntity,"NETWORK","class \\DppNm{ProcessNet}"},
	{DfEntity,"PLOTTING_STREAM_TYPE","eye plot or linear plot"},
	{DfEntity,"STREAM_IN","input data stream description",&stream_notes},
	{DfEntity,"STREAM_OUT","output data stream description",&stream_notes},
	{DfEntity,"TIMING_TYPE","linear or undefined timing",&timing_type_notes},
	{DfInt,"TYPE","type of buffering",&buffer_type_notes},
	{DfInt16,"IN","number of input channels"},
	{DfInt16,"NUMBER_BLOCKS","number of blocks in one display",
		&plot_sample_notes},
	{DfInt16,"OUT","number of output channels"},
	{DfInt16,"SCALE_FLAG","not used"},
	{DfInt32,"BLOCK_SIZE","number of samples in a block"},
	{DfInt32,"DELAY_IN","not used"},
	{DfInt32,"DELTA_IN","input samples for {\\tt DELTA\\_OUT} outputs"},
	{DfInt32,"DELTA_OUT","output samples for {\\tt DELTA\\_IN} inputs",
		&delta_out_notes},
	{DfInt32,"ELEMENT_SIZE","input sample size in words"},
	{DfInt32,"ELEMENT_SIZE_OUT","output sample size in words"},
	{DfInt32,"NODE_DELAY","sampless generated with {\\it no} input"},
	{DfInt32,"OVERLAP","overlapped input samples ",&overlap_notes},
	{DfInt32,"SIZE","buffer size"},
	{DfString,"CAPTION","plot or listing caption"},
	{DfInt16,0}
};


const char * UsrObjParmTypeName[] = {"int16","int32","int","char *",
	"double","UserEntity"};

CtorDefaults * CtorBaseClassDefaults ;


CtorDefaults::CtorDefaults(CtorDefaultsInit Init)
{	Init(&Parameters, NumberParameters, &BaseFunctionName, &IncludeFileName,
		&BaseCheckSafe, KernelFlag,&parent_class,&purpose_tex);
	if (NumberParameters >= MaxNumberDfNodeParams)
	    DbgError("CtorDefaults::CtorDefaults", "too many parameters");
}

void CtorDefaults::EmitBaseFunctionName(MofStream& HeaderOut)
{
	HeaderOut.PushSecondFileSelect(BaseStreamBuf::Off);
	HeaderOut << BaseFunctionName  ;
	HeaderOut.PopSecondFileSelect();
	HeaderOut.PushFirstFileSelect(BaseStreamBuf::Off);
	HeaderOut << "TargetNode" ;
	HeaderOut.PopFirstFileSelect();
}

void CtorDefaults::EmitDfNodeParam(MofStream& CppOut)
{
	CppOut << ":\n\t" ;
	CppOut.PushSecondFileSelect(BaseStreamBuf::Off);
	CppOut << BaseFunctionName ;
	CppOut << "(Name" ;
	EmitParameters(CppOut);
	CppOut.PopSecondFileSelect();

	CppOut.PushFirstFileSelect(BaseStreamBuf::Off);
	CppOut << "TargetNode(Name" ;
	EmitParameters(CppOut,"IN","0");
	EmitParameters(CppOut,"OUT","0");
	CppOut << ", in_links, out_links, exec_seq,\n\t\texec_type, delay" ;
	// EmitParameters(CppOut,"NODE_DELAY","0");
	CppOut.PopFirstFileSelect();
	CppOut << ")\n" ;
}

void CtorDefaults::EmitParameters(MofStream& CppOut, const char * Name,
	const char * Default)
{
	int CharCount = 12 + strlen(BaseFunctionName) ;
	const LocBufLimit = 79 ;
	char Temp[LocBufLimit];
	int DidEmit = 0 ;
	for (int i = 0 ; i < NumberParameters; i++) {
		UserObjParameter& ThisParam =
			Parameters[i];
		if (Name) if (strcmp(Name,ThisParam.UserName)) continue ;
		DidEmit = 1 ;
		CppOut << ", " ;
		const char * StrOut ;
/*
 *		cout << "CtorDefaults::EmitParameters - Expression = `" <<
 *			CtorParamFound[i].Expression << "'\n" ;
 */
		if (!(StrOut = CtorParamFound[i].Expression)) {
			char Buf[80];
			const char * StrTemp ;
			StrTemp = Buf ;
			switch(ThisParam.Type) {
case DfInt:
case DfInt16:
case DfInt32:
				// strcpy(StrTemp,
				//	dec(ThisParam.DefaultValue.Integer));
				sprintf(Buf,"%d",
					ThisParam.DefaultValue.Integer);
				break ;
case DfEntity:
case DfString:
				StrTemp = ThisParam.DefaultValue.String;
				break ;
case DfDouble:
				{
					double Val = ThisParam.DefaultValue.Double ;
					// StrTemp = form(FloatFormat(Val),Val);
					sprintf(Buf,FloatFormat(Val),Val);
				}
				break ;
default:
				DbgError("EmitDfNodeParam","bad type");
				break ;
		
			}
			if (strlen(StrTemp) > LocBufLimit -2) DbgError(
				"EmitDfNodeParam","string too long");
			StrOut = strcpy(Temp,StrTemp);
		}
		CharCount+=strlen(StrOut)+2;
		if (CharCount > 75) {
			CharCount = 8;
			CppOut << "\n\t" ;
		}
		CppOut << StrOut ;
	}
	if (Default && !DidEmit) CppOut << ", " << Default ;
}


UserObjParameter::UserObjParameter(UsrObjParmType type, const char * name,
        NodeParameterValue def, NodeParameterValue min,
        NodeParameterValue max, const char *type_name)
{
    // cout << "UserObjParameter init\n" ;
    Type = type;
    UserName = name;
    DefaultValue = def;
    Min = min;
    Max = max ;
    if (type_name) TypeName = type_name ;
    else TypeName = UsrObjParmTypeName[Type] ;
}


#define SET (*Param)[i++] = * new UserObjParameter

void DfNodeStrCtorInit(UserObjParameter ** Param, int& Size,
    const char ** CtorBaseName, const char ** IncludeFileName,
    const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
    // cout << "DfNodeCtorInit\n" ;
    
    *CtorBaseName = "DfNode" ;
    *IncludeFileName = "strnode.h" ;
    *SafeCheck = "DfNode" ;
    Kernel = 1;
	*base_class = "TargetNode" ;
    *tex_describe = "all DSP nodes" ;
    Size = 10;
    UserObjParameter * Temp = new UserObjParameter[Size+1] ;
    if (!Temp) {
        cerr << "No memory.\n" ;
        exit(1);
    }
    *Param = Temp ;
    int i = 0 ;
    SET (DfInt16, "IN",     1, 0,       LARGE_16);
    SET (DfInt16, "OUT",        1, 0,       LARGE_16);
    SET (DfEntity,"STREAM_IN",  "new StreamStr(StreamNotInitialized)",
                            0, 0, "StreamStr");
    SET (DfEntity,"STREAM_OUT", "new StreamStr(StreamNotInitialized)",
                            0, 0, "StreamStr");
    SET (DfInt32, "NODE_DELAY", 0, -LARGE_32,   LARGE_32);
    SET (DfInt32, "DELTA_IN",   1, 1,       LARGE_32);
    SET (DfInt32, "DELTA_OUT",  1, 1,       LARGE_32);
    SET (DfInt32, "OVERLAP",    0, 0,       LARGE_32);
    SET (DfInt32, "DELAY_IN",   0, 0,       LARGE_32);
    SET (DfEntity, "TIMING_TYPE",   "TimingTypeLinear", "TimingTypeLinear",
        "TimingTypeRandom");
    SET (DfInt16, "",       0, 0,       0);
    if (i != Size+1) DbgError("DfNodeCtorInit","bad size");
};

static CtorDefaults DfNodeStrCtorDefaults(DfNodeStrCtorInit) ;



// Following is used as second operand for `>>' 
// All nodes should have this base class in their hierarchy except
// Signal generating nodes



 
void DspNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "DspNodeCtorInit\n" ;
	
	*CtorBaseName = "Node" ;
	*IncludeFileName = "node.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "DfNode" ;
	*tex_describe = "all DSP nodes" ;
	Size = 10;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "IN",		1, 0,		LARGE_16);
	SET (DfInt16, "OUT",		1, 0,		LARGE_16);
	SET (DfEntity,"STREAM_IN",	"new StreamStr(StreamNotInitialized)",
							0, 0, "StreamStr");
	SET (DfEntity,"STREAM_OUT",	"new StreamStr(StreamNotInitialized)",
							0, 0, "StreamStr");
	SET (DfInt32, "NODE_DELAY",	0, -LARGE_32, 	LARGE_32);
	SET (DfInt32, "DELTA_IN",	1, 1, 		LARGE_32);
	SET (DfInt32, "DELTA_OUT",	1, 1, 		LARGE_32);
	SET (DfInt32, "OVERLAP",	0, 0, 		LARGE_32);
	SET (DfInt32, "DELAY_IN",	0, 0, 		LARGE_32);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("DspNodeCtorInit","bad size");
};

static CtorDefaults DspNodeCtorDefaults(DspNodeCtorInit) ;

void ProcessNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "ProcessNodeCtorInit\n" ;
	
	*CtorBaseName = "ProcessNode" ;
	*IncludeFileName = "procnode.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "ProcessNodeStr" ;
	*tex_describe = "DSP processing" ;
	Size = 13;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "IN",		1, 0,		LARGE_16);
	SET (DfInt16, "OUT",		1, 0,		LARGE_16);
	SET (DfInt32, "ELEMENT_SIZE",	1, 1,		LARGE_32);
	SET (DfInt32, "NODE_DELAY",	0, -LARGE_32, 	LARGE_32);
	SET (DfInt32, "DELTA_IN",	1, 1, 		LARGE_32);
	SET (DfInt32, "DELTA_OUT",	1, 1, 		LARGE_32);
	SET (DfInt32, "OVERLAP",	0, 0, 		LARGE_32);
	SET (DfInt32, "DELAY_IN",	0, 0, 		LARGE_32);
	SET (DfInt32, "ELEMENT_SIZE_OUT",0, 0,		LARGE_32);
	SET (DfInt32, "BLOCK_SIZE",	0, 0,		LARGE_32);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfEntity, "ARITH_TYPE_IN",	"(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined",
		"(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined", "(ArithType::ArithCapabilities)ArithType::MaxArithTypes");
	SET (DfEntity, "ARITH_TYPE_OUT", "(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined",
		"(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined", "(ArithType::ArithCapabilities)ArithType::MaxArithTypes");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("ProcessNodeCtorInit","bad size");
};

static CtorDefaults ProcessNodeCtorDefaults(ProcessNodeCtorInit) ;


void ProcessNodeStrCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "ProcessNodeCtorInit\n" ;
	
	*CtorBaseName = "ProcessNodeStr" ;
	*IncludeFileName = "procstr.h" ;
	*SafeCheck = "UserEntity" ;
	Kernel = 1;
	*base_class = "Node" ;
	*tex_describe = "DSP processing" ;
	Size = 10;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "IN",		1, 0,		LARGE_16);
	SET (DfInt16, "OUT",		1, 0,		LARGE_16);
	SET (DfEntity,"STREAM_IN",	"new StreamStr(StreamNotSet)",
							0, 0, "StreamStr");
	SET (DfEntity,"STREAM_OUT",	"new StreamStr(StreamNotSet)",
							0, 0, "StreamStr");
	SET (DfInt32, "NODE_DELAY",	0, -LARGE_32, 	LARGE_32);
	SET (DfInt32, "DELTA_IN",	1, 1, 		LARGE_32);
	SET (DfInt32, "DELTA_OUT",	1, 1, 		LARGE_32);
	SET (DfInt32, "OVERLAP",	0, 0, 		LARGE_32);
	SET (DfInt32, "DELAY_IN",	0, 0, 		LARGE_32);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("ProcessNodeCtorInit","bad size");
};

static CtorDefaults ProcessNodeStrCtorDefaults(ProcessNodeStrCtorInit) ;

static void SignalStrNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "SigNodeCtorInit\n" ;
	
	*CtorBaseName = "SignalStr" ;
	*IncludeFileName = "signode.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "Node" ;
	*tex_describe = "DSP signals" ;
	Size = 4;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "OUT",		1, 0,		LARGE_16);
	SET (DfEntity,"STREAM_OUT",	"new StreamStr(StreamReal)",
							0, 0, "StreamStr");
	SET (DfInt32, "DELTA_OUT",	1, 1, 		LARGE_32);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("SigNodeCtorInit","bad size");
};

static CtorDefaults SignalStrNodeCtorDefaults(SignalStrNodeCtorInit) ;

static void SignalNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "SigNodeCtorInit\n" ;
	
	*CtorBaseName = "Signal" ;
	*IncludeFileName = "sigbase.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "SignalStr" ;
	*tex_describe = "DSP signals" ;
	Size = 6;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "OUT",		1, 0,		LARGE_16);
	SET (DfInt32, "ELEMENT_SIZE",	1, 1,		LARGE_32);
	SET (DfInt32, "DELTA_OUT",	1, 1, 		LARGE_32);
	SET (DfInt32, "BLOCK_SIZE",	0, 0,		LARGE_32);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
        SET (DfEntity, "ARITH_TYPE_OUT", "(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined",
                "(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined", "(ArithType::ArithCapabilities)ArithType::MaxArithTypes");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("SigNodeCtorInit","bad size");
};

static CtorDefaults SignalNodeCtorDefaults(SignalNodeCtorInit) ;


static void DisplayNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "DisplayNodeCtorInit\n" ;
	
	*CtorBaseName = "DisplayNode" ;
	*IncludeFileName = "display.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "DisplayNodeStr" ;
	*tex_describe = "plotting" ;
	Size = 6;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "IN",		1, 0,		LARGE_16);
	SET (DfInt32, "DELTA_IN",	1, 1, 		LARGE_32);
	SET (DfInt32, "ELEMENT_SIZE",	1, 1,		LARGE_32);
	SET (DfInt32, "BLOCK_SIZE",	0, 0,		LARGE_32);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
        SET (DfEntity, "ARITH_TYPE_IN", "(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined",
                "(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined", "(ArithType::ArithCapabilities)ArithType::MaxArithTypes");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("DisplayNodeCtorInit","bad size");
};

static CtorDefaults DisplayNodeCtorDefaults(DisplayNodeCtorInit) ;

static void DisplayNodeStrCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "DisplayNodeCtorInit\n" ;
	
	*CtorBaseName = "DisplayNodeStr" ;
	*IncludeFileName = "dsplstr.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "Node" ;
	*tex_describe = "DSP output" ;
	Size = 4;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16, "IN",		1, 0,		LARGE_16);
	SET (DfInt32, "DELTA_IN",	1, 1, 		LARGE_32);
	SET (DfEntity,"STREAM_IN",	"new StreamStr(StreamNotSet)",
							0, 0, "StreamStr");
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfInt16, "",		0, 0,		0);
	if (i != Size+1) DbgError("DisplayNodeCtorInit","bad size");
};

static CtorDefaults DisplayNodeStrCtorDefaults(DisplayNodeStrCtorInit) ;

static void PlotNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "PlotNodeCtorInit\n" ;
	*CtorBaseName = "PlotNode" ;
	*IncludeFileName = "plotnd.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "DisplayNodeStr" ;
	*tex_describe = "plotting" ;
	Size = 4;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16,	"IN",		1, 	0,		LARGE_16);
	SET (DfEntity,"STREAM_IN",	"new StreamStr(StreamNotSet)",
							0, 0, "StreamStr");
	SET (DfInt16,	"SCALE_FLAG",	0, 	0,		1);
	SET (DfEntity, "TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults PlotNodeCtorDefaults(PlotNodeCtorInit) ;

static void GenPlotNodeStrCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "GenPlotNodeCtorInit\n" ;
	*CtorBaseName = "GenericPlotStr" ;
	*IncludeFileName = "gpltstr.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "PlotNode" ;
	*tex_describe = "plotting" ;
	Size = 13;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16,	"IN",		1, 	0,		LARGE_16);
	SET (DfEntity,"STREAM_IN",	"new StreamStr(StreamNotSet)",
							0, 0, "StreamStr");
	SET (DfString,	"CAPTION",	"0", 	0,		0);
	SET (DfDouble,	"MINIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MINIMUM_X",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_X",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfInt16,	"NUMBER_BLOCKS",1, 	0,		LARGE_16);
	SET (DfInt16,	"SCALE_FLAG",	0, 	0,		1);
	SET (DfEntity,	"TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfEntity,	"DYNAMIC_TYPE", "PlotDynStatic", "PlotDynStatic",
		"PlotDynDyn") ;
	SET (DfDouble,	"XY_SAMPLES_PER_PLOT",
					0.0,		0.0,	LARGE_DOUBLE);
	SET (DfEntity,	"PLOTTING_STREAM_TYPE",
					"PlotYs",
						"PlotYs",
						"PlotPairs");
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults GenPlotNodeStrCtorDefaults(GenPlotNodeStrCtorInit) ;

static void GenPlotNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "GenPlotNodeCtorInit\n" ;
	*CtorBaseName = "GenericPlot" ;
	*IncludeFileName = "genplot.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "GenericPlotStr" ;
	*tex_describe = "plotting" ;
	Size = 13;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt16,	"IN",		1, 	0,		LARGE_16);
	SET (DfInt32,	"ELEMENT_SIZE",	1, 	1,		LARGE_32);
	SET (DfString,	"CAPTION",	"0", 	0,		0);
	SET (DfDouble,	"MINIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MINIMUM_X",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_X",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfInt16,	"NUMBER_BLOCKS",1, 	0,		LARGE_16);
	SET (DfInt16,	"SCALE_FLAG",	0, 	0,		1);
	SET (DfInt32,	"BLOCK_SIZE",	0, 0,		LARGE_32);
	SET (DfEntity,	"TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfDouble,	"XY_SAMPLES_PER_PLOT",
					0.0,		0.0,	LARGE_DOUBLE);
	SET (DfEntity,	"PLOTTING_STREAM_TYPE",
					"PlotYs",
						"PlotYs",
						"PlotPairs");
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults GenPlotNodeCtorDefaults(GenPlotNodeCtorInit) ;

static void BlockPlotNodeStrCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "BlockPlotNodeCtorInit\n" ;
	*CtorBaseName = "GenericBlockPlotStr" ;
	*IncludeFileName = "blkpltstr.h" ;
	*SafeCheck = "DfNode" ;
	*base_class = "GenericPlotStr" ;
	*tex_describe = "plotting" ;
	Kernel = 1;
	Size = 10;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfEntity,"STREAM_IN",	"new StreamStr(StreamNotSet)",
							0, 0, "StreamStr");
	SET (DfString,	"CAPTION",	"0", 	0,		0);
	SET (DfDouble,	"MINIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MINIMUM_X",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_X",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfInt16,	"NUMBER_BLOCKS",1,	1,		LARGE_16);
	SET (DfInt16,	"SCALE_FLAG",	0, 	0,		1);
	SET (DfEntity,	"TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfEntity,	"DYNAMIC_TYPE", "PlotDynStatic", "PlotDynStatic",
		"PlotDynDyn") ;
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults BlockPlotNodeStrCtorDefaults(BlockPlotNodeStrCtorInit) ;

static void BlockPlotNodeCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	// cout << "BlockPlotNodeCtorInit\n" ;
	*CtorBaseName = "GenericBlockPlot" ;
	*IncludeFileName = "blockplt.h" ;
	*SafeCheck = "DfNode" ;
	Kernel = 1;
	*base_class = "GenericPlot" ;
	*tex_describe = "two dimensional plotting" ;
	Size = 10;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt32,	"ELEMENT_SIZE",	1, 	1,		LARGE_32);
	SET (DfString,	"CAPTION",	"0", 	0,		0);
	SET (DfDouble,	"MINIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_Y",	0.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MINIMUM_X",	-16.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfDouble,	"MAXIMUM_X",	15.0,	-LARGE_DOUBLE,	LARGE_DOUBLE);
	SET (DfInt16,	"NUMBER_BLOCKS",1,	1,		LARGE_16);
	SET (DfInt16,	"SCALE_FLAG",	0, 	0,		1);
	SET (DfInt32,	"BLOCK_SIZE",	0, 0,		LARGE_32);
	SET (DfEntity,	"TIMING_TYPE",	"TimingTypeLinear", "TimingTypeLinear",
		"TimingTypeRandom");
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults BlockPlotNodeCtorDefaults(BlockPlotNodeCtorInit) ;

static void SchedulerCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	*CtorBaseName = "NetControl" ;
	*IncludeFileName = "netcnt.h" ;
	*SafeCheck = "NetControl" ;
	Kernel = 0;
	*base_class = "UserEntity" ;
	*tex_describe = "network control" ;
	Size = 1;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfEntity,	"NETWORK",	"DefProcessNet", 0, 0, "ProcessNet");
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults SchedulerCtorDefaults(SchedulerCtorInit) ;

static void NetworkCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	*CtorBaseName = "ProcessNet" ;
	*IncludeFileName = "network.h" ;
	*SafeCheck = "ProcessNet" ;
	Kernel = 0;
	*base_class = "UserEntity" ;
	*tex_describe = "networks" ;
	Size = 0;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0;
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults NetworkCtorDefaults(NetworkCtorInit) ;

static void BufferCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	*CtorBaseName = "BufferDescript" ;
	*IncludeFileName = "buffer.h" ;
	*SafeCheck = "BufferDescript" ;
	Kernel = 0;
	*base_class = "UserEntity" ;
	*tex_describe = "buffering" ;
	Size = 2;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0 ;
	SET (DfInt,"TYPE", (int) CircBufferType,0, (int) (MaxInvalidBufferType-1));
	SET (DfInt32,	"SIZE",	512, 	1,		LARGE_32);
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults BufferCtorDefaults(BufferCtorInit) ;

static void MiscellaneousCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	*CtorBaseName = "Miscellaneous" ;
	*IncludeFileName = "miscel.h" ;
	*SafeCheck = "UserEntity" ;
	Kernel = 0;
	*base_class = "UserEntity" ;
	*tex_describe = "miscellaneous" ;
	Size = 0;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0;
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults MiscellaneousCtorDefaults(MiscellaneousCtorInit) ;

static void SystemCtorInit(UserObjParameter ** Param, int& Size,
	const char ** CtorBaseName, const char ** IncludeFileName,
	const char ** SafeCheck, int& Kernel,
	const char ** base_class, const char ** tex_describe)
{
	*CtorBaseName = "NetworkSystem" ;
	*IncludeFileName = "netsys.h" ;
	*SafeCheck = "NetworkSystem" ;
	Kernel = 0;
	*base_class = "Miscellaneous" ;
	*tex_describe = "network systems" ;
	Size = 0;
	UserObjParameter * Temp = *Param = new UserObjParameter[Size+1] ;
	int i = 0;
	SET (DfInt16, 	"",		0, 	0,		0);
};

static CtorDefaults SystemCtorDefaults(SystemCtorInit) ;

#undef SET


static CtorDefaults * CtorBaseClassDefaultOptions[] = {
	&DfNodeStrCtorDefaults,
	&ProcessNodeCtorDefaults,
	&ProcessNodeStrCtorDefaults,
	&DspNodeCtorDefaults,
	&SignalNodeCtorDefaults,
	&SignalStrNodeCtorDefaults,
	// &ReadNodeCtorDefaults,
	// &WriteNodeCtorDefaults,
	&DisplayNodeStrCtorDefaults,
	&DisplayNodeCtorDefaults,
	&PlotNodeCtorDefaults,
	&GenPlotNodeCtorDefaults,
	&GenPlotNodeStrCtorDefaults,
	&BlockPlotNodeCtorDefaults,
	&BlockPlotNodeStrCtorDefaults,
	&SchedulerCtorDefaults,
	&NetworkCtorDefaults,
	&BufferCtorDefaults,
	&MiscellaneousCtorDefaults,
	&SystemCtorDefaults,
	0
};


const char * GetBaseClassName()
{
	if (!CtorBaseClassDefaults) DbgError("GetBaseClassName","null base");
	return CtorBaseClassDefaults->BaseFunctionName;
}


int InitFoundBaseFunctionName(const char * Name, const char * NodeName)
{
	for (CtorDefaults ** Def = CtorBaseClassDefaultOptions ; *Def;Def++) {
		// cout << "Checking `" << (*Def)->BaseFunctionName << "'\n" ;
		if (!strcmp(Name,(*Def)->BaseFunctionName)) {
			CtorBaseClassDefaults = *Def ;
			WriteBaseClass(NodeName,GetBaseClassName());
			return 1 ;
		}
	}
	return 0;
}

static void table_head(const char * fields, const char * heading,
	const char *placement =0, int footnotesize=0)
{
	cout << "\n\\begin{table}" ;
	// if (placement) cout << "[" << placement << "]" ;
	cout << "\n\\begin{center}\n" ;
	if (footnotesize) cout << "\\footnotesize\n" ;
	cout << "\\begin{tabular}{" << fields << "} \\hline\n" ;
	cout << heading << " \\\\ \\hline\n" ;
}

static void end_table_out()
{
	cout << "\\end{table}\n\n" ;
}

static const char * TotalCtorParts = "TotalCtorParts" ;

static void table_end(const char * caption, const char * Tab,
	const char * index = 0, int skip_end=0,int part=0)
{
	cout << "\\hline\n\\end{tabular}\n" ;
	cout << "\\caption{" << caption ;
	if (part) cout << " (part " << part << " of \\" << TotalCtorParts << "{})";
	cout << "}\n";
	if (index) cout << "\\index{" << index << "}\n" ;
	if (part < 2) cout << "\\label{" << Tab << "}\n" ;
	cout << "\\end{center}\n" ;
	if (!skip_end) end_table_out();
}

static int parameter_compare(const void * a, const void * b)
{
    UserObjParameter * A = (UserObjParameter *) a ;
    UserObjParameter * B = (UserObjParameter *) b ;
    if (!A) if (!B) return 0 ; else return -1 ;
    if (!B) return 1 ;

    const char * Aa = A->UserName ;
    const char * Bb = B->UserName ;
    if (!Aa) if (!Bb) return 0; else return -1 ;
    if (!Bb) return 1 ;
    return TeXstrcmp(Aa,Bb);
}
static int ctor_base_compare(const void * a, const void * b)
{
    const CtorDefaults ** A = (const CtorDefaults **) a ;
    const CtorDefaults ** B = (const CtorDefaults **) b ;
    if (!A) if (!B) return 0 ; else return -1 ;
    if (!B) return 1 ;

    const char * Aa = (*A)->BaseFunctionName ;
    const char * Bb = (*B)->BaseFunctionName ;
    if (!Aa) if (!Bb) return 0; else return -1 ;
    if (!Bb) return 1 ;
    return TeXstrcmp(Aa,Bb);
}

static const char * DppNm(const char * str, const char * omit_prefix=0,
	const char * second_omit=0)
{
	if (omit_prefix) 
		if (!strncmp(omit_prefix,str,strlen(omit_prefix)))
			str += strlen(omit_prefix);
	if (second_omit)
		if (!strncmp(second_omit,str,strlen(second_omit)))
            str += strlen(second_omit);
	const buf_size = 8192;
	static char buf[buf_size+1] ;
	strcpy(buf,"{\\tt ") ;
	char * dest = buf + strlen(buf) ;
	for(const char * pt = str; *pt; pt++) {
		if(*pt == '_') *dest++ = '\\' ;
		*dest++ = *pt ;
	}
	strcpy(dest,"}\\index{");
	strcat(dest,str);
	strcat(dest,"}");
	return buf ;
}


void CtorDefaults::param_table_out()
{
	qsort((char *)Parameters,NumberParameters,sizeof(Parameters[0]),
		parameter_compare);
	cout << "\\DppNm{" << BaseFunctionName << "} & " ;
	const max_length = 40 ;
	int length = 0 ;
	for(int i = 0 ; i < NumberParameters; i++) {
		length += strlen(Parameters[i].UserName) ;
		if (length > max_length) {
			cout << "\\\\\n & \n" ;
			length = strlen(Parameters[i].UserName) ;
		}
		cout <<  DppNm(Parameters[i].UserName) << "\n" ;
	}
	cout << "\\\\\n" ;
}

void CtorDefaults::table_out()
{
	const char * inc = IncludeFileName ;
	if (!strcmp(inc,"strnode.h") && !strcmp(BaseFunctionName,"DfNode"))
		inc = "dfnode.h" ;
	cout << "\\DppNm{" << BaseFunctionName << "} & " <<
		purpose_tex << " & \\DppNm{" << parent_class << "}\n\t& \\DppNm{"
		<< inc  << "} \\\\\n" ;
}

struct ParamStruct {
	CtorDefaults * cls ;
	UserObjParameter * param ;
	void set(CtorDefaults * c, UserObjParameter * p)
	{
		cls=c;
		param=p;
	}
	void out(int list_class,int righ_flag);
	int equal(ParamStruct& ck);
};

int ParamStruct::equal(ParamStruct& ck)
{
	// if (cls != ck.cls) return 0 ;
	return param->equal(*(ck.param));
}




int NodeParameterValue::equal(UsrObjParmType type, NodeParameterValue ck)
{
	switch(type) {
case DfInt16:
case DfInt32:
case DfInt:
		return Integer == ck.Integer ;
case DfEntity:
case DfString:
		if (!String) return !ck.String ;
		if (!ck.String) return 0 ;
		return !strcmp(String,ck.String);
case DfDouble:
		return Double == ck.Double ;
		break ;
default:
		cout << "NodeParameterValue::equal, BAD TYPE: " << (int) type ;
		break ;
	}
	return 0 ;
}

static const char * remove_constructor(const char * base,const char *ctr)
{
	const buf_size = 1024 ;
	static char buf[buf_size] ;
	int length = strlen(ctr);
	int base_length = 0 ;
	if (!strncmp(base,ctr,length)) if (base[base_length = strlen(base)-1]==')') {
		strcpy(buf,base+length);
		buf[base_length-length] = '\0' ;
		return buf ;
	}
	return base ;
}

static const char * remove_prefix(const char * base,const char *ctr,
	const char * alt=0)
{
	const buf_size = 1024 ;
	static char buf[buf_size] ;
	int length = strlen(ctr);
	if (strncmp(base,ctr,length)) {
		if (!alt) return base ;
		length = strlen(alt);
		if (strncmp(base,alt,length)) return base ;
	}
    strcpy(buf,base+length);
    return buf ;
}

void NodeParameterValue::out(UsrObjParmType type, const char * ter)
{
	switch(type) {
case DfInt16:
case DfInt32:
case DfInt:
		cout << Integer ;
		break ;
case DfEntity:
case DfString: {
 		const char * s1 = remove_constructor(String,"new StreamStr(") ;
 		s1 = Concatenate(remove_prefix(s1,"TimingType"));
		const char *name = remove_prefix(s1,arith_type, "ArithType") ;
/*
 *		const char * name = remove_prefix(remove_constructor(
 *           String,"new StreamStr("),"TimingType"),arith_type,"ArithType") ;
 */
		if (!strcmp("StreamNotInitialized", name)) name = "NotInitialized" ; 
		cout << DppNm(name) ;
		break ;
		}
case DfDouble:
		cout << Double ;
		break ;
default:
		cout << "BAD TYPE: " << (int) type ;
		break ;
	}
	if (ter) cout << ter ;
}

static int is_null(UsrObjParmType type,NodeParameterValue val)
{
	switch(type) {
case DfInt16:
case DfInt32:
case DfInt:
case DfDouble:
        return 0 ;
case DfEntity:
case DfString:
		if (!val.String) return 1 ;
		if (!strcmp(val.String,"0")) return 1 ;
		return 0 ;
default:
        cout << "is_null, BAD TYPE: " << (int) type ;
    }
	return 1 ;
}

int UserObjParameter::equal(UserObjParameter&ck)
{
	if (Type != ck.Type) return 0 ;
	if (strcmp(TypeName,ck.TypeName)) return 0 ;
	if (strcmp(UserName,ck.UserName)) return 0 ; 
	if (!DefaultValue.equal(Type,ck.DefaultValue)) return 0 ;
	if (!Min.equal(Type,ck.Min)) return 0 ;
	return Max.equal(Type,ck.Max) ;
}

void UserObjParameter::param_out(int right_flag)
{
	cout << DppNm(UserName) ;
	if (!right_flag) return ;
	cout << " & " << DppNm(TypeName,arith_type) << " & " ;
	if (is_null(Type,DefaultValue)) cout << "{\\it NULL} & " ;
	else DefaultValue.out(Type," &");
	if (is_null(Type,Min)) {
		cout << " & " ;
		return ;
	}
	Min.out(Type," &");
	Max.out(Type);
}

static const BaseClassTexDescribe * find_describe(const char * user_name)
{
	for (BaseClassTexDescribe * pt = base_class_tex_describe;
			pt->class_name;pt++) if (!strcmp(pt->class_name,user_name))
				return pt ;
	return 0 ;
}


static int param_struct_compare(const void * a, const void * b)
{
    const ParamStruct * A = (const ParamStruct *) a ;
    const ParamStruct * B = (const ParamStruct *) b ;
    if (!A) if (!B) return 0 ; else return -1 ;
    if (!B) return 1 ;

    const char * Aa = A->param->UserName ;
    const char * Bb = B->param->UserName ;
    if (!Aa) if (!Bb) return 0; else return -1 ;
    if (!Bb) return 1 ;
    int compare = TeXstrcmp(Aa,Bb);
	if (compare) return compare ;
	Aa = A->cls->BaseFunctionName ;
    Bb = B->cls->BaseFunctionName ;
    if (!Aa) if (!Bb) return 0; else return -1 ;
    if (!Bb) return 1 ;
    return TeXstrcmp(Aa,Bb);
}

const max_notes = 1000 ;
class ParameterTableOut {
	static const max_line_count;
	int size ;
	int part ;
	int last_note ;
	ParamStruct * all_param ;
	const char * ordered_notes[max_notes];
public:
	ParameterTableOut();
	int need_list_class(ParamStruct * st);
	void parameter_table_end(int part);
	void parameter_table_head(int right_flag);
	void parameter_table_out();
	void parameter_table_out(int start,int right_flag);
	int add_note(const char * note);
	void notes_out();
	static const char * caption_string;
	int count_lines();
};

const int ParameterTableOut::max_line_count = 25 ;
const char * ParameterTableOut::caption_string =
	"\\protect\\IntPp{} base class constructor parameters" ;

ParameterTableOut::ParameterTableOut():
	size(0),
	part(0),
	all_param(0),
	last_note(0)
{
	for (int i = 0;i < max_notes;i++) ordered_notes[i] = 0 ;
}

int ParameterTableOut::add_note(const char * note)
{
	for (int i = 0 ; ordered_notes[i]; i++) if (ordered_notes[i] == note) {
		if (i < last_note) last_note = i ;
		return i + 1;
	}
	if (i < max_notes) {
		ordered_notes[i] = note ;
		return i + 1;
	} 
	cerr << "Too many notes.\n" ;
	exit(1);
	return 0 ;
}

static void superscript(int i)
{
	cout << "$^{" << i << "}$" ;
}

void ParameterTableOut::notes_out()
{
	if (!ordered_notes[last_note]) {
		end_table_out();
		return ;
	}
	cout << "\\vspace{.5in}\n" ;
	cout << "\\footnoterule\n" ;
	cout << "{\n" ;
	cout << "\\footnotesize\n" ;
	for (int i = last_note ; ordered_notes[i]; i++) {
		superscript(i+1);
		cout << ordered_notes[i] << "\\\\\n" ;
	}
	cout << "}\n" ;
	end_table_out();
	// cout << "\\addtocounter{footnote}[" << i - last_note << "]\n" ;
	last_note = i ;
}

int ParameterTableOut::need_list_class(ParamStruct * st)
{
	if (!st->cls) return 0 ;
	for (ParamStruct * pt = st+1; pt->cls; pt++) {
		if (strcmp(st->param->UserName,pt->param->UserName)) return 0 ;
		if (!st->equal(*pt)) {
			cout << "% need_list_class\n" ;
			return 1 ;
		}
	}
	return 0 ;
}

void ParameterTableOut::parameter_table_end(int part)
{
		table_end(caption_string, "Tab:IntPpConstParam",
		"base class constructor parameters", 1, part );
		notes_out();
}

void ParameterTableOut::parameter_table_head(int right_flag)
{
	if (right_flag) table_head("|llrrr|",
		"Parameter & Type & Default & Min & Max ","h",1);
	else table_head("|lll|","Parameter & Description & Class ", "h");
}

int ParameterTableOut::count_lines()
{
	int listing_class = 0 ;
	int count = 0 ;
	for (int i = 0 ; i < size; i++) {
		int check = 0 ;
        if (!i) check = 1 ;
        else check = strcmp(all_param[i-1].param->UserName,
            all_param[i].param->UserName) ;
        if (check) listing_class = need_list_class(&(all_param[i]));
        else if (!listing_class) continue ;
        count++;
	}
	return count ;
}

void ParameterTableOut::parameter_table_out(int start,int right_flag)
{
	int listing_class = 0 ;
	int line_count = 0 ;
	parameter_table_head(right_flag);
	int save_start = start ;
	for (int i = start ; i < size; i++) {
		// cout << "% " << i << "\n" ;
		int check = 0 ;
		if (!i) check = 1 ;
		else check = strcmp(all_param[i-1].param->UserName,
			all_param[i].param->UserName) ;
		if (check) listing_class = need_list_class(&(all_param[i]));
		else if (!listing_class) {
			cout << "\t\t% " << all_param[i].cls->BaseFunctionName << "\n" ;
			continue ;
		}
		if (++line_count > max_line_count) {
			parameter_table_end(part++);
			if (right_flag) return ;
			parameter_table_out(save_start,1);
			save_start = i ;
			parameter_table_head(right_flag);
			line_count = 0;
		}
		all_param[i].out(listing_class,right_flag);
	}
	parameter_table_end(part++);
	if (!right_flag) parameter_table_out(save_start,1);
}

void ParameterTableOut::parameter_table_out()
{
	size = 0 ;
	for (CtorDefaults ** pt = CtorBaseClassDefaultOptions; (*pt); pt++)
		size += (*pt)->NumberParameters ;
	all_param = new ParamStruct [size+1] ;
	ParamStruct * dest = all_param ;
	
	for (pt = CtorBaseClassDefaultOptions; (*pt); pt++)
		for (int i = 0 ; i < (*pt)->NumberParameters; i++) 
			(dest++)->set(*pt,(*pt)->Parameters + i);
	dest->set(0,0);
	
	qsort((char *)all_param,size, sizeof(all_param[0]),
		param_struct_compare);


	// cout << "\\ifodd\\value{page} \\newpage \\fi\n" ;
	cout << "{\\small\n" ;
	part = 1 ;

	cout << "\\newcommand{\\" << TotalCtorParts << "}{" <<
		2*((count_lines() -1) / max_line_count + 1) << "}\n" ;
	parameter_table_out(0,0);
	cout << "\n\\normalsize\n}\n" ;
	delete all_param ;
}

static ParameterTableOut tab;


void ParamStruct::out(int list_class,int right_flag)
{
	param->param_out(right_flag);
	if (!right_flag) {
		const BaseClassTexDescribe * desc = find_describe(param->UserName);
		if (!desc) {
			cerr << "No description for `" << param->UserName << "'.\n" ;
			exit(1);
		}
		cout << " & " << desc->description  ;
		if (desc->notes) {
			int index = tab.add_note(*(desc->notes)) ;
			superscript(index);
		}
		cout << " & " ;
		if (list_class) cout <<  cls->BaseFunctionName ;
	}
	cout << "\\\\ % " << cls->BaseFunctionName << "\n" ;
}

void create_prgramming_documentation()
{
	int num_classes = 0 ;
	for (CtorDefaults ** pt = CtorBaseClassDefaultOptions; *pt; pt++)
		num_classes++ ;
	qsort((char *)CtorBaseClassDefaultOptions,num_classes,
		sizeof(CtorBaseClassDefaultOptions[0]),ctor_base_compare);

	// Output base class table
	table_head("|llll|","Base class & Used for & Parent & header file");

	for (pt = CtorBaseClassDefaultOptions; (*pt); pt++) (*pt)->table_out();

	table_end("\\protect\\IntPp{} base classes","Tab:IntPpBaseClasses",
		"base classes");

	// Output parameters of each base class
	table_head("|ll|","Base class & Constructor parameters");

	for (pt = CtorBaseClassDefaultOptions; (*pt); pt++) 
		(*pt)->param_table_out();

	table_end("\\protect\\IntPp{} base class parameters ",
		"Tab:IntPpBaseClassParam", "base class parameters");

	// Output parameter table
	tab.parameter_table_out();

}

