#include "ObjProDSPint/netlnk.h"
#include "ObjProNet/dfnode.h"

#include "ObjProUsr/demux.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 * DemuxNodeList = 0 ;
static InteractiveEntity * IntEntDemux ;
void DemuxNodesInit();
Demux::Demux (const char * Name, int16 Channels, int32 InputSampleSize, 
		int32 InputElementSize, int32 OutputElementSize):
	ProcessNode(Name, 1, Channels, InputElementSize, 0, 
	Channels * InputSampleSize * OutputElementSize, InputSampleSize * InputElementSize, 0, 0, OutputElementSize, 0, 
	TimingTypeLinear, (ArithType::ArithCapabilities)ArithType::ArithTypeUndefined, 
	(ArithType::ArithCapabilities)ArithType::ArithTypeUndefined)
,
	Channels_1(Channels),
	InputSampleSize_2(InputSampleSize),
	InputElementSize_3(InputElementSize),
	OutputElementSize_4(OutputElementSize)
{
	if (!DemuxNodeList) DemuxNodesInit() ;
	DemuxNodeList->Append(MakeDeclaredEntity(this, IntEntDemux)) ;
	InitArithType(TheArithType);
	NewMenuItem("Demux",GetName());
} // end constructor

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

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

double Demux::TimeFirst( DfNodeInLink * In, DfNodeOutLink * Out)
{
#line 89 "../demux.usr"
 
	double ThisChannel = Out->GetNodeOutputChannel();
	
	int32 IncrementIn = 1 ;
	int32 IncrementOut = 1 ;
	if (In) IncrementIn = In->GetIncrementIn();
	if (Out) IncrementOut = Out->GetIncrementOut() ;
	return (ThisChannel * IncrementOut ) / IncrementIn ;
#line 60 "../demux.cxx"
} // end timing code

Demux * DemuxDef;

ErrCode Demux::DoNode(int32 k)
{
#line 107 "../demux.usr"
 
	for (int32 i = 0 ; i < k ; i++ )
	for (int32 li = 0 ; li < GetInputElementSize(); li++) 
	for (int32 lo = 0 ; lo < GetOutputElementSize(); lo++) 
	for (int16 Channel= 0 ; Channel < GetChannels() ; Channel++) 
	for (int32 l = 0 ; l < GetInputSampleSize(); l++) {
		MachWord Data = ReadWord(0);
		WriteWord(Data, Channel) ;
	}
	return OK ;
#line 78 "../demux.cxx"
} // end kernel code

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

void Demux::Describe(OutTokens& Out, ListEntity Option)
{
	switch(Option) {
case ListSingleEntity:
		Out.NewLine();
		MakeDemux(Out,EntityReqDescribeFull,*IntEntDemux, (ArithType::ArithCapabilities) TheArithType);
		Out.NewLine();
		Out.NextQuoteOut("Demux");
		Out.NextFillOut("demultiplexes a single input channel into");
		Out.NextQuoteOut("Channels");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetChannels()));
		Out.NextFillOut(")");
		Out.NextFillOut("output channels.");
		Out.NextFillOut("The input channel has samples");
		Out.NextFillOut("of");
		Out.NextQuoteOut("InputSampleSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetInputSampleSize()));
		Out.NextFillOut(")");
		Out.NextFillOut("words.");
		Out.NextFillOut("The parameter does not affect the demultiplexing loop.");
		Out.NextFillOut("The input channel must have this value for");
		Out.NextQuoteOut("InputElementSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetInputElementSize()));
		Out.NextFillOut(")");
		Out.NextFillOutConcat(".");
		Out.NextFillOut("If you are demultiplexing an element into its component");
		Out.NextFillOut("parts (such as demultiplexing complex data to real and");
		Out.NextFillOut("imaginary streams)");
		Out.NextQuoteOut("Channels");
		Out.NextFillOut("and");
		Out.NextQuoteOut("InputElementSize");
		Out.NextFillOut("must have the");
		Out.NextFillOut("same value.");
		Out.NextFillOut("The parameter does not affect the demultiplexing loop.");
		Out.NextFillOut("All output channels have this value for");
		Out.NextQuoteOut("OutputElementSize");
		Out.NextFillOut("(");
		Out.NextFillOut(TypeToString(GetOutputElementSize()));
		Out.NextFillOut(")");
		Out.NextFillOutConcat(".");
		Out.NewLine();
		break;
case ListEntityMembers:
		Out.NextOut(GetName());
		break;
case ListGlobalClasses:
case ListEntityClasses:
		break ;
case ListSetParameterValues:
		IntEntDemux->GetOneParameter("Channels")->
			IntP->CurrentValue = Channels_1;
		IntEntDemux->GetOneParameter("InputSampleSize")->
			IntP->CurrentValue = InputSampleSize_2;
		IntEntDemux->GetOneParameter("InputElementSize")->
			IntP->CurrentValue = InputElementSize_3;
		IntEntDemux->GetOneParameter("OutputElementSize")->
			IntP->CurrentValue = OutputElementSize_4;
		break;
	}
} // end  list entity switch

void DemuxNodesInit()
{
	if (DemuxNodeList)  return ;

	static StringParam DemuxNameParam =
		{"Demux", MakeNewEntityName, 0, LegalEntityName};
	static IntParam DemuxChannelsParam = {
		 2, 0,  0,  2, 0, 32767};
	static IntParam DemuxInputSampleSizeParam = {
		 1, 0,  0,  1, 0, 2.14748e+09};
	static IntParam DemuxInputElementSizeParam = {
		 1, 0,  0,  1, 0, 2.14748e+09};
	static IntParam DemuxOutputElementSizeParam = {
		 1, 0,  0,  1, 0, 2.14748e+09};

	static OneParameter DemuxParArray[] = {
		{"Name", 0, "node name", 0, 0, &DemuxNameParam},
		{"Channels", 0, 
			"number of output channels",
			&DemuxChannelsParam},
		{"InputSampleSize", 0, 
			"number of consecutive words demultiplexed in one input sample",
			&DemuxInputSampleSizeParam, 0, 0, 0, 0, 1},
		{"InputElementSize", 0, 
			"element size of input channels",
			&DemuxInputElementSizeParam, 0, 0, 0, 0, 1},
		{"OutputElementSize", 0, 
			"element size of output channels",
			&DemuxOutputElementSizeParam, 0, 0, 0, 0, 1},
		{0}
	};

	DemuxNodeList = new EntityList;
	IntEntDemux = new InteractiveEntity("Demux", DemuxNodeList,
		MakeDemux, InteractiveNode, "demux.h",
		0, "ProcessNode");
	IntEntDemux->SetParameters(new UserParameters(DemuxParArray));
	TheNodes->Append(IntEntDemux);
} // end initalization

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

case EntityReqDescribeFull:
		Out.NextQuoteOut("Demux");
		Out.NextFillOut("takes one input channel and demultiplexes it onto");
		Out.NextQuoteOut("Channels");
		Out.NextFillOut("output channels. The input channel must have samples consisting of");
		Out.NextQuoteOut("InputElementSize");
		Out.NextFillOut("words. For example, complex data streams");
		Out.NextFillOut("will generally have two words in each sample. The output data");
		Out.NextFillOut("stream will have samples or");
		Out.NextQuoteOut("OutputElementSize");
		Out.NextFillOut("words.");
		Out.NextQuoteOut("InputElementSize");
		Out.NextFillOut("and");
		Out.NextQuoteOut("OutputElementSize");
		Out.NextFillOut("do not affect the kernel");
		Out.NextFillOut("loop execution.");
		Out.NextQuoteOut("InputSampleSize");
		Out.NextFillOut("words are taken from the input");
		Out.NextFillOut("and written to the first output channel. The next");
		Out.NextQuoteOut("InputSampleSize");
		Out.NextFillOut("words of input are written to the next channel. This is done for");
		Out.NextFillOut("all output channels and then begins again with the first output channel.");
		Out.NewLine();
		break;

case EntityReqCreate:
	{
		const char * Name = IntNode.GetStringParameterValue("Name");
		int16 Channels =
			IntNode.GetIntParameterValue("Channels");
		int32 InputSampleSize =
			IntNode.GetIntParameterValue("InputSampleSize");
		int32 InputElementSize =
			IntNode.GetIntParameterValue("InputElementSize");
		int32 OutputElementSize =
			IntNode.GetIntParameterValue("OutputElementSize");
		return new Demux(Name, Channels, InputSampleSize, InputElementSize, OutputElementSize);

	}
	}
	return 0;
}

static InitObj LocalInit(DemuxNodesInit, "Demux", "ProcessNode");

