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

#include "ObjProUsr/unpack.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 * UnpackWordNodeList = 0 ;
static InteractiveEntity * IntEntUnpackWord ;
void UnpackWordNodesInit();
UnpackWord::UnpackWord (const char * Name, int16 OutputWordSize, int16 OutputsPerInput, 
		int16 SignedOutput):
	ProcessNodeStr(Name, 1, 1, 
	 new StreamStr(1 , 1 , (ArithType::ArithCapabilities)ArithType::ArithCapabilityAnyInt), 
	 new StreamStr(1 , 1 , (ArithType::ArithCapabilities)ArithType::ArithCapabilityAnyInt), 0, 1, OutputsPerInput, 0, 0, TimingTypeLinear)
,
	OutputWordSize_1(OutputWordSize),
	OutputsPerInput_2(OutputsPerInput),
	SignedOutput_3(SignedOutput)
{
	if (!UnpackWordNodeList) UnpackWordNodesInit() ;
	UnpackWordNodeList->Append(MakeDeclaredEntity(this, IntEntUnpackWord)) ;
	InitArithType(TheArithType);
	NewMenuItem("UnpackWord",GetName());
#line 85 "../unpack.usr"
 
	Ratio = GetOutputsPerInput();
    Mask = 1 ;
    for (int i = 1 ; i < GetOutputWordSize(); i++) Mask = (Mask << 1) | 1 ;
    fill_ones = 0 ;
    sign_bit = 1 << (GetOutputWordSize()-1) ;
    for (i = 0 ; i < 33 - GetOutputWordSize(); i++) fill_ones =
        (fill_ones << 1) | sign_bit ;
#line 45 "../unpack.cxx"
} // end constructor

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

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

UnpackWord * UnpackWordDef;

ErrCode UnpackWord::DoNode(int32 k)
{
#line 115 "../unpack.usr"
 
	if (State.IsError()) return FatalError;
	for (int32 i = 0 ; i < k ; i++ )  {
		uint32 CurrentMask = Mask ;
		uint32 Word = ReadInteger();
		unsigned int RightShift = -GetOutputWordSize() ;
		for (int j = 0 ; j < Ratio ;j++) {  
			uint32 to_write = (Word & CurrentMask) >>
                (RightShift+=GetOutputWordSize()) ;
			if (GetSignedOutput()) if (to_write & sign_bit)
				to_write |= fill_ones ;
			WriteInteger(to_write);
			CurrentMask <<= GetOutputWordSize() ;
		}
	}
	return OK ;
#line 82 "../unpack.cxx"
} // end kernel code

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

void UnpackWord::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeUnpackWord(Out,EntityReqDescribeFull,*IntEntUnpackWord, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("OutputWordSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetOutputWordSize()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the number of bits in the output");
		Out.NextFillOut("word.");
		Out.NextQuoteOut("OutputsPerInput");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetOutputsPerInput()));
		Out.NextFillOut(")");
		Out.NextFillOut("is the number of output words");
		Out.NextFillOut("unpacked from each input word.");
		Out.NextFillOut("If");
		Out.NextQuoteOut("SignedOutput");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetSignedOutput()));
		Out.NextFillOut(")");
		Out.NextFillOut("is set the output will be written as a signed");
		Out.NextFillOut("two's compliment value in the full physical word size.");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntUnpackWord->GetOneParameter("OutputWordSize")->
			IntP->CurrentValue = OutputWordSize_1;
		IntEntUnpackWord->GetOneParameter("OutputsPerInput")->
			IntP->CurrentValue = OutputsPerInput_2;
		IntEntUnpackWord->GetOneParameter("SignedOutput")->
			IntP->CurrentValue = SignedOutput_3;
		break;
	}
} // end  list entity switch

void UnpackWordNodesInit()
{
	if (UnpackWordNodeList)  return ;

	static StringParam UnpackWordNameParam =
		{"UnpackWord", MakeNewEntityName, 0, LegalEntityName};
	static IntParam UnpackWordOutputWordSizeParam = {
		 8, 0,  0,  1,  0,  16};
	static IntParam UnpackWordOutputsPerInputParam = {
		 2, 0,  0,  2,  0,  32};
	static IntParam UnpackWordSignedOutputParam = {
		 0, 0,  0,  0,  0,  1};

	static OneParameter UnpackWordParArray[] = {
		{"Name", 0, "node name", 0, 0, &UnpackWordNameParam},
		{"OutputWordSize", 0, 
			"size in bits of output word",
			&UnpackWordOutputWordSizeParam},
		{"OutputsPerInput", 0, 
			"number or words to unpack from each input",
			&UnpackWordOutputsPerInputParam, 0, 0, 0, 0, 1},
		{"SignedOutput", 0, 
			"option(1) to treat output as signed two's compliment value",
			&UnpackWordSignedOutputParam, 0, 0, 0, 0, 1},
		{0}
	};

	UnpackWordNodeList = new EntityList;
	IntEntUnpackWord = new InteractiveEntity("UnpackWord", UnpackWordNodeList,
		MakeUnpackWord, InteractiveNode, "unpack.h",
		0, "ProcessNodeStr");
	IntEntUnpackWord->SetParameters(new UserParameters(UnpackWordParArray));
	TheNodes->Append(IntEntUnpackWord);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("UnpackWord");
		Out.NextFillOut("unpacks each input word to");
		Out.NextQuoteOut("OutputsPerInput");
		Out.NextFillOut("output");
		Out.NextFillOut("words each containing");
		Out.NextQuoteOut("OutputWordSize");
		Out.NextFillOut("bits. If");
		Out.NextQuoteOut("SignedOutput");
		Out.NextFillOut("is");
		Out.NextFillOut("set the output will be written as a signed");
		Out.NextFillOut("two's compliment value in the full physical word size.");
		Out.NextFillOut("The least significant bits of each input word are written first.");
		Out.NextFillOut("The physical word size");
		Out.NextFillOut("must be at least as large as");
		Out.NextQuoteOut("OutputWordSize");
		Out.NextFillOut("*");
		Out.NextQuoteOut("OutputsPerInput");
		Out.NextFillOutConcat(".");
		Out.NextFillOut("If not an error will be generated and the node will");
		Out.NextFillOut("be unusable. The");
		Out.NextFillOut("inverse of this operation is");
		Out.NextFillOut("`PackWord'");
		Out.NextFillOutConcat(".");
		Out.NextFillOut("`RepackStream'");
		Out.NextFillOut("is a");
		Out.NextFillOut("more general but less efficient operation that is its own");
		Out.NextFillOut("inverse.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		int16 OutputWordSize =
			IntNode.GetIntParameterValue("OutputWordSize");
		int16 OutputsPerInput =
			IntNode.GetIntParameterValue("OutputsPerInput");
		int16 SignedOutput =
			IntNode.GetIntParameterValue("SignedOutput");
		return new UnpackWord(Name, OutputWordSize, OutputsPerInput, SignedOutput);

	}
	}
	return 0;
}

static InitObj LocalInit(UnpackWordNodesInit, "UnpackWord", "ProcessNodeStr");

