#include <complex.h>
#include <signal.h>
#include "ObjProDSP/portable.h"
#include "ObjProComGui/usercom.h"
#include "ObjProArith/hrdarth.h"
#include "ObjProArithGen/arthfnc.h"
#include "ObjProComGui/cgidbg.h"
#include "ObjProArithGen/artherr.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/gainpad.h"
#include "ObjProGen/outtok.h"
#include "ObjProGui/intfc.h"
#include "ObjProGui/remmen.h"
#include "ObjProGui/user.h"
#include "ObjProGui/dynmnu.h"
#include "ObjProArith/typout.h"
#include "ObjProGui/array.h"
#include "ObjProGui/interinit.h"
#include "ObjProGen/stattyp.h"
static EntityList * GainPadNodeList = 0 ;
static InteractiveEntity * IntEntGainPad ;
void GainPadNodesInit();
GainPad::GainPad (const char * Name, double Scale, int16 ElementSize, 
		int32 NullOutputSample):
	ProcessNode(Name, 1, 1, ElementSize ? ElementSize : 1, 0, 1, 1, 0, 0, 
	ElementSize ? ElementSize : 2, 0, TimingTypeLinear, 
	(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined, (ArithType::ArithCapabilities)ArithType::ArithTypeUndefined)
,
	Scale_1(Scale),
	ElementSize_2(ElementSize),
	NullOutputSample_3(NullOutputSample)
{
	if (!GainPadNodeList) GainPadNodesInit() ;
	GainPadNodeList->Append(MakeDeclaredEntity(this, IntEntGainPad)) ;
	InitArithType(TheArithType);
	NewMenuItem("GainPad",GetName());
#line 83 "../gainpad.usr"
 
	NumberOfOverflows = 0;
	RealToComplex = ElementSize==0;
	InElementSize = ElementSize ? ElementSize : 1;
	SampleCount = 0 ;
#line 45 "../gainpad.cxx"
} // end constructor

GainPad::~GainPad()
{
	TheMenuServer->DeleteMenuItem("GainPad",GetName());
	GainPadNodeList->Delete(GetName()) ;
} // end destructor

int GainPad::CheckSafeDelete()
{
	int Safe_Check_Return = DfNode::CheckSafeDelete();
	if (!Safe_Check_Return) return 0;
	return 1;
} // end check safe delete

GainPad * GainPadDef;

ErrCode GainPad::DoNode(int32 k)
{
#line 103 "../gainpad.usr"
 
	int32 SaveOverflows = NumberOfOverflows ;
	for (int32 i = 0 ; i < k ; i++ ) 
		for (int32 l = 0 ; l < InElementSize; l++) {
			OverflowCheck Out = (OverflowCheck)
				(GetScale() * (double) ReadWord()) ;
			if (GetNullOutputSample()) if (SampleCount++ >=
				GetNullOutputSample()) {
				WriteWord(0) ;
				if (RealToComplex) WriteWord(0);
				continue ;
			}
			NumberOfOverflows += ArithCheckOverflow(Out);
			WriteWord((MachWordCast) Out);
			if (RealToComplex) WriteWord(0) ;
	}
	if (NumberOfOverflows > SaveOverflows) ReportOverflows(
		NumberOfOverflows, SaveOverflows,GetName());
	return OK ;
#line 85 "../gainpad.cxx"
} // end kernel code

static UserEntity * MakeGainPad(OutTokens& Out, EntityReq Request,
	InteractiveEntity& IntNode,
	ArithType::ArithCapabilities arith = (ArithType::ArithCapabilities) TheArithType) ;
int GainPad::CppList(OutTokens& Out, CppListCmds Cmd)
{
	return IntEntGainPad->CppList(Out,Cmd,this);
}

void GainPad::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeGainPad(Out,EntityReqDescribeFull,*IntEntGainPad, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("Scale");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetScale()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the ratio of input amplitude to");
		Out.NextFillOut("output amplitude. Integer overflows are prevented");
		Out.NextFillOut("by clipping. The first");
		Out.NextFillOut("time clipping occurs a help message is generated. A new help");
		Out.NextFillOut("message is generated after every 400 clippings.");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetElementSize()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the sample size.");
		Out.NextFillOut("The most common use of");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("is to");
		Out.NextFillOut("set it to two for a complex data stream or");
		Out.NextFillOut("1 for real data. Set it to 0 to convert real");
		Out.NextFillOut("to complex data by padding the imaginary part with 0.");
		Out.NextFillOut("If");
		Out.NextQuoteOut("NullOutputSample");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetNullOutputSample()));
		Out.NextFillOut(")");
		Out.NextFillOut("is non zero then all samples after");
		Out.NextQuoteOut("NullOutputSample");
		Out.NextFillOut("will be zero. If");
		Out.NextQuoteOut("NullOutputSample");
		Out.NextFillOut("is 0 then the input is written to the output continuously.");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntGainPad->GetOneParameter("Scale")->
			FloatP->CurrentValue = Scale_1;
		IntEntGainPad->GetOneParameter("ElementSize")->
			IntP->CurrentValue = ElementSize_2;
		IntEntGainPad->GetOneParameter("NullOutputSample")->
			IntP->CurrentValue = NullOutputSample_3;
		break;
	}
} // end  list entity switch

static ValueType * SetScale(OutTokens&,EntityReq Request,
		UserParameters * Param,UserEntity *This) 
{
	switch (Request) {
case EntityReqDescribe:
	break ;
case EntityReqDescribeFull:
	break ;
case EntityReqCall:
		{		// Call procedure
				double Scale =
			Param->GetFloatParameterValue("Scale");
		((GainPad *) This)->SetScale(Scale);
		return 0 ;
	}
	}
	return 0;
}

void GainPadNodesInit()
{
	if (GainPadNodeList)  return ;

	static StringParam GainPadNameParam =
		{"GainPad", MakeNewEntityName, 0, LegalEntityName};
	static FloatParam GainPadScaleParam = {
		 1.0, 0, 0, -1e+100, 0, 1e+100};
	static IntParam GainPadElementSizeParam = {
		 1, 0,  0,  0, 0, 32767};
	static IntParam GainPadNullOutputSampleParam = {
		 0, 0,  0,  0, 0, 2.14748e+09};

	static OneParameter GainPadParArray[] = {
		{"Name", 0, "node name", 0, 0, &GainPadNameParam},
		{"Scale", 0, 
			"ratio of input amplitude to output amplitude",
			0, &GainPadScaleParam},
		{"ElementSize", 0, 
			"number of multiplexed elements",
			&GainPadElementSizeParam, 0, 0, 0, 0, 1},
		{"NullOutputSample", 0, 
			"all samples beyond `NullOutputSample' will be 0",
			&GainPadNullOutputSampleParam, 0, 0, 0, 0, 1},
		{0}
	};

	static OneParameter SetScaleGainPadList[] = {
		{"Scale", 0, "ratio of input amplitude to output amplitude",
			 0, &GainPadScaleParam},
			{0}
	};
	UserParameters * SetScaleMemberParam = new UserParameters
		(SetScaleGainPadList);

	Procedure * SetMemberProcScale = new Procedure("SetScale", SetScale,
		 SetScaleMemberParam, "void");
static ValueType * GainPadMembers[2] ;
	int ii = 0 ;
	GainPadMembers[ii++] = new ValueType(DecProcedure, SetMemberProcScale) ;
	GainPadMembers[ii++] = 0 ;
	GainPadNodeList = new EntityList;
	IntEntGainPad = new InteractiveEntity("GainPad", GainPadNodeList,
		MakeGainPad, InteractiveNode, "gainpad.h",
		GainPadMembers, "ProcessNode");
	IntEntGainPad->SetParameters(new UserParameters(GainPadParArray));
	TheNodes->Append(IntEntGainPad);
} // end initalization

static UserEntity * MakeGainPad(OutTokens& Out, EntityReq Request,
	InteractiveEntity& IntNode,
	ArithType::ArithCapabilities arith)
{
	switch(Request) {
case EntityReqDescribe:

case EntityReqDescribeFull:
		Out.NextQuoteOut("GainPad");
		Out.NextFillOut("copies its input to its output after applying a liner");
		Out.NextFillOut("scale factor (");
		Out.NextFillOutConcat("Scale");
		Out.NextFillOutConcat(") to each input sample element. It will");
		Out.NextFillOut("convert real to complex data by adding a 0 imaginary part");
		Out.NextFillOut("to each sample. Set");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("to 1 for this purpose.");
		Out.NextFillOut("Otherwise");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("is the number");
		Out.NextFillOut("of values or elements in each sample.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		double Scale =
			IntNode.GetFloatParameterValue("Scale");
		int16 ElementSize =
			IntNode.GetIntParameterValue("ElementSize");
		int32 NullOutputSample =
			IntNode.GetIntParameterValue("NullOutputSample");
		return new GainPad(Name, Scale, ElementSize, NullOutputSample);

	}
	}
	return 0;
}

static InitObj LocalInit(GainPadNodesInit, "GainPad", "ProcessNode");

