#include "ObjProDSP/portable.h"
#include "ObjProArith/hrdarth.h"
#include "ObjProArithGen/artherr.h"
#include "ObjProArithGen/arthfnc.h"
#include "ObjProComGui/cgidbg.h"
#include "ObjProGui/sigintfc.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/normal.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 * NormalNodeList = 0 ;
static InteractiveEntity * IntEntNormal ;
void NormalNodesInit();
Normal::Normal (const char * Name, double Sigma, double Mean, int16 ElementSize, 
		int32 Seed):
	Signal(Name, 1, ElementSize, 1, 1, TimingTypeLinear, 
	(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined)
,
	Sigma_1(Sigma),
	Mean_2(Mean),
	ElementSize_3(ElementSize),
	Seed_4(Seed)
{
	if (!NormalNodeList) NormalNodesInit() ;
	NormalNodeList->Append(MakeDeclaredEntity(this, IntEntNormal)) ;
	InitArithType(TheArithType);
	NewMenuItem("Normal",GetName());
#line 92 "../normal.usr"
 
	rand_gen = new GaussRand(GetSeed()) ;
	// rand_gen->dump_state(GetName());
#line 41 "../normal.cxx"
} // end constructor

Normal::~Normal()
{
	TheMenuServer->DeleteMenuItem("Normal",GetName());
	NormalNodeList->Delete(GetName()) ;
#line 97 "../normal.usr"
 
	delete rand_gen ;
#line 51 "../normal.cxx"
} // end destructor

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

double Normal::TimeFirst( DfNodeInLink * , DfNodeOutLink * )
{
#line 119 "../normal.usr"
	return 0.0 ;
#line 65 "../normal.cxx"
} // end timing code

Normal * NormalDef;

ErrCode Normal::DoNode(int32 k)
{
#line 126 "../normal.usr"
 
	rand_gen->set_state();
	// rand_gen->dump_state(GetName());
	for (int32 i = 0 ; i < k ; i++ ) {
		for (int j = 0 ; j < GetElementSize(); j++) {
			WriteWord((MachWordCast)
				RoundDouble(rand_gen->gauss_rand() * GetSigma()
				+ GetMean())) ;
		}
	}
	// rand_gen->dump_state(GetName());
	rand_gen->restore_state();
	return OK ;
#line 86 "../normal.cxx"
} // end kernel code

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

void Normal::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeNormal(Out,EntityReqDescribeFull,*IntEntNormal, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("Sigma");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetSigma()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the standard deviation of the normally");
		Out.NextFillOut("distributed samples created by this generator.");
		Out.NextQuoteOut("Sigma");
		Out.NextFillOut("is a");
		Out.NextFillOut("scale factor for values generated in the standard normal");
		Out.NextFillOut("distribution.");
		Out.NextQuoteOut("Mean");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetMean()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the mean of the normally distributed samples");
		Out.NextFillOut("created by this generator.");
		Out.NextQuoteOut("Mean");
		Out.NextFillOut("is an offset for the");
		Out.NextFillOut("values generated in the standard normal distribution.");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetElementSize()));
		Out.NextFillOut(")");
		Out.NextFillOut("specifies the number of words in a single sample.");
		Out.NextFillOut("It is most commonly 1 for real data or 2 for complex data.");
		Out.NextQuoteOut("Seed");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetSeed()));
		Out.NextFillOut(")");
		Out.NextFillOut("seeds the random number generator. Each object instance");
		Out.NextFillOut("maintains a separate history state for the random number");
		Out.NextFillOut("generator. If the same");
		Out.NextFillOut("value of");
		Out.NextQuoteOut("Seed");
		Out.NextFillOut("is used in different object instances");
		Out.NextFillOut("they will generate the same sequence.");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntNormal->GetOneParameter("Sigma")->
			FloatP->CurrentValue = Sigma_1;
		IntEntNormal->GetOneParameter("Mean")->
			FloatP->CurrentValue = Mean_2;
		IntEntNormal->GetOneParameter("ElementSize")->
			IntP->CurrentValue = ElementSize_3;
		IntEntNormal->GetOneParameter("Seed")->
			IntP->CurrentValue = Seed_4;
		break;
	}
} // end  list entity switch

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

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

void NormalNodesInit()
{
	if (NormalNodeList)  return ;

	static StringParam NormalNameParam =
		{"Normal", MakeNewEntityName, 0, LegalEntityName};
	static FloatParam NormalSigmaParam = {
		 1024.0, 0,  0,  0.0, 0, 1e+100};
	static FloatParam NormalMeanParam = {
		 0.0, 0, 0, -1e+100, 0, 1e+100};
	static IntParam NormalElementSizeParam = {
		 1, 0,  0,  1, 0, 32767};
	static IntParam NormalSeedParam = {
		 1, 0,  0,  0, 0, 2.14748e+09};

	static OneParameter NormalParArray[] = {
		{"Name", 0, "node name", 0, 0, &NormalNameParam},
		{"Sigma", 0, 
			"standard deviation of normally distributed data",
			0, &NormalSigmaParam},
		{"Mean", 0, 
			"mean of normally distributed data",
			0, &NormalMeanParam, 0, 0, 0, 1},
		{"ElementSize", 0, 
			"number of words in one sample",
			&NormalElementSizeParam, 0, 0, 0, 0, 1},
		{"Seed", 0, 
			"random number generator seed",
			&NormalSeedParam, 0, 0, 0, 0, 1},
		{0}
	};

	static OneParameter SetSigmaNormalList[] = {
		{"Sigma", 0, "standard deviation of normally distributed data",
			 0, &NormalSigmaParam},
			{0}
	};
	UserParameters * SetSigmaMemberParam = new UserParameters
		(SetSigmaNormalList);

	Procedure * SetMemberProcSigma = new Procedure("SetSigma", SetSigma,
		 SetSigmaMemberParam, "void");
	static OneParameter SetMeanNormalList[] = {
		{"Mean", 0, "mean of normally distributed data",
			 0, &NormalMeanParam, 0, 0, 0, 1},
			{0}
	};
	UserParameters * SetMeanMemberParam = new UserParameters
		(SetMeanNormalList);

	Procedure * SetMemberProcMean = new Procedure("SetMean", SetMean,
		 SetMeanMemberParam, "void");
static ValueType * NormalMembers[3] ;
	int ii = 0 ;
	NormalMembers[ii++] = new ValueType(DecProcedure, SetMemberProcSigma) ;
	NormalMembers[ii++] = new ValueType(DecProcedure, SetMemberProcMean) ;
	NormalMembers[ii++] = 0 ;
	NormalNodeList = new EntityList;
	IntEntNormal = new InteractiveEntity("Normal", NormalNodeList,
		MakeNormal, InteractiveSignal, "normal.h",
		NormalMembers, "Signal");
	IntEntNormal->SetParameters(new UserParameters(NormalParArray));
	TheNodes->Append(IntEntNormal);
	new Normal("CxNormal", 128.0, 0.0, 2, 1);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("Normal");
		Out.NextFillOut("generates noise samples from a normal distribution.");
		Out.NextFillOut("Let Z be samples from the standard normal distribution. This");
		Out.NextFillOut("process generates samples as");
		Out.NextQuoteOut("Mean");
		Out.NextFillOut("+");
		Out.NextQuoteOut("Sigma");
		Out.NextFillOut("* Z.");
		Out.NextFillOut("A vector of");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("samples is generated.");
		Out.NextQuoteOut("ElementSize");
		Out.NextFillOut("is ordinarily set to 1 for real data and 2 for complex data.");
		Out.NextQuoteOut("Seed");
		Out.NextFillOut("determines the sequence generated.");
		Out.NextFillOut("Each object instance maintains it a separate state for the");
		Out.NextFillOut("random number generator.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		double Sigma =
			IntNode.GetFloatParameterValue("Sigma");
		double Mean =
			IntNode.GetFloatParameterValue("Mean");
		int16 ElementSize =
			IntNode.GetIntParameterValue("ElementSize");
		int32 Seed =
			IntNode.GetIntParameterValue("Seed");
		return new Normal(Name, Sigma, Mean, ElementSize, Seed);

	}
	}
	return 0;
}

static InitObj LocalInit(NormalNodesInit, "Normal", "Signal");

