/*  dfnode.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include <stream.h>
#include <ctype.h>

#include "portable.h"
#include "debug.h"
#include "outtok.h"
#include "cgidbg.h"

#include "network.h"
#include "netlnk.h"
#include "intfc.h"
#include "yacintfc.h"
#include "strmstr.h"
#include "tarparm.h"
#include "travparm.h"
#include "bufstat.h"
#include "buffer.h"
#include "dfnode.h"
#include "mkstr.h"
#include "dspe_app.h"


void DfNode::Describe(OutTokens& Out, ListEntity)
		// interactive execution list
{
	Out.NextOut(GetName());
}

/*
 * void DfNodeList::Describe(OutTokens& Out, ListEntity Option)
 *		// interactive execution list
 * {
 *	if (!this) {
 *		State.Error("no node to describe");
 *		return ;
 *	}
 *	DfNodeIterator Next(*this) ;
 *	DfNode * TheNode;
 *	while(TheNode = Next()) {
 *		TheNode->Describe(Out,Option) ;
 *		if (State.IsError()) return ;
 *	}
 * }
 */

int DfNodeOutLink::DoTail()
{
	if (!CkNull("DoTail")) return 0;
	return OutLink->DoTail();
}


void DfNodeOutLink::UpdateWrite(int32 Size) // Add Size words to read pointer
{
	if (!CkNull("UpdateWrite")) return ;
	OutLink->UpdateWrite(Size);
}

StreamStr * DfNode::GetInStream(int i) const
{
	DfNodeInLink * InLink = GetInLink(i);
	if (InLink) return InLink->GetStreamStr();
	return 0 ;
}

StreamStr * DfNode::GetOutStream(int i) const
{
	DfNodeOutLink * OutLink = GetOutLink(i);
	if (OutLink) return OutLink->GetStreamStr();
	return 0 ;
}

DfNodeOutLink * DfNode::GetOutLink(int i) const
{
	// LogOut << "GetOutLink(" << i << ")\n" ;
	// LogOut << "Out = 0x" << Out << "\n" ;
	if (!Out) return 0;
	if (!CkOut(i,"GetOutLink")) return 0;
	return OutLinks+i ;
}

DfNodeInLink * DfNode::GetInLink(int i) const
{
	if (!In) return 0;
	if (!CkIn(i,"GetInLink")) return 0;
	return InLinks+i ;
}




DfNode * DfNode::GetDriverNode(int InChannel)
{
	DfNodeOutLink * Driver = GetDriverOutputChannel(InChannel);
	if (!Driver) return 0;
	return Driver->GetDriverNode();
}


MachWord * DfNodeOutLink::GetWriteBase()
{
	if (!CkNull("GetWriteBase")) return 0 ;
	return OutLink->GetBase();
}

MachWord * DfNodeOutLink::GetWriteEnd()
{
	if (!CkNull("GetWriteEnd")) return 0;
	return OutLink->GetEnd();
}

MachWord * DfNodeOutLink::GetWritePtr()
{
	if (!CkNull("GetWritePtr")) return 0;
	return OutLink->GetWritePtr();
}

void DfNodeOutLink::WriteCxWord(CxMachWord Data)
{
	if (!CkNull("WriteCxWord")) return ;
	OutLink->WriteCxWord(Data);
}

CxMachWord DfNodeInLink::ReadCxWord ()
{
	if (!CkNull("ReadCxWord")) return 0;
	return InLink->ReadCxWord(BufferChannelIndex) ;
}

int DfNodeOutLink::GetSpace()
{
	if (!CkNull("GetSpace")) return 0 ;
	return OutLink->GetSpace();
}

int DfNodeOutLink::GetContiguousSpace()
{
	if (!CkNull("GetContiguousSpace")) return 0 ;
	return OutLink->GetContiguousSpace();
}

void DfNodeOutLink::WriteBinary(BinMachWord Data)
{
	if (!CkNull("WriteBinary")) return ;
	OutLink->WriteBinary(Data);
}

void DfNodeOutLink::WriteWord(MachWord Data)
{
	if (!CkNull("WriteWord")) return ;
	OutLink->WriteWord(Data);
}

int DfNodeInLink::GetAvailableData()
{
	if (!CkNull("GetAvailableData")) return 0;
	return InLink->GetAvailableData(BufferChannelIndex) ;
}

int DfNodeInLink::GetContiguousAvailableData()
{
	if (!CkNull("GetContiguousAvailableData")) return 0;
	return InLink->GetContiguousAvailableData(BufferChannelIndex) ;
}

BinMachWord DfNodeInLink::ReadBinary ()
{
	if (!CkNull("ReadBomWord")) return (int16) 0;
	return InLink->ReadBinary(BufferChannelIndex) ;
}

MachWord DfNodeInLink::ReadWord ()
{
	if (!CkNull("ReadWord")) return (int16) 0;
	return InLink->ReadWord(BufferChannelIndex) ;
}

int DfNodeInLink::CkNull(const char * routine) const
{
	if (State.IsError()) return 0;
	if (InLink) return 1;
	State.Error("null input link from ",routine);
	return 0;
}

int DfNodeOutLink::CkNull(const char * routine) const
{
	if (State.IsError()) return 0;
	if (OutLink) return 1;
	State.Error("null output link from ",routine);
	return 0;
}

const char * DfNodeOutLink::GetDriverNodeName()
{
	DfNode * Driver = GetDriverNode();
	if (Driver) return Driver->GetName();
	return "ISOLATED NODE" ;
}

void DfNodeInLink::EmitBufferName(BufferOutInfo& Info)
{
	GetInLink()->GetDataBuffer()->OutTargetName(Info);
}

void DfNodeOutLink::EmitBufferName(BufferOutInfo& Info)
{
	GetOutLink()->GetDataBuffer()->OutTargetName(Info);
}


void DfNodeOutLink::EmitTargetBuffer(BufferOutInfo& Info)
{
	// LogOut << "EmitTargetBuffer\n" ;
	DfNodeLink * TheLink = GetOutLink();
	Buffer * TheBuffer = TheLink->GetDataBuffer() ;
	// Output reader information
	OutTokens& Out = Info.Out ;

	Out.NextOut("static BufferReadStatus");
	TheBuffer->OutTargetReadersName(Info);
	Out.NextConcat("[");
	Out.NextOut(TheLink->GetOutSize()) ;
	Out.NextConcat("] = {");
	Out.NewLine();
	for (int i = 0 ; i < TheLink->GetOutSize(); i++) {
		if (i) {
			Out.NextConcat(", ");
			Out.NewLine();
		}
		Out.NextFillOut("\t{ BufferOK, 0, 0 }");
	}
	Out.NewLine();
	Out.NextOut("} ;");
	Out.NewLine();
	
	TheBuffer->OutTargetDefinition(Info);

	Out.NewLine();
	Out.NextOut("/*");
	Out.NewLine();
	for (i = 0 ; i < TheLink->GetOutSize(); i++) {
		DfNodeInLink * NodeIn = TheLink->GetConsumerLink(i);
		Out.NextConcatToken(" *	LeftOver[");
		Out.NextConcatToken(i);
		Out.NextConcatToken("] = ") ;
		char buf[32];
		sprintf(buf,"%d",
			NodeIn->GetTargetReaderParameters() ->GetLeftOver());
		Out.NextOutToken(buf);
		Out.NewLine();
	}
	Out.NextOut(" */");
	Out.NewLine();
}
	
DfNode * DfNodeInLink::GetOutputNode()
{
	if (InLink)  return InLink->GetOutputNode(BufferChannelIndex) ;
	DbgError("DfNodeInLink::GetOutputNode","no link");
	return 0 ;
}

const char * DfNodeInLink::GetOutputNodeName()
{
	DfNode * Out = 0 ;
	if (InLink) Out = InLink->GetOutputNode(BufferChannelIndex) ;
	if (Out) return Out->GetName();
	return "ISOLATED NODE" ;
}

DfNode * DfNodeInLink::GetDriverNode()
{
	DfNodeOutLink * NodeOut = GetDriverOutputChannel();
	if (NodeOut) return NodeOut->GetDriverNode();
	return 0 ;
}

const char * DfNodeInLink::GetDriverNodeName()
{
	DfNodeOutLink * NodeOut = GetDriverOutputChannel();
	if (NodeOut) return NodeOut->GetDriverNodeName();
	return "ISOLATED NODE" ;
}


void DfNodeInLink::UpdateRead(int32 Size) // Add Size words to read pointer
{
	if (!CkNull("UpdateRead")) return ;
	InLink->UpdateRead(Size,BufferChannelIndex);
}

const MachWord * DfNodeInLink::GetReadBase()
{
	if (!CkNull("GetReadBase")) return 0;
	return InLink->GetBase();
}

const MachWord * DfNodeInLink::GetReadEnd()
{
	if (!CkNull("GetReadEnd")) return 0;
	return InLink->GetEnd();
}

const MachWord * DfNodeInLink::GetReadPtr()
{
	if (!CkNull("GetReadPtr")) return 0;
	return InLink->GetReadPtr(BufferChannelIndex);
}



void DfNodeInLink::Display()
{
/*
 *	TheLog << "DfNodeIn::Overlap = " << Overlap << "\n  IncrementIn = "
 *		<<IncrementIn<<", ElementSize = " << GetElementSize() << "\n" ;
 */
	if (InLink) InLink->Display() ;
}

void DfNodeInLink::NameDisplay()
{
	if (InLink) InLink->NameDisplay() ;
}

static const char * MakeNewNodeName(const char * CurrName)
{
	if (State.IsError()) return 0;
	// if name is `BODY_XX' where XX is a decimal number
	// set YY to XX+1 and return new name `BODY_XX'
	// Otherwise simply tack on _0 to existing name
	char * RetString ;
	if (!CurrName) {
		State.Error("no name for node to clone");
		return 0;
	}
	const char * pt = CurrName + strlen(CurrName)  - 1;
	while (isdigit(*pt--)) if (pt <= CurrName) break ;
	if (pt >=CurrName) if (*pt == '_') {
		RetString = new char[strlen(CurrName)+2];
		int value ;
		strcpy(RetString,++pt) ;
		sscanf(RetString,"%d",&value) ;
		strncpy(RetString,CurrName,pt-CurrName);
		RetString[pt-CurrName] = '\0' ;
		char buf[32] ;
		sprintf(buf,"%d",value++);
		strcat(RetString,buf);
	}
	else RetString = new char[strlen(CurrName)+3] ;
	strcpy (RetString,CurrName);
	strcat(RetString,"_0");
	return RetString ;
}

DfNode& DfNode::Clone()
{
	// Clone a copy of oneself with a different name
	if (State.IsError()) return *this ;
	const char * NewNodeName=MakeNewNodeName(GetName()) ;
	if (State.IsError()) return *this ;
	DfNode * MyClone = new DfNode(NewNodeName,In,Out,0) ;
	if (State.IsError()) return *this ;
	// initialize all links identically
	for (int i = 0 ; i < In ; i++) {
		DfNodeInLink * InLk = this->GetInLink(i) ;
		MyClone->GetInLink(i)->Set(
			InLk->GetElementSize(),InLk->IncrementIn,
			InLk->Overlap,InLk->Delay);
		if (State.IsError()) return *MyClone;
	}
	for (i = 0 ; i < Out ; i++) {
		DfNodeOutLink * OutLk = this->GetOutLink(i) ;
		MyClone->GetOutLink(i)->Set(
			OutLk->GetElementSize(),
			OutLk->IncrementOut);
		if (State.IsError()) return *MyClone;
	}
	return *MyClone ;
}

int32 DfNode::GetOverlap(int InChannel) const
{
	return GetInLink(InChannel)->GetOverlap();
}

int32 DfNode::GetDelay(int InChannel) const
{
	return GetInLink(InChannel)->GetDelay();
}

void DfNode::GraphDisplay(GraphInfo& graph, int in_channel)
{
/*
 *	LogOut << "DfNode::GraphDisplay(" << in_channel << ") for `" << GetName()
 *		<<"'\n" ;
 *	LogOut << "ParentNodeName = " << graph.NodeName << "\n" ;
 */
	int continuation = graph.Continuation();
	GraphInfo Graph = graph ; // save current state
	Graph.NodeName = GetName();
	Graph.SetContinuation();

	OutTokens& O = *(Graph.GetOut());
	char * NodeName = 0 ;
	int in = -1 ;
	char buf[32];
	sprintf(buf,"%d",in_channel);
	if (In) CkIn(in_channel,"DfNode::GraphDisplay");
	else if (in_channel != -1) DbgError("DfNode::GraphDisplay","bad channel");
	if (In) if (in_channel)
		NodeName = Concatenate(GetName(),".LinkIn(",buf,")");
	if (!NodeName) NodeName = Concatenate(GetName());
	for (in = 0; in<In;in++) if (GetInLink(in)->is_linked()) break ;	
	int first_link = 1 ;
/*
 *	LogOut << "Out = " << Out << ", in_channel = " << in_channel <<
 *		", in = " << in << "\n" ;
 */
	if (!Out || ((in_channel > 0) && (in_channel != in))) {
		O.NextOut(NodeName) ;
		if (!Graph.DoCpp()) O.NextOut("END.") ;
		else O.NextOut(";") ;
		O.NewLine() ;
	} else for (int out = 0 ; out < Out ; out ++) {
		int continue_network = 0 ;
		DfNodeLink * node_link = OutLinks[out].GetOutLink();
		if (node_link) if (node_link->Size()) continue_network = 1 ;
		if (!continue_network) if (out != Out-1) continue ;
		else {
			O.NextFillOut(NodeName);
			O.NextConcat(";");
			O.NewLine();
			break ;
		}
	
		Graph.OutChannel = out;
		char * NodeBuf = 0 ;
		int linking = 0 ;
		if (In || ! first_link) {
			if ((!continuation || !first_link) && OutLinks[out].is_linked()) {
				linking = 1 ;
				delete NodeName ;
				O.NewLine();
				sprintf(buf,"%d",out);
				NodeName = Concatenate(Graph.NetName,
					".Link(",GetName(),",", buf,")");
			}
		}
		if (In || linking || first_link) O.NextFillOut(NodeName);
		first_link = 0 ;
/*
 *		LogOut << "DfNode::gd for `" << GetName() << "', con = " <<
 *			continue_network << ", Out = " << Out << ", out = " << out << "\n" ;
 */
		if (continue_network) {
			O.NextFillOut(">>");
			OutLinks[out].GraphDisplay(Graph) ;
		} else {
			O.NextFillOut(";");
			O.NewLine();
		}
	}
	delete NodeName ;
	// graph.NodeName = ParentNodeName ;
	// if (!continuation) graph.ClearContinuation();
}

ErrCode TargetNode::Reset()
{
	SequenceIndex = 0 ;
	return ((DfNode *) this)->DoReset();
}

ErrCode DfNode::DoReset()
{
	if (IsTraverseFlag(GenericTraverseBit)) return OK ;
	SetTraverseFlag(GenericTraverseBit);
	int i ;
	ErrCode Ret = OK ;
	ErrCode Loc = OK ;
	for (i = 0 ; i < In ; i++) if ((Loc = InLinks[i].Reset())
		> Ret) Ret = Loc ;
	for (i = 0 ; i < Out ; i++) if ((Loc = OutLinks[i].Reset())
		> Ret) Ret = Loc ;
	History = 0 ;
	// LogOut << "NodeReset for `" << GetName() << "'\n" ;
	Loc = NodeReset();
	// LogOut << "NodeReset for `" << GetName() << "' return\n" ;
	if (Loc > Ret) Ret = Loc ;
	ClearTraverseFlag(GenericTraverseBit);
	return Ret ;
} 

int TargetNode::CkIn(int in, const char * Routine) const
{
	if (State.IsError()) return 0;
	if (in < In && in > -1) return 1;
	State.Error("bad input channel ", Dec(in), " in node `",
		GetName(), "' in routine ", Routine);
	return 0;
}

int TargetNode::CkOut(int out, const char * Routine) const
{
	if (State.IsError()) return 0;
	if (out < Out && out > -1) return 1 ;
	// LogOut << "DfNode::CkOut(" << out << ", " << Routine << ")\n" ;
	State.Error("bad output channel ", Dec(out), " in node `",
		GetName(), "' in routine ", Routine);
	return 0;
}

int32 TargetNode::GetInEltSize(int index) const
{
	if (!CkIn(index,"GetEltSize")) return  0;
	return InLinks[index].GetElementSize() ;
}


int32 TargetNode::GetEltSize(int index) const
{
	if (!CkOut(index,"GetEltSize")) return 0 ;
	return OutLinks[index].GetElementSize() ;
}

double DfNode::GetMaximumX(int index)
{
	if (!CkIn(index,"GetMaximumX")) return 0 ;
	const StreamStr * Str = InLinks[index].GetStreamStr();
	if (!Str) return 0 ;
	return Str->GetMaximumX();
}

double DfNode::GetMinimumX(int index)
{
	if (!CkIn(index,"GetMinimumX")) return 0 ;
	const StreamStr * Str = InLinks[index].GetStreamStr();
	if (!Str) return 0 ;
	return Str->GetMinimumX();
}

int32 DfNode::GetBlockSize(int index)
{
	if (!CkIn(index,"GetBlockSize")) return 0 ;
	const StreamStr * Str = InLinks[index].GetStreamStr();
	if (!Str) return 0 ;
	int32 Size = Str->GetBlockSize();
	if (!Size) {
		TheLog << "Warning null BlockSize in node `" << GetName() << "'\n";
		Size = 1 ;
	}
	return Size ;
}

void DfNode::NameDisplay()
{
	if (!GetName()) {
		TheLog << "NULL name.\n" ;
		return ;
	}
	TheLog << "DfNode::" << GetName() << " In =" << In << ", Out = "<< Out
		<< "\n\n" ;
}


void DfNode::Display()
{
	NameDisplay();
	if (In) {
		TheLog << "\n\nInput links:\n" ;
		for (int i =0 ; i < In ; i++)
			InLinks[i].NameDisplay() ;
	} else TheLog << "No input links.\n" ;
	if (Out) {
		TheLog << "\n\nOutput Links:\n" ;
		for (int i =0 ; i < Out ; i++) OutLinks[i].Display() ;
	} else TheLog << "No output links.\n" ;
}


void DfNode::Clear()
{
	NotYetIn("DfNode::Clear");
}



DfNode * DfNode::FindTail(int OutChannel)
{
	DfNode * temp;
	if (OutChannel >= Out || OutChannel < 0) {
		// LogOut << "Channel = " << OutChannel << "\n" ;
		// NameDisplay() ;
		State.Error("access to invalid channel in node `",
			GetName(), "'");
		return 0;
	}
	if (OutLinks[OutChannel].GetOutLink()) {
		if (temp=OutLinks[OutChannel].GetOutLink()->FindTail())
			return temp ;
		else return 0;   // cannot simply append must specify
			 	// where to add
	} else return this ;
}


static ErrCode ReportLinkError(DfNode * source, DfNode * dest,
	const char * What)
{
	State.Error("problem in linking from `", source->GetName(),
		"' to `", dest->GetName(), "'");
	*Output + OutputCppHelp << What << ".\n" ;
	source->clear_thread();
	return FatalError ;
}


ErrCode DfNode::Append(DfNode * node, int OutputLk, int InputLk,
	int TheFlag)
// Append `node' to `this'.
// OutputLk is the index of the output channel from `this'.
// InputLk is the index of the input channel to `node'.
// If FirstFlag is set than this must be the the first output
// from `this'.
{
	// LogOut << "DfNode::Append " << GetName()  << "\n" ;
	if (State.IsError()) return FatalError ;
	if (!node) DbgError("DfNode::Append", "NULL node");
	// LogOut << "DfNode::Append of " << node->GetName() << "\n"  ;
	if (InputLk < 0) {
		InputLk = node->GetFreeInLink();
	}

	if (InputLk < 0) return ReportLinkError(this,node,
		"There are no free links to add to the destination node") ;

	const StreamStr * link_from = GetOutputStreamStr(OutputLk);
	if (!link_from) return ReportLinkError(this,node,
		"Cannot get `link from' stream descriptor");
	const StreamStr * link_to = node->GetInStream(InputLk);
	if (!link_to) return ReportLinkError(this,node,
        "Cannot get `link to' stream descriptor");
	ErrCode check_arith = link_from->CheckReportArithType(*link_to,
		node,InputLk);
	if (check_arith != OK) return ReportLinkError(this,node,
		"Incompatible arithmetic");

	if (OutLinks[OutputLk].GetOutLink()) {
		 if (TheFlag&1) return ReportLinkError(this,node,
			"The output channel in the source node is in use");
	} else  OutLinks[OutputLk].SetLink(new DfNodeLink(this,OutputLk)) ;
	// create a new link and set this output channel to point to it

	if (State.IsError()) return ReportLinkError(this,node,
		"Error in setting up output link from source");

	OutLinks[OutputLk].GetOutLink()->AppendOut(node,InputLk,TheFlag&2?1:0) ;
	if (State.IsError()) return 
		ReportLinkError(this,node, "Error in creating output link");
	// append a pointer to the new link to the new (or existing) list
	// if TheFlag&2 is set this is a SelfLink - not the additon of a new node

	int Index = OutLinks[OutputLk].GetOutLink()->Size() - 1 ;
	if (State.IsError()) return ReportLinkError(this,node,
		"Error in getting output channel index");
	// LogOut <<"Just set output link: " << OutputLk <<
	// 	", for buffer output channel = " << Index <<".\n" ;
	// LogOut << "This links " << GetName() << " to :" ;
	// node->NameDisplay() ;
	node->SetInLink(OutLinks[OutputLk].GetOutLink(),InputLk,Index) ;
	if (State.IsError()) return ReportLinkError(this, node,
			"Error in setting up link");
	return OK ;
}

void DfNode::input_linked(int in_channel)
{
	// virtual functions can set output block size, etc.  base on input
	// structure
}

void DfNode::MustBeActiveNet()
{
	if (!GetActiveNet()) DbgError("DfNode::MustBeActiveNet",
		"in use and no active net");
}

int DfNode::CheckLinked()
{
	for (int i = 0 ; i < In ; i++) if (InLinks[i].GetInLink()) return 1 ;
	for (i = 0 ; i < Out ; i++) if (OutLinks[i].GetOutLink()) return 1 ;
	return 0;
}

int DfNode::check_safe_delete()
{
	// want to delete links
	if (!CheckLinked()) return 1 ;
	if (State.IsInOverwrite()) return 1 ;
	MustBeActiveNet();
	*Output + OutputCppHelp << "Node `" << GetName() <<
		"' is linked into network `" << GetActiveNet()->GetName() <<
		"'.\n" ;
	return 0 ;
/*
 *	for (;;) {
 *		const char * Resp = ::GetName(
 *		"`yes' to clear all network links or\n\tRETURN to abort deleting this node");
 *		if (!strcmp(Resp,"yes")) return 1;
 *		if (!strlen(Resp)) return 0;
 *	}
 */
}

void DfNodeOutList::Display()
{
	if (!this) return ;
	DfNodeOutIterator Next(*this);
	DfNodeOut * Curr;
	while (Curr = Next()) {
		Curr->Display();
/*
 *		LogOut << "In this link data goes to input channel " <<
 *			Curr->GetIndex() << " in the above consumer node.\n" ;
 */
	}
}

void DfNodeOutList::NameDisplay()
{
	if (!this) return ;
	DfNodeOutIterator Next(*this);
	DfNodeOut * Curr;
	while (Curr = Next()) Curr->NameDisplay() ;
}

void DfNodeOutList::remove_link(DfNode* driven, int input_channel)
{
	DfNodeOutIterator Next(*this);
	DfNodeOut * out;
	DfNodeOut * to_remove = 0 ;
	int count = 0 ;
	while (out = Next()){
		 if (to_remove) out->decrement_buffer_channel(count);
			else if (out->GetNode() == driven &&
			out->GetIndex() == input_channel) {
				to_remove = out ;
				count-- ;
			}
		count++ ;
	}
	if (!to_remove) DbgError("DfNodeOutList::remove_link",driven->GetName());
	ErrCode ret = SingleList::RemoveEntry((Entity)to_remove);
	if (ret != OK) DbgError("DfNodeOutList::remove_link_2",driven->GetName());
}

int DfNodeOutList::CheckComplete(const char * Name )
{
	if (State.IsError()) return 0 ;
	int Complete = 1;
	DfNodeOutIterator Next(*this);
	DfNodeOut * Elt ;
	while (Elt = Next()) if (!Elt->GetNode()) {
		Complete = 0;
		if (State.IsError()) break ;
		State.Error("missing output node in  network `", Name, "'" );
		break ;
	} else if (!Elt->CheckComplete()) {
		Complete = 0;
		if (State.IsError()) break ;
		State.Error("incomplete output links from network `",
			Name, "' in node `", Elt->GetNode()->GetName(),"'") ;
		break ;
	} 
	return Complete;
}


int DfNode::GetFreeInLink()
{
	int Return = -1;
	for (int i = 0 ; i < In ; i ++) if (!InLinks[i].GetInLink()) {
		Return = i ;
		break ;
	}
	if (UseInLink > -1) if (CkIn(UseInLink,"LinkIn")) Return = UseInLink ;
	UseInLink = -1 ;
	return Return;
}

int DfNode::SetActiveNet(ProcessNet * Net)
{
	if (!Net) {
		ActiveNet = 0 ;
		return 1 ;
	}
	if (!ActiveNet) ActiveNet = Net;
	else if (ActiveNet != Net) return 0;
	return 1 ;
}
	
// RENAME
void DfNode::SubtractExecCount(int32 count)
{
	ExecCount += count ;
	if (count < 0) {
/*
 *	 	LogOut << "DfNode::Subtract - Negative execute count (" <<
 *			count << ") in `" << GetName() << "'.\n" ;
 */
		count = 0 ;
	}
}

int32 DfNode::GetEltSize(int index)
{
	// LogOut << "GetEltSize for `" << GetName() << "\n" ;
	return TargetNode::GetEltSize(index);
}

int32 DfNode::GetInEltSize(int index)
{
	// LogOut << "GetInEltSize for `" << GetName() << "\n" ;
	return TargetNode::GetInEltSize(index);
}

const char * DfNode::EmitTargetState(OutTokens& Out)
{
	int i;
	// LogOut << "EmitTargetState for " << GetName() << "\n" ;
	// LogOut << "In = " << GetIn() << ", Out = " << GetOut() << "\n" ;
	// Emit input links
	if (GetIn()) {
		Out.NextOut("static DfNodeInLink");
		Out.NextConcatToken(GetName());
		Out.NextOutToken(InputLinksSuffix);
		Out.NextConcat("[");
		Out.NextOut(GetIn());
		Out.NextConcat("] = {");
		Out.NewLine();
		for (int i = 0 ; i < GetIn() ; i++) {
			DfNodeInLink * InLk = GetInLink(i);
			if (i) {
				Out.NextConcat(",");
				Out.NewLine();
			}
			Out.NextConcat("\t{ ");
			Out.NextOut(InLk->GetElementSize()) ;
			Out.NextConcat(", ");
			Out.NextOut(InLk->GetBlockSize()) ;
			Out.NextConcat(", ");
			Out.NextOut(InLk->GetOverlap()) ;
			Out.NextConcat(", ");
			Out.NextOut(InLk->GetIncrementIn()) ;
			Out.NextConcat(", ");
			Out.NextOut(InLk->GetDelay()) ;
			Out.NextConcat(", ");
			Out.NextOut(InLk->GetBufferChannelIndex());
			Out.NextOut(", &");
			BufferOutInfo Info(Out,InLk->GetDriverNodeName(),
				InLk->GetDriverOutputChannel()->
				GetDriverChannel());
			InLk->EmitBufferName(Info);
			Out.NextConcat(", ");
			Out.NextOut(i);
			Out.NextConcat(", ");
			// Shift, count, minimum, history
			InLk->EmitTargetReaderParameters(Out);
			Out.NextConcat(", ");
			Out.NextOut("0") ;  // Initialize history
			Out.NextOut(" }");
		}
		Out.NextConcat("} ;");
		Out.NewLine();
	}

	if (!GetOut()) return 0 ;

	// Emit output links
	Out.NextOut("static DfNodeOutLink");
	Out.NextConcatToken(GetName());
	Out.NextOutToken(OutputLinksSuffix);
	Out.NextConcat("[");
	Out.NextOut(GetOut());
	Out.NextConcat("] = {");
	Out.NewLine();
	for (i = 0 ; i < GetOut() ; i++) {
		// LogOut << "i = " << i << "\n" ;
		if (i) {
			Out.NextConcat(",");
			Out.NewLine();
		}
		BufferOutInfo Info(Out,GetName(),i);
		Out.NextConcat("\t{ ");
		Out.NextOut(GetEltSize()) ;
		Out.NextConcat(", ");
		Out.NextOut(GetOutLink(i)->GetBlockSize()) ;
		Out.NextConcat(", ");
		Out.NextOut(GetIncrementOut(i)) ;
		Out.NextOut(", &");
		GetOutLink(i)->EmitBufferName(Info);
		Out.NextConcat(", ");
		Out.NextOut(i);
		Out.NextConcat(", ");
		GetOutLink(i)->EmitTargetWriterParameters(Out);
		Out.NextOut("}");
	}
	Out.NextConcat("} ;");
	Out.NewLine();
	// LogOut << "EmitTargetState for " << GetName() << " exiting\n" ;
	return 0 ;
}

TraverseObject::TraverseObject(OutTokens& out, const char * doing_what,
	ostream& head, TraverseParameters* params, TraverseType type,
	MemberFunc forward, MemberFunc backward):
	Out(out),
	DoingWhat(doing_what),
	HeaderOut(head),
	Params(params),
	TheType(type),
	ForwardAction(forward),
	BackwardAction(backward)
{
}

TraverseObject::~TraverseObject()
{
	ClearParameters();
}

void TraverseObject::ClearParameters()
{
	delete Params ;
	Params = 0 ;
}

TraverseParameters * TraverseObject::GetParameters() const
{
	if (!Params) DbgError("TraverseObject::GetParameters","null");
	return Params;
}

BufferStatus * TraverseObject::GetBufferStatus() const
{
	return GetParameters()->GetBufferStatus();
}

TraverseResult TraverseObject::DoForwardAction(DfNode& node)
{
	if (!ForwardAction) return TraverseOK ;
	return (node.*ForwardAction)(*this);
}

TraverseResult TraverseObject::DoBackwardAction(DfNode& node)
{
	if (!BackwardAction) return TraverseOK ;
	return (node.*BackwardAction)(*this);
}

void TraverseObject::SetForwardAction(MemberFunc forward)
{
	if (ForwardAction) DbgError("TraverseObject::SetForwardAction",
		"already set");
	ForwardAction = forward;
}

void TraverseObject::SetBackwardAction(MemberFunc backward)
{
	if (BackwardAction) DbgError("TraverseObject::SetBackwardAction",
		"already set");
	BackwardAction = backward;
}

int32 DfNode::GetDriverElementSize(int InChannel)
{
	DfNodeOutLink * Driver = GetDriverOutputChannel(InChannel);
	if (!Driver) return 0;
	return Driver->GetElementSize();
}

DfNodeOutLink * DfNode::GetDriverOutputChannel(int InChannel)
{
	DfNodeInLink * In = GetInLink(InChannel);
	if (!In->GetInLink()) return 0;
	return In->GetDriverOutputChannel();
}

void DfNode::InitArithType(ArithType::ArithCapabilities type)
{
	InitArithType((ArithType::ArithTypes) type);
}

void DfNode::InitArithType(ArithType::ArithTypes type)
{
/*
 *	LogOut << "DfNode::InitArithType(" << type << "), in = " << GetIn() <<
 *		", out = " << GetOut() << "\n" ;
 */
	if (State.IsError()) return ;	
	for (int i = 0 ; i < GetIn() ; i++) {
		DfNodeInLink * in = GetInLink(i);
		if (!in) DbgError("DfNode::InitArithType","bad link in");
		in->InitArithType(type);
	}
	for (i = 0 ; i < GetOut() ; i++) {
		DfNodeOutLink * out = GetOutLink(i);
		if (!out) DbgError("DfNode::OutArithType","bad link out");
		out->InitArithType(type);
	}
}

