/*  netlnk.C   */
/*  Copyright 1991 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 "usercom.h"

#include "travparm.h"
#include "network.h"
#include "netlnk.h"
#include "strmstr.h"
#include "intfc.h"
#include "yacintfc.h"
#include "cgidbg.h"
#include "bufstat.h"
#include "dspe_app.h"

void TestAlloc(const char * msg);

#ifdef __NT_VC__
char * dec(int i)
{
	static char buf[32] ;
	sprintf(buf,"%d",i);
	return buf ;
}
char * hex(int i)
{
	static char buf[32] ;
	sprintf(buf,"%0x",i);
	return buf ;
}
#endif

void DfNodeList::Display()
{
	if (!this) return ;
	DfNodeIterator Next(*this);
	DfNode * Curr;
	while (Curr = Next()) Curr->Display();
}

void DfNodeList::NameDisplay()
{
	if (!this) return ;
	DfNodeIterator Next(*this);
	DfNode * Curr;
	while (Curr = Next()) Curr->NameDisplay();
}

int DfNodeList::InList(DfNode * nt)
{
	DfNodeIterator Next(*this);
	DfNode * Elt ;
	while (Elt = Next()) if (Elt == nt) return 1;
	return 0;
}

/* 
 * int DfNodeList::CheckComplete(const char * Name )
 * {
 *	int Complete = 1;
 *	DfNodeIterator Next(*this);
 *	DfNode * Elt ;
 *	while (Elt = Next()) if (!Elt->CheckComplete()) {
 *		Complete = 0;
 *		LogOut << "Incomplete DfNodeList from `" << Name <<
 *			"' in DfNode `" <<
 *			Elt->GetName() << "'.\n" ;
 *	}
 *	return Complete;
 * }
 */


int DfNode::GetFreeOutLink()
{
	// LogOut << "DfNode::GetFreeOutLink\n" ;
	for (int i = 0 ; i < Out ; i++)
		if (!GetOutLink(i)->GetOutLink()) return i;
	return -1 ;
}

int DfNode::CheckComplete()
{
	// LogOut << "CheckComplete : " << GetName() << "\n" ;
	if (UseInLink == -2) {
		return 1 ; // this avoids infinite loop
	}
	UseInLink = -2 ;
	int Complete = 1;
	char Buf[48];
	for (int i = 0; i < In ; i++) {
		if (!InLinks[i].CheckComplete(GetName())) {
			strcpy(Buf,"input link ");
			strcat(Buf,dec(i));
			State.Error(Buf," in node `",GetName(),
				"' is not complete");
			Complete = 0 ;
		}
	} 
	for (i = 0; i < Out ; i++) {
		strcpy(Buf,"output link ");
		strcat(Buf,dec(i));
		int LocalComplete = 0 ;
		LocalComplete = OutLinks[i].CheckComplete(GetName());
		DfNodeLink * InLink = OutLinks[i].GetOutLink() ;
		if (!InLink) {
			State.Error(Buf, " has a null connection in node `",
				GetName(), "'");
			UseInLink = -1;
			return 0;
		}
		DfNodeIn * InLk = InLink->GetInputLink();
		int BadLk = 0 ;
		if (InLk->GetIndex() != i) BadLk = 1;
		if (InLk->GetNode() != this) BadLk |= 2;
		if (BadLk) {
			Complete = 0;
			State.Error("inconsistent back pointer in node `",
				GetName(), "' and ", Buf);
			if (BadLk & 1) *Output + OutputCppHelp <<
				"Back index is " <<
				InLk->GetIndex() << ".\n" ;
			if (BadLk & 2) *Output + OutputCppHelp <<
				"Node is incorrect.\n" ;
		}
		if (!LocalComplete) {
			State.Error(Buf, " in node `",
				GetName(), "'") ;
			if (OutLinks[i].GetOutLink()) *Output + OutputCppHelp <<
				"The link is incomplete.\n" ;
			else *Output + OutputCppHelp << "The link is missing.\n";
			Complete = 0;
		}
		if (!OutLinks[i].CheckComplete(GetName())) {
			State.Error( Buf, " in node `",
				GetName(), "'") ;
			Complete = 0 ;
		}
	} 
	UseInLink = -1;
	return Complete ;
}

int DfNode::DoTail()
{
	// LogOut << "DoTail for `" << GetName() << "'\n" ;
	if (UseInLink == -2) return 0 ; // this avoids infinite loop
	UseInLink = -2 ;

	// Find out how many times we can execute based on input data
	// Then call Execute Node for this many times
	
	const int32 Big = 0x40000000 ;
	ExecLimit = Big ;
	for (int i = 0 ; i < In ; i++) {
		int32 LocMaxExe = InLinks[i].GetCanExecute(SequenceIndex) ;
/*
 *		LogOut << "DfNode::DoTail - LocMaxExe = " << LocMaxExe <<
 *			", ExecLimit = " << ExecLimit << "\n" ;
 */
 
		if (LocMaxExe < ExecLimit) ExecLimit = LocMaxExe ;
	}
	int32 DelayExe = Delay - History ;

/*
 *	LogOut << "Delay = " << Delay << ", History = " << History <<
 *		", DelayExe = " << DelayExe << "\n" ;
 */

	for (i = 0 ; i < Out ; i ++) {
		int32 LocExe = OutLinks[i].GetCanExecute() ;
		if (LocExe < DelayExe) DelayExe = LocExe ;
		if (LocExe - DelayExe < ExecLimit) ExecLimit =
			LocExe - DelayExe ;
/*
 *		LogOut << "LocExe = " << LocExe << ", DelayExe = " <<
 *			DelayExe << ", ExecLimit = " << ExecLimit <<"\n" ;
 */
	}
/*
 *	LogOut << GetName() << "::DelayExe = "<<DelayExe << ", ExecLimit = " <<
 *		ExecLimit <<"\n" ;
 */
 
	History += DelayExe ;
	ExecLimit += DelayExe ;
	int MadeProgress = 0;
	int32 DidExe = 0 ;
/*
 *	LogOut << "ExecLimit for `" << GetName() << "' = " <<
 *		GetExecLimit() << "\n" ;
 */ 
	if (ExecLimit) DidExe = ExecuteNode(ExecLimit) ;
	if (DidExe <0) {
		UseInLink = -1 ;
		return DidExe ;
	}
	int ExTailP = 0;
	if (Out) ExTailP = ExecuteTail() ;
	MadeProgress = MadeProgress || DidExe || ExTailP ;
/*
 *  	LogOut << "DoTail of `" << GetName() << "', DidExe = " << DidExe <<
 *		", Tail return = " << ExTailP << ".\n" ;
 */


	UseInLink = -1 ;
	return MadeProgress ;
}

int DfNode::ExecuteTail()
{
	if (State.IsError()) return 0 ;
	int MadeProgress = 0 ;
	// LogOut << "ExecuteTail(" << GetName() << "), Out = " << Out <<"\n" ;
	for (int i = 0 ; i < Out ; i ++) {
		int Progress = OutLinks[i].DoTail() ;
		// LogOut << "ExecuteTail, Progress = " << Progress << "\n" ;
		if (State.IsError()) {
			State.Error("detected in node `", GetName(), "'");
			// LogOut << "DfNode::ExecuteTail error exit\n" ;
			return 0 ;
		}
		if (Progress < 0) return Progress ;
		MadeProgress = MadeProgress || Progress ;
	}
	// LogOut << "DfNode::ExecuteTail exit\n" ;
	return MadeProgress ;
}

static void ErrorCheckTiming(TimingDescription * Timing, const char * name,
	const char * where, int chan, const char * InOut)
{
	int Warn = 0 ;
	if (Timing) {
		int32 Numerator = Timing->NumeratorSampling ;
		if (!Numerator) { Warn=1 ; }
		int32 Denominator = Timing->DenominatorSampling ;
		if (!Denominator) { Warn |= 2 ; }
	} else Warn = 100 ;
	if (Warn) TheLog << "*******Time Warn = " << Warn
		<< " " << name << " " << where << " " << chan << " " <<
		InOut << "\n" ;
		
}

static void ErrorCheckTiming(DfNode * TheNode,const char * Where)
{
	for (int i = 0 ; i < TheNode->GetIn(); i++)
		ErrorCheckTiming(TheNode->GetInLink(i)->GetTiming(),
			TheNode->GetName(),Where,i,"in");

	for (i = 0 ; i < TheNode->GetOut(); i++)
		ErrorCheckTiming(TheNode->GetTiming(i),
			TheNode->GetName(),Where,i,"out");
}

/*
 * static void ErrorCheckTimingX(DfNode * TheNode,const char * Where)
 * {
 *	 DfNode * BadCheck=TheNode->GetActiveNet()->FindNode("V27T48JoinEncode");
 *	if (BadCheck) ErrorCheckTiming(BadCheck,Where);
 *	if (BadCheck != TheNode) ErrorCheckTiming(TheNode,Where);
 * }
 */


int32 DfNode::ExecuteNode(int32 k)
{
// First determine how many times we can execute for
// given the available buffer space
// Compute output data k executions will generate
	ExecLimit = k ;
	int32 LocCanExe ;
	if (State.IsError()) return -1 ;
	// LogOut << "In DfNode::ExecuteNode(" << GetName() << ").\n" ;
	for (int i = 0; i < Out ; i++ )  {
		if ((LocCanExe = OutLinks[i].GetCanExecute()) < ExecLimit)
			ExecLimit = LocCanExe ;
/*
 *	 	 LogOut << "DfNode::ExecuteNode(" << GetName() <<
 *			") - LocCanExe = " << LocCanExe << ", ExecLimit = "
 *			<< ExecLimit << "\n" ;
 */
 
	}
	ErrCode  Return = OK ;
	ExecCount = ExecLimit ;
	// LogOut << "ExecLimit for `" << GetName() << "' = " << ExecLimit <<"\n";
	if (!ExecLimit || NodeState >= EndOfData) return 0 ;
	if (DspApplication::is_trace())
		TheLog << "Execute `" << GetName() << "' for " << ExecLimit << "\n" ;
	if (DspApplication::is_heap()) TestAlloc("entry");
	Return = DoNode(ExecLimit) ;
	if (State.IsError()) if (Return < FatalError) Return = FatalError ;
	const char * warn = 0 ;
	switch(Return) {
case OutputBuffersFull:
			if (State.IsVerbose()) warn = "output buffers full in `" ;
			break ;
case Warning:
			warn = "from `" ;
			break ;
case EndOfData:
			NodeState = EndOfData ;
			warn = "end of data in `" ;
			break ;
case ExecutionComplete:
			NodeState = ExecutionComplete ;
			warn = "execution complete in `" ;
			break ;
case OK:
case FatalError:
			break ;
default:
			State.Error("invalid return state (", dec(Return),") from `",
				GetName(), "'");
			break ;
	}
	if (warn) State.Warning(warn, GetName(), "'");
	if (DspApplication::is_heap()) TestAlloc("exit");
	if (DspApplication::is_trace()) TheLog << "`" << GetName()<<"' exit.\n" ;
	if (Return > ExecutionComplete) {
/*
 *		LogOut << "ExecLimit = " << ExecLimit << " Error from: `"
 *			<< GetName() << "'\n" ;
 *		LogOut << "Return = " << Return << ", OK = " << OK << "\n" ;
 */
		State.Error("error in node `", GetName(), "'");
		// LogOut << "returning -1\n" ;
		return -1 ;
	}
	return ExecCount ;
}


DfNode * DfNode::FindNode(const DfNode * node)
{
	if (node==this) return this ;
	if (IsTraverseFlag(FindBit)) return 0 ; // this avoids infinite loop
	SetTraverseFlag(FindBit);
	DfNode * Found ;
	for (int i = 0; i < Out ; i++)
		if (Found = OutLinks[i].FindNode(node)) {
		ClearTraverseFlag(FindBit);
		return Found ;
	}
	ClearTraverseFlag(FindBit);
	return 0;
}

DfNode * DfNode::FindNode(const char * node)
{
	if (!strcmp(node,GetName())) return this ;
	if (IsTraverseFlag(FindBit)) return 0 ; // this avoids infinite loop
	SetTraverseFlag(FindBit);
	DfNode * Found ;
	for (int i = 0; i < Out ; i++)
		if (Found = OutLinks[i].FindNode(node)) {
		ClearTraverseFlag(FindBit);
		return Found ;
	}
	ClearTraverseFlag(FindBit);
	return 0;
}


DfNodeOutLink::DfNodeOutLink():
	InitStreamStructure(0)
{
	Init();
}

DfNodeOutLink::~DfNodeOutLink()
{
	// TestAlloc("DfNodeOutLink::~DfNodeOutLink");
	Clear();
	delete InitStreamStructure ;
	InitStreamStructure = 0 ;
	// TestAlloc("DfNodeOutLink::~DfNodeOutLink exit");
}


void DfNodeInLink::init_stream(StreamStr * str)
{
/*
 *	if (InLink) LogOut <<
 *		"DfNodeInLink::init_stream for " << GetDriverNodeName() << "\n" ;
 *	LogOut << "Arith = " << str->GetArithType() << "\n" ;
 */
	TheStreamStructure = str ;
	InitStreamStructure = new StreamStr(*str);
}

void DfNodeOutLink::init_stream(StreamStr * str)
{
	TheStreamStructure = str ;
	InitStreamStructure = new StreamStr(*str);
}

int DfNodeOutLink::IsFeedbackHead() const
{
	return GetOutLink()->IsFeedbackHead();
}


void DfNodeOutLink::GraphDisplay(GraphInfo& Graph)
{
	const char* ParentNode = Graph.NodeName ;
	int Elt = GetElementSize() != 1 ;
	int Inc = IncrementOut != 1;
	int Tail = Inc ;
	char * NewName = new  char[strlen(Graph.NodeName)+32] ;
	strcpy(NewName, Graph.NodeName) ;
	if (Graph.DoTime()) {
		char Buffer[132];
		strcpy(Buffer,"{");
		strcat(Buffer,dec(Timing.NumeratorSampling)) ;
		strcat(Buffer, " / ");
		strcat(Buffer,dec(Timing.DenominatorSampling)) ;
		if (Timing.FirstSample != 0 ) {
			char bf[64] ;
			sprintf(bf,"%f",Timing.FirstSample);
			strcat(Buffer," : ");
			strcat(Buffer,bf);
			if (Timing.ErrorTolerance > 0.0) {
				sprintf(bf,"(%f)",Timing.ErrorTolerance);
				strcat(Buffer,bf);
			}
		}
		strcat(Buffer,"}");
		
		Graph.GetOut()->NextOut(Buffer);
		strcat(NewName," ") ;
		strcat(NewName,Buffer) ;
		Graph.NodeName = NewName ;
	} else if (Graph.DoFull()) if (Elt || Tail) {
		char Buffer[32];
		strcpy(Buffer,"{");
		if (Elt) strcat(Buffer, dec(GetElementSize()));
		if (Tail) {
			if (Elt) strcat(Buffer,"*");
			strcat(Buffer,"k");
			if(Inc) {
				strcat(Buffer,"*");
				strcat(Buffer,dec(IncrementOut));
			}
		}
		strcat(Buffer,"}");
		Graph.GetOut()->NextOut(Buffer);
		strcat(NewName," ") ;
		strcat(NewName,Buffer) ;
		Graph.NodeName = NewName ;
	}
	if (OutLink) OutLink->GraphDisplay(Graph) ;
	else {
		if (!Graph.DoCpp()) Graph.GetOut()->NextOut("NULL pointer!");
		Graph.GetOut()->NewLine() ;
	}
	Graph.NodeName = ParentNode ;
}


DfNodeInLink::DfNodeInLink():
	InitStreamStructure(0)
{
	Init();
}

DfNodeInLink::~DfNodeInLink()
{
	// TestAlloc("DfNodeInLink::~DfNodeInLink");
	Clear();
	delete InitStreamStructure ;
	InitStreamStructure = 0 ;
	// TestAlloc("DfNodeInLink::~DfNodeInLink exit");
}

void DfNodeInLink::disconnect()
{
	// TestAlloc("DfNodeInLink::disconnect");
	// delete InLink ; cannot delete this because it is refrenced multiple places
	InLink = 0 ;
	// TestAlloc("DfNodeInLink::disconnect exit");
}

void DfNodeInLink::remove_this_link(DfNode* driven, int channel)
{
	if (InLink) {
		DfNodeLink * tmp = InLink ;
		InLink = 0 ;
		tmp->remove_this_output_link(driven,channel);
		BufferChannelIndex = 0 ;
	}
}

void DfNodeInLink::Clear()
{
	// TestAlloc("DfNodeInLink::Clear");
	delete TheStreamStructure ;
	delete TargetParameters ;
	Init();
	// SetLink(0,0);
	// TestAlloc("DfNodeInLink::Clear exit");
}

DfNodeOutLink * DfNodeInLink::GetDriverOutputChannel()
{
	if (State.IsError()) return 0;
	if (!InLink) {
		State.Error("links not set properly");
		return 0;
	}
	return InLink->GetDriverOutputChannel(
		InLink->GetInputLink()->GetChannel());
}


int32 DfNodeInLink::GetElementSize() const
{
	return TheStreamStructure->GetElementSize() ;
}

int32 DfNodeInLink::GetChunkSize() const
{
	return TheStreamStructure->GetChunkSize() ;
}

void DfNodeInLink::GraphDisplay(GraphInfo& Graph)
{
	int Elt = GetElementSize() != 1;
	int Inc = IncrementIn != 1 ;
	int Tail = Inc || Overlap /* || Delay */ ;
	if (Graph.DoFull()) if (Elt || Tail || Delay) {
		char Buffer[128];
		strcpy(Buffer,"{");
		if (Elt) strcat(Buffer,dec(GetElementSize()));
		if (Tail) {
			if (Elt) strcat(Buffer,"*(");
			strcat(Buffer,"k");
			if (Inc) {
				strcat(Buffer,"*");
				strcat(Buffer,dec(IncrementIn));
			}
			if (Overlap) {
				strcat(Buffer,"+");
				strcat(Buffer,dec(Overlap));
			}

			if (Delay) {
				strcat(Buffer,"-");
				strcat(Buffer,dec(Delay));
			}
			if (Elt) strcat(Buffer,")");
		}
		strcat(Buffer,"}");
		Graph.GetOut()->NextOut(Buffer);
	}
}


void DfNodeOutLink::disconnect()
{
	// TestAlloc("DfNodeOutLink::disconnect");
	delete OutLink ;
	OutLink = 0 ;
	// TestAlloc("DfNodeOutLink::disconnect exit");
}

void DfNodeOutLink::remove_this_link()
{
	if (OutLink) {
		DfNodeLink * tmp = OutLink ;
		OutLink = 0 ;
		tmp->remove_this_input_link();
	}
}

DfNode * DfNodeOutLink::FindNode(const DfNode * node)
{
	if(!OutLink) return 0;
	return OutLink->FindNode(node) ;
}

DfNode * DfNodeOutLink::FindNode(const char * Name)
{
	if(!OutLink) return 0;
	return OutLink->FindNode(Name) ;
}
		

void DfNodeInLink::InitArithType(ArithType::ArithTypes type)
{
	if (!TheStreamStructure || !InitStreamStructure)
		DbgError("DfNodeInLink::InitArithType", "no stream");
	TheStreamStructure->InitArithType(type);
	InitStreamStructure->InitArithType(type);
}

void DfNodeOutLink::InitArithType(ArithType::ArithTypes type)
{
	if (!TheStreamStructure || !InitStreamStructure)
		DbgError("DfNodeOutLink::InitArithType",
		"no stream");
	TheStreamStructure->InitArithType(type);
	InitStreamStructure->InitArithType(type);
}

int DfNodeOutLink::CheckComplete(const char * Name)
{
	int Complete = 1 ;
	if (!TheStreamStructure) DbgError("DfNodeOutLink::CheckComplete",
		"no stream");
	if (TheStreamStructure->CheckInitialized()) {
		Complete = 0 ;
		*Output + OutputCppHelp << "Initializaiton error in node `" <<
			Name << "'.\n" ;
	}
	if (!IncrementOut ) *Output + OutputCppHelp <<
		"output increment not set in node " << Name << ".\n" ;
	Complete = Complete && IncrementOut ;
	if (OutLink) return Complete && GetOutLink()->CheckComplete(Name) ;
	*Output + OutputCppHelp << "Output channel with no connection in node `" <<
		Name  << "'.\n" ;
	return 0 ;
}


int DfNodeInLink::CheckComplete(const char * Name)
{
	int Complete = 1 ;
	if (TheStreamStructure->CheckInitialized()) {
		Complete = 0 ;
		*Output + OutputCppHelp << "Initializaiton error in node `" <<
			Name << "'.\n" ;
	}
	if (!IncrementIn ) *Output + OutputCppHelp <<
		"Input increment not set in node " <<
		Name << ".\n" ;
	if (!InLink) {
		*Output + OutputCppHelp << "No input link in node `"
			<< Name << ".\n" ;
		return 0 ;
	}
	return Complete && IncrementIn ;
}

void DfNodeOutLink::Display()
{
/*
 *	LogOut << "DfNodeOutLink::IncrementOut = " << IncrementOut
 *		<< ", ElementSize = " << GetElementSize() << "\n" ;
 */

	if (OutLink) OutLink->Display() ;
}

int32 DfNodeInLink::GetDataPerExe() const
{
	int32 Return = IncrementIn*GetChunkSize() ;
/*
 *	LogOut << "IncrementIn = " << IncrementIn << ", ChunkSize " <<
 *		GetChunkSize() << "\n" ;
 *	LogOut << "DfNodeInLink::GetDataPerExe returning " << Return << "\n" ;
 */
	return Return ;
}

int32 DfNodeOutLink::GetDataPerExe() const
{
/*
 *	LogOut << "DfNodeOutLink::GetDataPerExe,IncrementOut = " << IncrementOut <<
 *		", GetChunkSize = " << GetChunkSize() << "\n" ;
 */
	return IncrementOut*GetChunkSize() ;
}

int32 DfNodeInLink::GetCanExecute(int not_first_time)
{
	if (State.IsError()) return 0;
	int32 DataPerExe = GetDataPerExe();
/*
 *	LogOut << "IncrementIn = " << IncrementIn << ", ChunkSize = "
 *		<< GetChunkSize() << "\n" ;
 */
	if (!InLink) {
		State.Error("null input link in node");
		return 0;
	}
	int32 Space = InLink->GetAvailableData(BufferChannelIndex);
	// LogOut << "DfNodeInLink::GetCanExecute Space = " << Space << "\n" ;
	if (State.IsError()) return 0;
	int32 overlap_needed = 0 ;
	if (!not_first_time) overlap_needed = Overlap * GetChunkSize();
	int32 CanExe = (Space - overlap_needed) / DataPerExe ;
	// int32 CanExe = Space/DataPerExe + IncrementIn - Overlap ;

/*
 *	LogOut << "In - GetCanExe - Space = " << Space << ", ov_need = "
 * 		<< overlap_needed << "\n" ;
 *	LogOut << "CanExe = " << CanExe << ", DataPerExe = " << DataPerExe 
 *		<< "\n" ;
 *	LogOut << "IncrementIn = " << IncrementIn << ", ElementSize = " <<
 *		GetElementSize() << "\n" ;
 *	LogOut << "Delay = " << Delay << ", Overlap = " << Overlap << "\n" ;
 */


	if (CanExe < 0) return 0;
	return CanExe ;
}

int32 DfNodeOutLink::GetCanExecute()
{
	if (State.IsError()) return 0;
	int32 DataPerExe = GetDataPerExe();
	// int32 DataPerExe = IncrementOut*GetChunkSize() ;
	if (!OutLink) {
		State.Error("null output link");
		return 0;
	}
	int32 Space = OutLink->GetSpace() ;
	// LogOut << "DfNodeOutLink::GetCanExecute, Space = " << Space << "\n" ;
	if (State.IsError()) return 0;

/*
 *	LogOut << "IncrementOut = " << IncrementOut << ", EltSz = "
 *		<< GetElementSize() << ", Space = " << Space << "\n" ;
 *	LogOut << "Out - GetCanExecute - DataPerExe = " <<
 *		DataPerExe << ", Space = " << Space << "\n" ;
 */

	return Space/DataPerExe ;
}

int32 DfNode::GetIncrementIn(int Index) const
{
	if (State.IsError()) return 0;
	DfNodeInLink * InLk = GetInLink(Index);
	if (!InLk) {
		State.Error("null input link in node `", GetName(), "'");
		return 0;
	}
	return InLk->IncrementIn ;
}

int32 DfNode::GetIncrementOut(int Index) const
{
	if (State.IsError()) return 0;
	DfNodeOutLink * OutLk = GetOutLink(Index);
	if (!OutLk) return 1 ;
	return OutLk->IncrementOut ;
}


void DfNode::DeassignBufferDescriptor(BufferDescript *des)
{
	if (IsTraverseFlag(GenericTraverseBit)) return ;
    SetTraverseFlag(GenericTraverseBit);
	for (int i = 0 ; i < Out ; i++) OutLinks[i].DeassignBufferDescriptor(des);
	ClearTraverseFlag(GenericTraverseBit);
}

int DfNode::AssignBuffers(BufferDescript *Des)
{
	if (IsTraverseFlag(GenericTraverseBit)) return 1 ;
	if (delete_link_state == delete_after_buffers_assigned)
		delete_link_state = do_delete_if_unlinked ;
    SetTraverseFlag(GenericTraverseBit);

	// LogOut << "DfNode::AssignBuffers for `" << GetName() << "'\n" ;
	int AssignOK = 1;
	for (int i = 0 ; i < Out ; i++) {
		// LogOut << "Assigning for link " << i << "\n" ;
		AssignOK= AssignOK && OutLinks[i].GetOutLink()->
			AssignBuffers(Des) ;
		// LogOut << "Did asign for link " << i << "\n" ;
		if (State.IsError()) AssignOK = 0 ;
	}
	// LogOut << "Returning " << AssignOK << "\n" ;
	ClearTraverseFlag(GenericTraverseBit);
	return AssignOK ;
}

int DfNode::ClearBuffers()
{
/*
 *	LogOut << "DfNode::ClearBuffers, FreeNodeBit = " <<
 *		IsTraverseFlag(FreeNodeBit) << "\n" ;
 */
	ClearTimingVisitChannel();
	if (IsTraverseFlag(FreeNodeBit)) return 1;
	SetTraverseFlag(FreeNodeBit);
	clear_buffers();
	// History =0 ;
	int DeleteOK = 1;
	// LogOut << "DfNode::ClearBuffers: `" << GetName() << "'\n" ;
	for (int i = 0 ; i < Out ; i++) {
		// LogOut << "Out line is " << i << "\n" ;
		DeleteOK= DeleteOK && OutLinks[i].ClearBuffers();
		// DeleteOK= DeleteOK && OutLinks[i].GetOutLink()->ClearBuffers() ;
		if (State.IsError()){
			DeleteOK = 0 ;
			break ;
		}

	}
	ClearTraverseFlag(FreeNodeBit);
	return DeleteOK ;
}

int DfNode::DeleteAllLinks(class DfNodeList * List)
{
	// LogOut << "DfNode::DeleteAllLinks for `" << GetName() << "'.\n" ;
	if (UseInLink == -2)  return 1 ; // this avoids infinite loop
	if (List) List->Append(this);
	UseInLink = -2 ;
	int DeleteOK = 1;
	char Buf[200];
	// LogOut << "DfNode::DeleteAllLinks " << GetName() << "\n" ;
	for (int i = 0; i < In ; i++) if (InLinks[i].InLink) {
		// LogOut << "Deleting in = " << i << "\n" ;
		if (!InLinks[i].DeleteAllLinks(GetName(),List)) {
			strcpy(Buf,"input link ");
			strcat(Buf,dec(i));
			State.Error(Buf," in node `",GetName(),
				"' cannot delete links");
			DeleteOK = 0 ;
		} else InLinks[i].Clear();
	} 
	for (i = 0; i < Out ; i++) if (OutLinks[i].OutLink) {
		// LogOut << "Deleting out = " << i << "\n" ;
		strcpy(Buf,"output link ");
		strcat(Buf,dec(i));
		strcat(Buf," in node `");
		int LocalDeleteOK = 0 ;
/*
 *		DfNodeLink * InLink = OutLinks[i].GetOutLink() ;
 *		DfNodeIn * InLk = InLink->GetInputLink();
 *		delete InLk;
 *		InLk = 0 ;
 *		delete InLink ;
 *		InLink = 0;
 */
		LocalDeleteOK = OutLinks[i].DeleteAllLinks(GetName(),List);
		OutLinks[i].Clear();
		if (!LocalDeleteOK) {
			State.Error("there is a problem deleting ", Buf,
				GetName(), "'") ;
			DeleteOK = 0;
		}
	} 
	UseInLink = -1;
	SetActiveNet(0);
	// LogOut << "Active net cleared for `" << GetName() << "'\n" ;
	return DeleteOK ;
}

void DfNodeOutLink::Clear()
{
	// TestAlloc("DfNodeOutLink::Clear");
	Timing.Clear();
	delete TheStreamStructure ;
	delete TargetParameters;
	Init();
	// TestAlloc("DfNodeOutLink::Clear exit");
}

void DfNodeOutLink::DeassignBufferDescriptor(BufferDescript * des)
{
	GetOutLink()->DeassignBufferDescriptor(des);
}

const char * DfNode::GetFreeNodeIn()
{
	for (int i = 1 ; i < In ; i++)
		if (!InLinks[i].GetInLink()) return GetName();
	return 0 ;
/*
 *	if (IsTraverseFlag(FreeNodeBit)) return 0;
 *	SetTraverseFlag(FreeNodeBit);
 *	for (int i = 0 ; i < Out ; i++)
 *	ClearTraverseFlag(FreeNodeBit);
 */
}

const char * DfNode::GetFreeNodeOut()
{
	if (Out) if (!OutLinks[0].GetOutLink()) return GetName();
/*
 *	if (IsTraverseFlag(FreeNodeBit)) return 0;
 *	SetTraverseFlag(FreeNodeBit);
 *	ClearTraverseFlag(FreeNodeBit);
 */
	return 0 ;
}

void DfNode::SetSampleRate(double Rate, int16 Channel)
{
	ProcessNet * TheNet = GetActiveNet();
	if (!TheNet) {
		State.Error("cannot set sample rate for `",GetName(),
			"', it is not in a network");
		return ;
	}
			
	TheNet->CreateController();
	if (State.IsError()) return ;
	if (!TheNet->CheckComplete()) {
		State.Error("cannot set sample rate for `", GetName(),
			"', the network its network is incomplete");
		return ;
	}

/*
 *	LogOut<<"DfNode::SetSampleRate(" << Rate << ", " << Channel << ") for "
 *		<< GetName() << "\n" ;
 */
	if (!CkOut(Channel,"SetSampleRate")) return ;
	TimingDescription& timing = OutLinks[Channel].SetSampleRate(Rate);
/*
 *	LogOut << "`" << GetName() << "' GetTiming(0)->GetSampleRate() = " <<
 *		GetTiming(0)->GetSampleRate();
 *	LogOut << "Got timing\n" ; 
 */
	AdjustSampleRate(timing);
/*
 *	LogOut << "`" << GetName() <<  "' GetTiming(0)->GetSampleRate() = " <<
 *		GetTiming(0)->GetSampleRate() << "\n" ;
 *	LogOut << "Exit DfNode::SetSampleRate for " << GetName() << "\n" ;
 */
}

void DfNode::AdjustSampleRate(TimingDescription& timing)
{
	// LogOut << "DfNode::AdjustSampleRate for " << GetName() << "\n" ;
	if (TimingVisitChannel > -1) return ;
	for (int i = 0 ; i < Out ; i++) {
		SetTimingVisitChannel(i);
		OutLinks[i].AdjustSampleRate(timing);
	}
	for (i = 0 ; i < In ; i++) {
/*
 *		LogOut << "SampleRate for node `" << GetName() << "'(" <<
 *			i << ") is " << InLinks[i].GetTiming()->GetSampleRate()
 *			<< ".\n" ;
 */
		SetTimingVisitChannel(i);
		InLinks[i].AdjustSampleRate(timing) ;
/*
 *		LogOut << "SampleRate for node `" << GetName() << "'(" <<
 *			i << ") is " << InLinks[i].GetTiming()->GetSampleRate()
 *			<< ".\n" ;
 */
	}
	ClearTimingVisitChannel();
	NewSampleRate();
		
}

void DfNode::NewSampleRate()
{
/*
 * 	LogOut << "DfNode::NewSampleRate called for `" << GetName()
 *		<< "'\n" ;
 */
	return ;
}

int DfNode::ExactCountExecute() const
{
	return ExecuteType != NodeExecuteSpaceBound ;
}

int DfNode::CheckBufferSpace() const
{
	return ExecuteType == NodeExecuteFixedIgnoreSpace ;
}

void DfNodeLink::AdjustInputSampleRate(TimingDescription& timing)
{
	if (GetInputNode()) GetInputNode()->AdjustSampleRate(timing) ;
}

void DfNodeLink::AdjustOutputSampleRate(TimingDescription& timing)
{
	if (!OutputArray) return ;
	for (int i = 0 ; i < OutSize ; i++) if (GetOutputNode(i))
		GetOutputNode(i)->AdjustSampleRate(timing);
}

void DfNodeInLink::AdjustSampleRate(TimingDescription& timing)
{
	if (GetInLink()) GetInLink()->AdjustInputSampleRate(timing);
}

void DfNodeOutLink::AdjustSampleRate(TimingDescription& timing)
{
	if (Timing.TheTimingType == TimingTypeRandom) return ;
	Timing.AdjustSampleRate(timing);
	if (GetOutLink()) GetOutLink()->AdjustOutputSampleRate(timing);
}

TimingDescription& DfNodeOutLink::SetSampleRate(double Rate)
{
	Timing.SampleRate = Rate ;
	// LogOut << "Set Timing.SampleRate to " << Rate << "\n" ;
	return Timing ;
}

const char * DfNodeOutLink::GetFreeNodeIn()
{
	if (!OutLink) return 0;
	return OutLink->GetFreeNodeIn();
}


const char * DfNodeOutLink::GetFreeNodeOut()
{
	if (!OutLink) return 0;
	return OutLink->GetFreeNodeOut();
}

int DfNodeOutLink::GetDriverChannel()
{
	if (!OutLink) return -1 ;
	return OutLink->GetInputNodeOutputChannel();
}

int32 DfNodeOutLink::GetChunkSize() const 
{
	return TheStreamStructure->GetChunkSize();
}

int32 DfNodeOutLink::GetElementSize() const
{
	return TheStreamStructure->GetElementSize();
}

void DfNodeInLink::Init()
{
	TheStreamStructure = 0 ;
	InLink = 0 ;
	BufferChannelIndex = 0 ;
	Overlap = 0 ;
	IncrementIn = 0 ;
	Delay = 0 ;
	TargetParameters = 0 ;
}

void DfNodeOutLink::Init()
{
	TheStreamStructure = 0 ;
	OutLink = 0 ;
	IncrementOut = 0 ;
	TargetParameters = 0 ;
	timing_type = TimingTypeLinear ;
}

int32 DfNodeInLink::GetBlockSize() const
{
	int32 size = TheStreamStructure->GetBlockSize();
	if (!size) {
		TheLog << "Warning DfNodeInLink::GetBlockSize null block size\n" ;
		size = 1 ;
	}
	return size ;
}

int32 DfNodeOutLink::GetBlockSize() const
{
	return TheStreamStructure->GetBlockSize();
}

int DfNodeOutLink::AnyConsumerOverlap() const
{
	return  OutLink->AnyConsumerOverlap();
}

void DfNodeOutLink::EmitTargetWriterParameters(OutTokens& Out)
{
	// LogOut << "DfNodeOutLink::EmitTargetWriterParameters\n" ;
	if (!TargetParameters) return ;
	// LogOut<<"TargetParameters = " << (void *) TargetParameters << "\n" ;
	TargetParameters->EmitParameters(Out);
	delete TargetParameters ;
	TargetParameters = 0 ;
}

void DfNodeInLink::EmitTargetReaderParameters(OutTokens& Out)
{
	if (!TargetParameters) return ;
	TargetParameters->EmitParameters(Out);
	delete TargetParameters ;
	TargetParameters = 0 ;
}

int DfNodeOutLink::IsTargetDefined() const
{
	return GetOutLink()->IsTargetDefined();
}

int DfNodeOutLink::IsTraverseComplete() const
{
	// LogOut << "DfNodeOutLink::IsTraverseComplete()\n" ;
	return GetOutLink()->IsTraverseComplete();
}

int DfNodeInLink::IsTraverseComplete() const
{
	// LogOut << "DfNodeInLink::IsTraverseComplete()\n" ;
	DfNodeLink * In = GetInLink();
	if (!In) DbgError("DfNodeInLink::IsTraverseComplete","null link");
	return In->GetInputNode()->IsTraverseComplete() ;
}

TargetBufferParameters * DfNodeInLink::GetTargetBuffer() const
{
	return GetInLink()->GetTargetBuffer();
}

TargetAdjustState DfNodeInLink::AdjustTargetBuffer(int32 NewSize)
{
	return GetInLink()->AdjustTargetBuffer(NewSize);
}

void DfNodeInLink::ClearTargetParameters()
{
	// LogOut << "DfNodeInLink::ClearTargetParameters()\n" ;
	GetInLink()->ClearTargetParameters();
	// LogOut << "DfNodeInLink::ClearTargetParameters() exit\n" ;
}

TraverseResult DfNodeOutLink::CheckTargetBufferSize(TraverseObject& obj)
{
	// LogOut << "DfNodeOutLink::CheckTargetBufferSize\n" ;
	TraverseResult Ret = GetOutLink()->CheckTargetBufferSize(obj);
	TargetParameters = new TargetWriterParameters(*this,
		GetOutLink()->GetTargetBuffer()->GetSize()) ;
	return TraverseOK ;
}

TraverseResult DfNodeInLink::CheckTargetBufferSize(TraverseObject& obj)
{
	TraverseResult Ret = GetInLink()->CheckTargetBufferSize(obj);
	delete TargetParameters ;
/*
 *	LogOut << "DfNodeInLink::CheckTargetBufferSize size = " <<
 *		GetTargetBuffer()->GetSize() << "\n" ;
 *	
 *	LogOut << "Creating TargetReaderParameters\n" ;
 */
	TargetParameters = new TargetReaderParameters(*this,
		GetTargetBuffer()->GetSize()) ;
	return Ret ;
}

ErrCode DfNodeOutLink::Reset()
{
	if (GetOutLink()) return GetOutLink()->Reset();
	else return OK ;
}

ErrCode DfNodeInLink::Reset()
{
	return OK ;
}

void DfNodeInLink::decrement_buffer_channel(int new_value)
{
	if (new_value != --BufferChannelIndex) 
		DbgError("DfNodeInLink::decrement_buffer_channel","bad");
}

int32 DfNodeInLink::GetMinBufferSize() const 
{
	return GetOverlap() + GetIncrementIn() * GetChunkSize() ;
}

void DfNodeInLink::new_buffer_channel(int buffer_channel)
{
	BufferChannelIndex = buffer_channel;
}

void DfNodeOutLink::UnlinkReset()
{
	// TestAlloc("DfNodeOutLink::UnlinkReset") ;
	delete TheStreamStructure ;
	TheStreamStructure = new StreamStr(*InitStreamStructure);
	// TestAlloc("DfNodeOutLink::UnlinkReset middle") ;
	UnlinkChannel();
	// TestAlloc("DfNodeOutLink::UnlinkReset exit") ;
}

void DfNodeOutLink::UnlinkChannel()
{
	// TestAlloc("DfNodeOutLink::UnlinkChannel") ;
	if (!OutLink) return ;
	delete TargetParameters ;
	TargetParameters = 0 ;
	OutLink = 0 ;
	Timing.Clear();
	// TestAlloc("DfNodeOutLink::UnlinkChannel exit") ;
}

void DfNodeInLink::UnlinkReset()
{
	// TestAlloc("DfNodeInLink::UnlinkReset") ;
	delete TheStreamStructure ;
    TheStreamStructure = new StreamStr(*InitStreamStructure);
	UnlinkChannel();
	// TestAlloc("DfNodeInLink::UnlinkReset exit") ;
}

void DfNodeInLink::UnlinkChannel()
{
	// TestAlloc("DfNodeInLink::UnlinkChannel" );
	if (!InLink) return ;
	delete TargetParameters ;
    TargetParameters = 0 ;
    InLink = 0 ;
    BufferChannelIndex = 0 ;
	// TestAlloc("DfNodeInLink::UnlinkChannel exit" );
}

void DfNodeInLink::UnlinkDriven()
{
	// TestAlloc("DfNodeInLink::UnlinkDriven") ;
	if (!InLink) return ;
	DfNodeLink * link = InLink ;
	InLink = 0 ;
	link->UnlinkDriven(BufferChannelIndex);
	// TestAlloc("DfNodeInLink::UnlinkDriven a");
	delete TargetParameters ;
	// TestAlloc("DfNodeInLink::UnlinkDriven b");
	TargetParameters = 0 ;
	BufferChannelIndex = 0 ;
	delete TheStreamStructure ;
	// TestAlloc("DfNodeInLink::UnlinkDriven c");
	TheStreamStructure = new StreamStr(*InitStreamStructure);
	// TestAlloc("DfNodeInLink::UnlinkDriven exit");
}

void DfNodeOutLink::Unlink()
{
	 // TestAlloc("DfNodeOutLink::Unlink");
	if (!OutLink) return ;
	DfNodeLink * out_link = OutLink ;
	OutLink = 0 ; 
	out_link->Unlink();
	delete out_link ;
	delete TargetParameters ;
	TargetParameters =  0 ;
	delete TheStreamStructure ;
	TheStreamStructure = new StreamStr(*InitStreamStructure);
	// TestAlloc("DfNodeOutLink::Unlink exit") ;
}

int32 DfNodeOutLink::GetMinBufferSize() const 
{
	return GetIncrementOut() * GetChunkSize();
}

int DfNodeOutLink::DoInitAfterLinked()
{
	if (!OutLink) return 0 ;
	return OutLink->DoInitAfterLinked();
}

void DfNodeOutLink::set_increment_out(int32 val)
{
	IncrementOut = val ;
}

void DfNodeInLink::set_increment_in(int32 val)
{
	IncrementIn = val ;
}

int DfNodeLink::DoInitAfterLinked()
{
	for (int i = 0 ; i < OutSize; i++) {
		DfNodeOut * out = OutputArray[i] ;
		if (!out) return 0 ;
		DfNode * node = out->GetNode();
		if (!node) return 0 ;
		if (!node->DoInitAfterLinked()) return 0 ;
	}
	return 1 ;
}
