#include <complex.h>
#include <math.h>
#include "ObjProDSP/portable.h"
#include "ObjProGen/newaloc.h"
#include "ObjProComGui/cgidbg.h"
#include "ObjProGen/dspconst.h"
#include "ObjProArith/hrdarth.h"
#include "ObjProArithGen/arthfnc.h"
#include "ObjProArith/hrdcmp.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/demod.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 * DemodNodeList = 0 ;
static InteractiveEntity * IntEntDemod ;
void DemodNodesInit();
Demod::Demod (const char * Name, int16 DataType, double DemodFreq):
	ProcessNode(Name, 1, 1, DataType & 2 ? 1 : 2, 0, 1, 1, 0, 0, 
	DataType & 1 ? 1 : 2, 0, TimingTypeLinear, 
	(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined, (ArithType::ArithCapabilities)ArithType::ArithTypeUndefined)
,
	DataType_1(DataType),
	DemodFreq_2(DemodFreq)
{
	if (!DemodNodeList) DemodNodesInit() ;
	DemodNodeList->Append(MakeDeclaredEntity(this, IntEntDemod)) ;
	InitArithType(TheArithType);
	NewMenuItem("Demod",GetName());
#line 76 "../demod.usr"
 
	DemodIndex = 0 ;
	DemodFlag = GetDemodFreq() != 0.0 ;
#ifndef __NT_VC__
        DemodDeltaPhase = complex(cos(-DemodFreq),sin(-DemodFreq));
#else
        DemodDeltaPhase.x = cos(-DemodFreq);
        DemodDeltaPhase.y = sin(-DemodFreq);
#endif
#line 48 "../demod.cxx"
} // end constructor

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

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

Demod * DemodDef;

ErrCode Demod::DoNode(int32 k)
{
#line 99 "../demod.usr"
 
	for (int32 i = 0 ; i < k ; i++ ) {
		CxMachWord Data ;
		if (GetDataType() & 2) Data = CxMachWord(ReadWord());
		else Data = ReadCxWord();
		if (DemodFlag) {
#ifndef __NT_VC__
			if (DemodIndex % 100 == 0) {
				DemodPhase = complex(
					cos (-DemodIndex * GetDemodFreq()),
					sin (-DemodIndex * GetDemodFreq()));
			} else DemodPhase *= DemodDeltaPhase ;
#else
			if (++DemodIndex % 100 == 0) {
				DemodPhase.x = cos (-DemodIndex * GetDemodFreq());
				DemodPhase.y = sin (-DemodIndex * GetDemodFreq());
			} else DemodPhase = NT_complex_multiply(DemodPhase,DemodDeltaPhase);
#endif
			DemodIndex++;
			CxMachWord Fact = FullScale(DemodPhase) ;
			// LogOut << "Fact = " << Fact << "\n" ;
			CxAccMachWord Temp = ((CxAccMachWord) Data) *
				(CxAccMachWord) Fact ;
			// LogOut << "Temp = " << Temp << "\n" ;
			Data = (CxMachWord) AccScale(Temp,1);
				// prevent overflow
			  	// from complex multiply
			// LogOut << "Data = " << Data << "\n" ;
		}
		if (GetDataType() & 1) WriteWord(MachReal(Data));
		else WriteCxWord(Data);
	}
	return OK ;
#line 102 "../demod.cxx"
} // end kernel code

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

void Demod::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeDemod(Out,EntityReqDescribeFull,*IntEntDemod, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("DataType");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetDataType()));
		Out.NextFillOut(")");
		Out.NextFillOut("selects complex input and complex output (0),");
		Out.NextFillOut("complex input and real output (1),");
		Out.NextFillOut("real input and complex output (2) or");
		Out.NextFillOut("real input and real output (3).");
		Out.NextQuoteOut("DemodFreq");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetDemodFreq()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the demodulation frequency in radians/sample.");
		Out.NextFillOut("Input sample N is multiplied by");
		Out.NextFillOut("e^(-i * N * 2 * Pi *");
		Out.NextQuoteOut("DemodFreq");
		Out.NextFillOutConcat(")");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntDemod->GetOneParameter("DataType")->
			IntP->CurrentValue = DataType_1;
		IntEntDemod->GetOneParameter("DemodFreq")->
			FloatP->CurrentValue = DemodFreq_2;
		break;
	}
} // end  list entity switch

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

void DemodNodesInit()
{
	if (DemodNodeList)  return ;

	static StringParam DemodNameParam =
		{"Demod", MakeNewEntityName, 0, LegalEntityName};
	static IntParam DemodDataTypeParam = {
		 0, 0,  0,  0,  0,  3};
	static FloatParam DemodDemodFreqParam = {
		 0.0, 0, 0, -1e+100, 0, 1e+100};

	static OneParameter DemodParArray[] = {
		{"Name", 0, "node name", 0, 0, &DemodNameParam},
		{"DataType", 0, 
			"select real or complex data for input or output",
			&DemodDataTypeParam},
		{"DemodFreq", 0, 
			"demodulation frequency (negative values for modulate)",
			0, &DemodDemodFreqParam},
		{0}
	};

	static OneParameter SetDemodFreqDemodList[] = {
		{"DemodFreq", 0, "demodulation frequency (negative values for modulate)",
			 0, &DemodDemodFreqParam},
			{0}
	};
	UserParameters * SetDemodFreqMemberParam = new UserParameters
		(SetDemodFreqDemodList);

	Procedure * SetMemberProcDemodFreq = new Procedure("SetDemodFreq", SetDemodFreq,
		 SetDemodFreqMemberParam, "void");
static ValueType * DemodMembers[2] ;
	int ii = 0 ;
	DemodMembers[ii++] = new ValueType(DecProcedure, SetMemberProcDemodFreq) ;
	DemodMembers[ii++] = 0 ;
	DemodNodeList = new EntityList;
	IntEntDemod = new InteractiveEntity("Demod", DemodNodeList,
		MakeDemod, InteractiveNode, "demod.h",
		DemodMembers, "ProcessNode");
	IntEntDemod->SetParameters(new UserParameters(DemodParArray));
	TheNodes->Append(IntEntDemod);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("Demod");
		Out.NextFillOut("is a complex modulation or demodulation function.");
		Out.NextFillOut("Its input can be real or complex as can its output.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		int16 DataType =
			IntNode.GetIntParameterValue("DataType");
		double DemodFreq =
			IntNode.GetFloatParameterValue("DemodFreq");
		return new Demod(Name, DataType, DemodFreq);

	}
	}
	return 0;
}

static InitObj LocalInit(DemodNodesInit, "Demod", "ProcessNode");

