#include <complex.h>
#include <signal.h>
#include "ObjProDSP/portable.h"
#include "ObjProComGui/cgidbg.h"
#include "ObjProGui/yacintfc.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/packword.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 * PackWordNodeList = 0 ;
static InteractiveEntity * IntEntPackWord ;
void PackWordNodesInit();
PackWord::PackWord (const char * Name, int16 InputWordSize, int16 InputsPerOutput):
	ProcessNodeStr(Name, 1, 1, 
	 new StreamStr(1 , 1 , (ArithType::ArithCapabilities)ArithType::ArithCapabilityAnyInt), 
	 new StreamStr(1 , 1 , (ArithType::ArithCapabilities)ArithType::ArithCapabilityAnyInt), 0, InputsPerOutput, 1, 0, 0, TimingTypeLinear)
,
	InputWordSize_1(InputWordSize),
	InputsPerOutput_2(InputsPerOutput)
{
	if (!PackWordNodeList) PackWordNodesInit() ;
	PackWordNodeList->Append(MakeDeclaredEntity(this, IntEntPackWord)) ;
	InitArithType(TheArithType);
	NewMenuItem("PackWord",GetName());
#line 51 "../packword.usr"
 
	err_state = OK ;
	Ratio = GetInputsPerOutput();
	Mask = 1 ;
	for (int i = 1 ; i < GetInputWordSize(); i++) Mask = (Mask << 1) | 1 ;
#line 40 "../packword.cxx"
} // end constructor

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

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

PackWord * PackWordDef;

ErrCode PackWord::DoNode(int32 k)
{
#line 75 "../packword.usr"
 
	if (State.IsError()) return FatalError;
	if (err_state >=FatalError) {
		State.Error("`", GetName(), "' has invalid parameters and is unusable");
		return FatalError ;
	}
	for (int32 i = 0 ; i < k ; i++ )  {
		unsigned int left_shift = 0 ;
		uint32 output = 0 ;
		for (int j = 0 ; j < Ratio ;j++,left_shift+=GetInputWordSize())  
			output |= (ReadInteger()&Mask) << left_shift ;
		WriteInteger((BinMachWord) output) ;
	}
	return OK ;
#line 75 "../packword.cxx"
} // end kernel code

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

void PackWord::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakePackWord(Out,EntityReqDescribeFull,*IntEntPackWord, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("InputWordSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetInputWordSize()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the number of bits in each input");
		Out.NextFillOut("word to pack into the output word.");
		Out.NextQuoteOut("InputsPerOutput");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetInputsPerOutput()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the number of input words combined");
		Out.NextFillOut("to form a single output word.");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntPackWord->GetOneParameter("InputWordSize")->
			IntP->CurrentValue = InputWordSize_1;
		IntEntPackWord->GetOneParameter("InputsPerOutput")->
			IntP->CurrentValue = InputsPerOutput_2;
		break;
	}
} // end  list entity switch

void PackWordNodesInit()
{
	if (PackWordNodeList)  return ;

	static StringParam PackWordNameParam =
		{"PackWord", MakeNewEntityName, 0, LegalEntityName};
	static IntParam PackWordInputWordSizeParam = {
		 8, 0,  0,  1,  0,  16};
	static IntParam PackWordInputsPerOutputParam = {
		 2, 0,  0,  2,  0,  32};

	static OneParameter PackWordParArray[] = {
		{"Name", 0, "node name", 0, 0, &PackWordNameParam},
		{"InputWordSize", 0, 
			"size in bits to pack from each input",
			&PackWordInputWordSizeParam},
		{"InputsPerOutput", 0, 
			"number or input words to pack into one output",
			&PackWordInputsPerOutputParam},
		{0}
	};

	PackWordNodeList = new EntityList;
	IntEntPackWord = new InteractiveEntity("PackWord", PackWordNodeList,
		MakePackWord, InteractiveNode, "packword.h",
		0, "ProcessNodeStr");
	IntEntPackWord->SetParameters(new UserParameters(PackWordParArray));
	TheNodes->Append(IntEntPackWord);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("PackWord");
		Out.NextFillOut("packs the least significant");
		Out.NextQuoteOut("InputWordSize");
		Out.NextFillOut("bits");
		Out.NextFillOut("of");
		Out.NextQuoteOut("InputsPerOutput");
		Out.NextFillOut("consecutive input words to a single");
		Out.NextFillOut("output word. The first input word is placed in the least");
		Out.NextFillOut("significant output bits.");
		Out.NextFillOut("The physical word size");
		Out.NextFillOut("must be at least as large as");
		Out.NextQuoteOut("InputWordSize");
		Out.NextFillOut("*");
		Out.NextQuoteOut("InputsPerOutput");
		Out.NextFillOutConcat(".");
		Out.NextFillOut("If it is not an error is generated and the node will not");
		Out.NextFillOut("be usable.");
		Out.NextFillOut("The inverse of this operation is");
		Out.NextFillOut("`UnpackWord'");
		Out.NextFillOutConcat(".");
		Out.NextFillOut("`RepackStream'");
		Out.NextFillOut("is a");
		Out.NextFillOut("a more general but less efficient operation that is its own inverse.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		int16 InputWordSize =
			IntNode.GetIntParameterValue("InputWordSize");
		int16 InputsPerOutput =
			IntNode.GetIntParameterValue("InputsPerOutput");
		return new PackWord(Name, InputWordSize, InputsPerOutput);

	}
	}
	return 0;
}

static InitObj LocalInit(PackWordNodesInit, "PackWord", "ProcessNodeStr");

