#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 "ObjProDSPint/netlnk.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/power.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 * PowerNodeList = 0 ;
static InteractiveEntity * IntEntPower ;
void PowerNodesInit();
Power::Power (const char * Name, int16 Amplitude, double Scale):
	ProcessNodeStr(Name, 1, 1,  new StreamStr(StreamNotSet), 
	 new StreamStr(1 , SizeVariable), 0, 1, 1, 0, 0, TimingTypeLinear)
,
	Amplitude_1(Amplitude),
	Scale_2(Scale)
{
	if (!PowerNodeList) PowerNodesInit() ;
	PowerNodeList->Append(MakeDeclaredEntity(this, IntEntPower)) ;
	InitArithType(TheArithType);
	NewMenuItem("Power",GetName());
#line 79 "../power.usr"
 
	NumberOfOverflows = 0;
	ScaleFlag = GetScale() != 1.0 ;
	ScaleUpFlag = GetScale() > 1.0 ;
#line 42 "../power.cxx"
} // end constructor

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

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

Power * PowerDef;

ErrCode Power::DoNode(int32 k)
{
#line 105 "../power.usr"
 
	int32 ElementSize = GetInLink(0)->GetElementSize();
	int32 SaveOverflows = NumberOfOverflows ;
	int32 i;
	int32 b ;
	if (GetAmplitude()) for (i = 0 ; i < k ; i++ )
		for (b=0; b< GetBlockSize(); b++) {
		AccOverflowCheck Sum = 0 ;
		for (int32 l = 0 ; l < ElementSize; l++) {
			AccOverflowCheck Out ;
			AccMachWord Temp = ReadWord() ;
			Out = (AccOverflowCheck) (Temp * Temp) ;
			if (ScaleFlag) {
				Out *= GetScale() ;
				NumberOfOverflows += ArithAccCheckOverflow(Out);
			}
			Sum += Out ;
			NumberOfOverflows += ArithAccCheckOverflow(Out);
		}
		OverflowCheck Root = (OverflowCheck) sqrt(Sum);
		NumberOfOverflows += ArithCheckOverflow(Root);
		// WriteWord((MachWordCast) Root);
		WriteWord(Root);
	} else for (i = 0 ; i < k ; i++ ) 
		for (b=0; b< GetBlockSize(); b++) {
		OverflowCheck Sum = 0 ;
		for (int32 l = 0 ; l < ElementSize; l++) {
			OverflowCheck Out ;
			AccMachWord Temp = ReadWord() ;
			Out = (OverflowCheck) (Temp * Temp) ;
			if (ScaleFlag) {
				if (ScaleUpFlag) {
					AccOverflowCheck check =
						Out * GetScale() ;
					NumberOfOverflows+=ArithAccCheckOverflow
						(check);
					Out = (AccMachWord) check ;
				} else Out = (OverflowCheck) (Out * GetScale());
			}
			NumberOfOverflows += ArithCheckOverflow(Out);
			Sum += Out ;
			NumberOfOverflows += ArithCheckOverflow(Sum);
		}
		WriteWord(Sum);
	}
	if (NumberOfOverflows > SaveOverflows) ReportOverflows(
		NumberOfOverflows, SaveOverflows,GetName());
	return OK ;
#line 111 "../power.cxx"
} // end kernel code

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

void Power::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakePower(Out,EntityReqDescribeFull,*IntEntPower, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextFillOut("If");
		Out.NextQuoteOut("Amplitude");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetAmplitude()));
		Out.NextFillOut(")");
		Out.NextFillOut("is set to 1, the output will be the square");
		Out.NextFillOut("root of the power and not the power.");
		Out.NextQuoteOut("Scale");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetScale()));
		Out.NextFillOut(")");
		Out.NextFillOut("is a linear scale factor applied before");
		Out.NextFillOut("summing the squared elements in a sample.");
		Out.NextFillOut("For integer arithmetic,");
		Out.NextQuoteOut("Scale");
		Out.NextFillOut("should be");
		Out.NextFillOut("set to prevent overflows. Note the squaring operation");
		Out.NextFillOut("(in the integer arithmetic model) is");
		Out.NextFillOut("done in double precision integer arithmetic.");
		Out.NextFillOut("Thus if one is taking");
		Out.NextFillOut("the amplitude as the final output (");
		Out.NextQuoteOut("Amplitude");
		Out.NextFillOut("=1), overflows");
		Out.NextFillOut("can only occur from the summation step. If integer overflows");
		Out.NextFillOut("do occur the output signal is clipped. 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.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntPower->GetOneParameter("Amplitude")->
			IntP->CurrentValue = Amplitude_1;
		IntEntPower->GetOneParameter("Scale")->
			FloatP->CurrentValue = Scale_2;
		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");
		((Power *) This)->SetScale(Scale);
		return 0 ;
	}
	}
	return 0;
}

void PowerNodesInit()
{
	if (PowerNodeList)  return ;

	static StringParam PowerNameParam =
		{"Power", MakeNewEntityName, 0, LegalEntityName};
	static IntParam PowerAmplitudeParam = {
		 0, 0,  0,  0,  0,  1};
	static FloatParam PowerScaleParam = {
		 1.0, 0, 0, -1e+100, 0, 1e+100};

	static OneParameter PowerParArray[] = {
		{"Name", 0, "node name", 0, 0, &PowerNameParam},
		{"Amplitude", 0, 
			"flag select amplitude(1) or power(0)",
			&PowerAmplitudeParam},
		{"Scale", 0, 
			"scale factor applied before summing powers",
			0, &PowerScaleParam, 0, 0, 0, 1},
		{0}
	};

	static OneParameter SetScalePowerList[] = {
		{"Scale", 0, "scale factor applied before summing powers",
			 0, &PowerScaleParam, 0, 0, 0, 1},
			{0}
	};
	UserParameters * SetScaleMemberParam = new UserParameters
		(SetScalePowerList);

	Procedure * SetMemberProcScale = new Procedure("SetScale", SetScale,
		 SetScaleMemberParam, "void");
static ValueType * PowerMembers[2] ;
	int ii = 0 ;
	PowerMembers[ii++] = new ValueType(DecProcedure, SetMemberProcScale) ;
	PowerMembers[ii++] = 0 ;
	PowerNodeList = new EntityList;
	IntEntPower = new InteractiveEntity("Power", PowerNodeList,
		MakePower, InteractiveNode, "power.h",
		PowerMembers, "ProcessNodeStr");
	IntEntPower->SetParameters(new UserParameters(PowerParArray));
	TheNodes->Append(IntEntPower);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("Power");
		Out.NextFillOut("computes the sum of the squares of each input sample");
		Out.NextFillOut("element. Before summing the power in each channel");
		Out.NextFillOut("is multiplied by a linear scale factor");
		Out.NextQuoteOut("Scale");
		Out.NextFillOutConcat(". The most common use is to");
		Out.NextFillOut("compute the power of a complex signal.");
		Out.NextFillOut("The linear scaling and the summation can cause an arithmetic overflow.");
		Out.NextFillOut("Overflows cannot occur in the squaring operation");
		Out.NextFillOut("(with integer arithmetic)");
		Out.NextFillOut("because double precision integer arithmetic is used.");
		Out.NextFillOut("Floating point overflows generate an interrupt and end");
		Out.NextFillOut("node execution. Integer 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.");
		Out.NewLine();
		break;

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

	}
	}
	return 0;
}

static InitObj LocalInit(PowerNodesInit, "Power", "ProcessNodeStr");

