#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/add.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 * AddNodeList = 0 ;
static InteractiveEntity * IntEntAdd ;
void AddNodesInit();
Add::Add (const char * Name, int16 Channels, int16 ElementSize, double Scale):
	ProcessNodeStr(Name, Channels, 1, 
	ElementSize ?  new StreamStr(StreamNotSet) :  new StreamStr(ElementSize , SizeVariable), 
	ElementSize ?  new StreamStr(StreamNotSet) :  new StreamStr(ElementSize , SizeVariable), 0, 1, 1, 0, 0, TimingTypeLinear)
,
	Channels_1(Channels),
	ElementSize_2(ElementSize),
	Scale_3(Scale)
{
	if (!AddNodeList) AddNodesInit() ;
	AddNodeList->Append(MakeDeclaredEntity(this, IntEntAdd)) ;
	InitArithType(TheArithType);
	NewMenuItem("Add",GetName());
#line 90 "../add.usr"
 
	NumberOfOverflows = 0;
	element_size = block_size= 0;
#line 42 "../add.cxx"
} // end constructor

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

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

Add * AddDef;

ErrCode Add::DoNode(int32 k)
{
#line 110 "../add.usr"
 
	if (!element_size) {
		element_size = GetInEltSize();
		block_size = GetBlockSize();
	}
	int32 SaveOverflows = NumberOfOverflows ;
	for (int32 i = 0 ; i < k ; i++ ) {
		for (int32 b = 0 ; b < block_size; b++)
		  for (int32 l = 0 ; l < element_size; l++) {
			OverflowCheck Sum =  0;
			for (int32 j = 0; j < GetChannels(); j++) {
				Sum += ReadWord(j);
				NumberOfOverflows += ArithCheckOverflow(Sum);
			}
			WriteWord((MachWordCast) Sum);
		}
	}
	
	if (NumberOfOverflows > SaveOverflows) ReportOverflows(
		NumberOfOverflows, SaveOverflows,GetName());
	return OK ;
#line 84 "../add.cxx"
} // end kernel code

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

void Add::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeAdd(Out,EntityReqDescribeFull,*IntEntAdd, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("Channels");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetChannels()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the number of input channels");
		Out.NextFillOut("to be added together in a single output channel.");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetElementSize()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the sample size for");
		Out.NextFillOut("each channel. The most common use of");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("is to");
		Out.NextFillOut("set it to two for a complex data stream. All input data");
		Out.NextFillOut("streams must have the same sample size. If set to 0");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("is set automatically based on its value for the first input node.");
		Out.NextQuoteOut("Scale");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetScale()));
		Out.NextFillOut(")");
		Out.NextFillOut("is a scale factor applied to each channel before");
		Out.NextFillOut("it is added to the output channel. The channel addition");
		Out.NextFillOut("will clip any data that would otherwise create an overflow");
		Out.NextFillOut("and generate a help message. Only one help messages is");
		Out.NextFillOut("generated, for every 400 input samples regardless of the");
		Out.NextFillOut("number of overflows that may occur.");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntAdd->GetOneParameter("Channels")->
			IntP->CurrentValue = Channels_1;
		IntEntAdd->GetOneParameter("ElementSize")->
			IntP->CurrentValue = ElementSize_2;
		IntEntAdd->GetOneParameter("Scale")->
			FloatP->CurrentValue = Scale_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");
		((Add *) This)->SetScale(Scale);
		return 0 ;
	}
	}
	return 0;
}

void AddNodesInit()
{
	if (AddNodeList)  return ;

	static StringParam AddNameParam =
		{"Add", MakeNewEntityName, 0, LegalEntityName};
	static IntParam AddChannelsParam = {
		 2, 0,  0,  2, 0, 32767};
	static IntParam AddElementSizeParam = {
		 0, 0,  0,  0, 0, 32767};
	static FloatParam AddScaleParam = {
		 1.0, 0, 0, -1e+100, 0, 1e+100};

	static OneParameter AddParArray[] = {
		{"Name", 0, "node name", 0, 0, &AddNameParam},
		{"Channels", 0, 
			"number of input channels",
			&AddChannelsParam},
		{"ElementSize", 0, 
			"number of multiplexed elements in each channel",
			&AddElementSizeParam, 0, 0, 0, 0, 1},
		{"Scale", 0, 
			"scale factor for each channel",
			0, &AddScaleParam, 0, 0, 0, 1},
		{0}
	};

	static OneParameter SetScaleAddList[] = {
		{"Scale", 0, "scale factor for each channel",
			 0, &AddScaleParam, 0, 0, 0, 1},
			{0}
	};
	UserParameters * SetScaleMemberParam = new UserParameters
		(SetScaleAddList);

	Procedure * SetMemberProcScale = new Procedure("SetScale", SetScale,
		 SetScaleMemberParam, "void");
static ValueType * AddMembers[2] ;
	int ii = 0 ;
	AddMembers[ii++] = new ValueType(DecProcedure, SetMemberProcScale) ;
	AddMembers[ii++] = 0 ;
	AddNodeList = new EntityList;
	IntEntAdd = new InteractiveEntity("Add", AddNodeList,
		MakeAdd, InteractiveNode, "add.h",
		AddMembers, "ProcessNodeStr");
	IntEntAdd->SetParameters(new UserParameters(AddParArray));
	TheNodes->Append(IntEntAdd);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("Add");
		Out.NextFillOut("sums");
		Out.NextQuoteOut("Channels");
		Out.NextFillOut("input channels into a single output channel.");
		Out.NextFillOut("Each sample is multiplied by");
		Out.NextQuoteOut("Scale");
		Out.NextFillOut("before being added to the");
		Out.NextFillOut("output channel. Overflows are prevented 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. Each sample");
		Out.NextFillOut("consists of");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("words.");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("is usually one");
		Out.NextFillOut("for real data streams and two for complex streams, but it can");
		Out.NextFillOut("be any 16 bit positive integer and used for any purpose.");
		Out.NewLine();
		break;

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

	}
	}
	return 0;
}

static InitObj LocalInit(AddNodesInit, "Add", "ProcessNodeStr");

