/*  execseq.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <math.h>
#include <stdlib.h>
#include <stream.h>
#include "cgidbg.h"
#include "netlnk.h"
#include "strmstr.h"
#include "yacintfc.h"
#include "tarparm.h"
#include "travparm.h"
#include "network.h"
#include "cmpseq.h"
#include "buffer.h"
#include "adjust.h"
#include "gcd.h"
#include "execseq.h"
#include "tarnodpar.h"
#include "bufstat.h"

int VarMaxSeqLength = 200 ;


TraverseObject * ExecutionSequence::Obj  = 0 ;
DfNodeInLink * ExecutionSequence::ConsumerInLink   = 0 ;
DfNodeOutLink * ExecutionSequence::DriverOutLink   = 0 ;
DfNodeOut * ExecutionSequence::OneConsumer  = 0 ;
TargetBufferParameters * ExecutionSequence::TargetBuffer  = 0 ;
TargetReaderParameters * ExecutionSequence::TargetReader  = 0 ;
ExecutionSequence * ExecutionSequence::ConsumerSequence  = 0 ;
int32 ExecutionSequence::DataConsumed  = 0 ;
int32 ExecutionSequence::DataAvailable  = 0 ;
int32 ExecutionSequence::DataNeeded  = 0 ;
int32 ExecutionSequence::ExcessData  = 0 ;
int32 ExecutionSequence::LeftOver  = 0 ;
int32 ExecutionSequence::OrigLeftOver  = 0 ;
int32 ExecutionSequence::OverlapWords  = 0 ;
int32 ExecutionSequence::OutBufSize  = 0 ;
int32 ExecutionSequence::InputPerExecution  = 0 ;
int32 ExecutionSequence::OutputPerExecution  = 0 ;
TargetAdjustState ExecutionSequence::StateOut  = TargetAdjustOK ;
BufferStatus * ExecutionSequence::BufStat  = 0 ;
int ExecutionSequence::ProviderCountNeeded  = 0 ;
int ExecutionSequence::ConsumerCountNeeded  = 0 ;
int32 ExecutionSequence::NeededBufSize  = 0 ;
int32 ExecutionSequence::MinBufSize  = 0 ;
int32 ExecutionSequence::SeqIndex  = 0 ;
int32 ExecutionSequence::SeqEnd = 0 ;

TargetAdjustState ExecutionSequence::SetSequenceLengthMultiplier(
	int32 NewMultiple)
{
	int32 TheNewMultiple = LeastCommonMultiple(ExecutionSequenceMultiple,
		NewMultiple);
	if (!TheNewMultiple) {
		int chan = ConsumerInLink ?
			ConsumerInLink->GetNodeInputChannel() : -1 ;
		BufStat->SetReason(new ReasonForFailure (
		"the execution sequence is too long (common multiple problem)",
			GetNode().GetName(),
			-1, chan, ReasonForFailure::Input));
		return TargetAdjustFail ;
	}
	if (ExecutionSequenceMultiple == TheNewMultiple) return TargetAdjustOK ;
	ExecutionSequenceMultiple = TheNewMultiple ;
	return TargetAdjustChange ;
}

DfNode& ExecutionSequence::GetNode() const
{
	return GetParameters()->GetNode();
}

int ExecutionSequence::Size() const 
{
	int Count=0 ;
	if (Sequence) 
		for (int32 * Pt = Sequence;*Pt != -1; Pt++) Count++ ;
	return Count ;
}

int32 ExecutionSequence::Count(int index) const
{
	if (index >= Size()) {
		TheLog << "index = " << index << ", Current = " <<
			CurrentSize << "\n" ;
		DbgError("ExecutionSequence::Count", "bad index");
	}
	return Sequence[index] ;
}

int32 ExecutionSequence::CountPast(int index) const
{
	if (!Sequence) return -3 ;
	if (index > Size()) return  -2 ;
	return Sequence[index] ;
}

int32 ExecutionSequence::CountZero(int index) const
{
	if (index >= Size()) return 0 ;
	return Sequence[index] ;
}

ExecutionSequence::ExecutionSequence(TargetNodeParameters& Param,
	int& Max_Length):
	Sequence(0),
	CurrentSize(0),
	NodeParam(&Param),
	MaxLength(Max_Length),
	PreviousExecutionSequenceMultiple(1),
	ExecutionSequenceMultiple(1),
	FlushCount(0),
	FlushCountSet(0),
	InitCheckDone(0)
{
	// LogOut << "ExecutionSequence ctor\n" ;
	// LogOut << "	for `" << Param.GetNode().GetName() << "\n" ;
}

ExecutionSequence::ExecutionSequence(ExecutionSequence& ToCopy):
	CurrentSize(0),
	Sequence(0),
	NodeParam(ToCopy.GetParameters()),
	MaxLength(ToCopy.GetMaxLengthRef()),
	PreviousExecutionSequenceMultiple(
		ToCopy.GetPreviousExecutionSequenceMultiple()),
	ExecutionSequenceMultiple(ToCopy.GetExecutionSequenceMultiple()),
	FlushCount(ToCopy.GetFlushCount()),
	FlushCountSet(ToCopy.GetFlushCountSet()),
	InitCheckDone(ToCopy.GetInitCheckDone())
{
	SetSequence(ToCopy.GetSize());
	for (int i = 0 ; i < CurrentSize; i++) SetValue(ToCopy.Count(i),i);
}

void ExecutionSequence::Restore(ExecutionSequence& RestoreFrom)
{
	MaxLength = RestoreFrom.GetMaxLengthRef();
	NodeParam = RestoreFrom.GetParameters() ;
	PreviousExecutionSequenceMultiple =
		RestoreFrom.GetPreviousExecutionSequenceMultiple();
	ExecutionSequenceMultiple = RestoreFrom.GetExecutionSequenceMultiple();
	FlushCount = RestoreFrom.GetFlushCount();
	FlushCountSet = RestoreFrom.GetFlushCountSet();
	// The above three are only used for the execution sequence
	int Temp = RestoreFrom.Size();
	// LogOut << "Temp = " << Temp << "\n" ;
	delete Sequence ;
	Sequence = 0 ;
	CurrentSize = 0 ;
	SetSequence(Temp);
	for (int i = 0 ; i < CurrentSize; i++) SetValue(RestoreFrom.Count(i),i);
	// LogOut << "Exit Restore\n" ;
}

void ExecutionSequence::InitLinks()
{
	DriverOutLink = OneConsumer->GetFeederLink();
	ConsumerInLink = OneConsumer->GetConsumerLink();
	if (!ConsumerInLink || !DriverOutLink)
		DbgError("ExecutionSequence::InitLinks","null link(s)"); 
	InputPerExecution = ConsumerInLink->GetChunkSize() *
		ConsumerInLink->GetIncrementIn() ;
	OutputPerExecution = DriverOutLink->GetChunkSize() *
		DriverOutLink->GetIncrementOut() ;
	OverlapWords = ConsumerInLink->GetOverlap() *
		ConsumerInLink->GetChunkSize();
	TargetBuffer = ConsumerInLink->GetTargetBuffer();
	TargetReader = ConsumerInLink->GetTargetReaderParameters();
	if (!TargetBuffer) {
		ConsumerInLink->AdjustTargetBuffer(1);
		TargetBuffer = ConsumerInLink->GetTargetBuffer();
	}
	OutBufSize = TargetBuffer->GetSize();
	if (!TargetBuffer) DbgError("ExecutionSequence::InitLinks",
		"no target buffer");
	if (!TargetReader) {
		ConsumerInLink->SetTargetReaderParameters(
			new TargetReaderParameters(*ConsumerInLink,
			TargetBuffer->GetSize() ));
		TargetReader = ConsumerInLink->GetTargetReaderParameters();
	}
	TargetWriterParameters * TargetWriter =
		DriverOutLink->GetTargetWriterParameters();
	if (!TargetWriter) DriverOutLink->SetTargetWriterParameters(
			new TargetWriterParameters(*DriverOutLink,
			TargetBuffer->GetSize() ));
}

TargetAdjustState ExecutionSequence::SetSequence(int * NewSequence)
{
	if (Sequence) DbgError("ExecutionSequence::SetSequence",
		"already set");
	TargetAdjustState Return = TargetAdjustChange ;
	if (Sequence) for (int i = 0 ; i < CurrentSize + 1;i++) {
		if (NewSequence[i] == -1) {
			if (Sequence[i]== -1) Return = TargetAdjustOK ;
			break ;
		}
		if (Sequence[i] != NewSequence[i]) break ;
	}
	Sequence = NewSequence ;
	CurrentSize = Size();
	if (CurrentSize > MaxLength) MaxLength = CurrentSize ;
	return Return ;
}

TargetAdjustState ExecutionSequence::SetSequence(int size)
{
	if (size >= VarMaxSeqLength) {
		// LogOut << "SetSequence - too big = " << size << "\n" ;
		int chan = ConsumerInLink ?
			ConsumerInLink->GetNodeInputChannel() : -1 ;
		BufStat->SetReason(new ReasonForFailure (
			"the execution sequence is too long",
			GetNode().GetName(),
			-1, chan, ReasonForFailure::Input));
		return TargetAdjustFail ;
	}
/*
 *	LogOut << "ExecutionSequence::SetSequence(" << size
 *		<< ", CurrentSize = " << CurrentSize << "\n" ;
 */
	if (!Sequence) CurrentSize = 0 ;
	TargetAdjustState Return = TargetAdjustOK ;
	if (CurrentSize < size) {
		CurrentSize = size ;
		if (CurrentSize > MaxLength) MaxLength = CurrentSize ;
		Return = TargetAdjustChange ;
	}
	int TempSize ;
	if (!Sequence) {
		Sequence = new int32[CurrentSize+1] ;
		for (int i = 0 ; i <= CurrentSize;i++)
			Sequence[i] = -1 ;
	} else if ((TempSize = Size()) < CurrentSize) {
		int32 * Temp = new int32[CurrentSize+1] ;
		int i ;
		for (i = 0 ; i < TempSize;i++) Temp[i] = Sequence[i];
		for (i = TempSize ; i <= CurrentSize;i++) Temp[i] = -1 ;
		delete Sequence ;
		Sequence = Temp ;
		Return = TargetAdjustChange ;
	}
	for (int i = 0 ; i < size; i++) if (Sequence[i] == -1) {
		Return = TargetAdjustChange ;
		Sequence[i] = 0 ;
	}
	return Return ;
}

TargetAdjustState ExecutionSequence::ReconcileInit(DfNodeOut * one_consumer,
	TraverseObject& obj)
{
	if (State.IsError()) return TargetAdjustFail ;
	TargetAdjustState Return = TargetAdjustOK ;
/*
 *	LogOut << "ExecutionSequence::ReconcileInit for " <<
 *		GetNode().GetName() << "\n" ;
 */
	OneConsumer = one_consumer ;
	Obj= &obj ;
	InitLinks();
	ConsumerSequence = &(OneConsumer->GetNode()->GetTargetParameters()
		->GetInit());
	if (!ConsumerSequence) DbgError("ExecutionSequence::ReconcileInit",
		"consumer sequence void");
	int32 SampleDelay = ConsumerInLink->GetDelay()*
		ConsumerInLink->GetChunkSize();
	Return = AdjustSequence(SampleDelay);

	// LogOut << "ExecutionSequence::ReconcileInit returning " << Return << "\n" ;
 
	return Return ;
}


inline ZeroEnd(int32 count) {return count < 0 ? 0:count;}


TargetAdjustState ExecutionSequence::ChannelInit(TraverseObject &,
	DfNodeInLink& InLink)
{
	// The base execution count is fixed by the max sample rate output.
	// We must create a buffer and set up the execution count to handle
	// this.

	TimingDescription& Timing = *(InLink.GetTiming());
	int32 MaxExecCount = BufStat->GetTotalInitExecCountHighestRateNode() ;
	
	double DoubCountRatio = BufStat->GetMaxSamplingRatio() /
		Timing.GetSamplingRatio() ;

/*
 *	LogOut << "ChannelInit for `" << GetNode().GetName() <<
 *		"', MaxExecCount = " << MaxExecCount << ", DCR = " <<
 *		DoubCountRatio << "\n" ;
 *
 *	LogOut << "MaxSR = " << BufStat->GetMaxSamplingRatio() <<
 *		", SR = " << Timing.GetSamplingRatio() << "\n" ;
 */ 
	int32 LocCount = (int32) (MaxExecCount / DoubCountRatio)  ;
	if (MaxExecCount < 1) {
		ReasonForFailure * the_problem = new ReasonForFailure
       		("maximum buffer size is too small to initialize buffer",
           	GetNode().GetName(),-1, InLink.GetNodeInputChannel(),
           	ReasonForFailure::Input);
       	BufStat->SetReason(the_problem);
   	    return TargetAdjustFail ;
	}

	int32 IncrementIn = InLink.GetIncrementIn();
	int32 Delay = InLink.GetDelay();
	int32 Overlap = InLink.GetOverlap();
	int32 ChunkSize = InLink.GetChunkSize();

	TargetAdjustState LocStateOut = TargetAdjustOK ;
/*
 *	LogOut << "ExecutionSequence::ChannelInit for `" << GetNode().GetName()
 *		<< "', IncrementIn = " << IncrementIn << "\n" ;
 *	LogOut << "ChunkSize = " << ChunkSize << "\n" ;
 *	LogOut << "InChan = " << InLink.GetNodeInputChannel() <<
 *		", Overlap = " << Overlap << ", LocCount = " <<
 *		LocCount << "\n" ;
 */

	DataNeeded = LocCount * ChunkSize * IncrementIn
		+ Overlap * ChunkSize  ;
	// LogOut << "DataNeeded = " << DataNeeded << "\n" ;
	if (DataNeeded > BufStat->GetMaxSize()) {
		int FatalFlag = ChunkSize * (IncrementIn + Overlap) >
			BufStat->GetMaxSize(); 
		ReasonForFailure * the_problem = new ReasonForFailure
		("maximum buffer size is too small to initialize buffer",
			GetNode().GetName(),DataNeeded,
			InLink.GetNodeInputChannel(),
			ReasonForFailure::Input,FatalFlag);
		BufStat->SetReason(the_problem);
		return TargetAdjustFail ;
	}
	int32 MaxSize = DataNeeded ;
	switch (BufStat->GetGoal()) {
case BufferStatus::ExistingSize:
		if (BufStat->GetDesiredSize() > DataNeeded)
			MaxSize = BufStat->GetDesiredSize() ;
		break ;
case BufferStatus::FixedSequence:
		break ;
default:
		DbgError("ExecutionSequence::ChannelInit",
			"bad goal case");
	}
	BufStat->IncrementTotalSize(DataNeeded);
	ConsumerInLink = &InLink ;
	TargetAdjustState Change = EnlargeBuffer(DataNeeded,DataNeeded);
	// LogOut << "Set buffer size to at least " << DataNeeded << "\n" ;
	return Change ;
}

TargetAdjustState ExecutionSequence::InitInit(TraverseObject &obj)
{
		

	
	BufStat = obj.GetBufferStatus();
	if (GetSize()) return CheckFlushSize();
	return DoInitInit(obj) ;
}

TargetAdjustState ExecutionSequence::CheckFlushSize()
{
/*
 *	LogOut << "ExecutionSequence::CheckFlushSize for " <<
 *		GetNode().GetName()
 *		<< ", State is " << BufStat->StateToString() << "\n" ;
 *	LogOut << "FlushCount = " << GetFlushCount() << ", FlushCountSet = "
 *		<< GetFlushCountSet() << "\n" ;
 */
	if (BufStat->IsFlushState())
		if (GetFlushCount() && ! GetFlushCountSet()) {
		if (!CurrentSize) DbgError("ExecutionSequence::InitInit",
			"null size");
		SetValue(Count(CurrentSize-1) + GetFlushCount(),
			CurrentSize-1);
		FlushCountSet = 1 ;
/*
 *		LogOut << "Set flush count for " << GetNode().GetName()
 *			<< " Count[" << CurrentSize -1 << "] = " <<
 *			Count(CurrentSize-1) << " \n" ;
 */

	}
	return TargetAdjustOK ;
}

int32 ExecutionSequence::GetExecCount(DfNodeInLink& InLink)
{
	// LogOut << "ExecutionSequence::GetExecCount\n" ;
	int32 IncrementIn = InLink.GetIncrementIn();
	int32 Delay = InLink.GetDelay();
	int32 Overlap = InLink.GetOverlap();
	int32 DesiredSize = BufStat->GetDesiredSize();
	int32 MinBufInc = BufStat->GetMinBufInc() ;
	int32 ChunkSize = InLink.GetChunkSize();
	int32 LowerIncrement = ((Delay - Overlap) * ChunkSize +
		DesiredSize) / IncrementIn ;
/*
 *	LogOut << "Delay = " << Delay << ", Overlap = " << Overlap << 
 *		", IncrementIn = " << IncrementIn << "\n" ;
 */
	double DoubCountRatio = BufStat->GetMaxSamplingRatio() /
            InLink.GetTiming()->GetSamplingRatio() ;
	int32 MinBuf = (int32) (MinBufInc / DoubCountRatio) ;
	int32 MinIncrement = LeastCommonMultiple(ChunkSize*IncrementIn, MinBuf);

	int32 ExecCount = LowerIncrement ;
/*
 *	LogOut << "LowerIncrement = " << LowerIncrement << ", MinBufInc = " <<
 *		MinBufInc << ", MinBuf " << MinBuf << "\n" ;
 *	LogOut << "ExecutionSequence::GetExecCount for `" <<
 *		GetNode().GetName() << "', IncrementIn = " << IncrementIn
 *		<< ",  MinInc = " << MinIncrement << "\n" ;
 *	LogOut << "InChan = " << InLink.GetNodeInputChannel() <<
 *		", Overlap = " << Overlap << ", LowerIncrement = " <<
 *		LowerIncrement << "\n" ;
 *
 *	LogOut << "ChunkSize = " << ChunkSize << ", ExecCount " << ExecCount
 *		<< ", MinIncrement = " << MinIncrement << ", Overlap = " << Overlap
 *		<< "\n";
 */
	while ((DataNeeded = MinIncrement * (ExecCount + Overlap)) >
		BufStat->GetMaxSize()) {
/*
 *		LogOut << "DataNeeded = " << DataNeeded << ", ExecCount = " <<
 *			ExecCount << "\n" ;
 */
		if (ExecCount < 1) {
			ReasonForFailure * the_problem =
				new ReasonForFailure
	("maximum buffer size is too small to initialize buffer and execute",
				GetNode().GetName(),DataNeeded,
				InLink.GetNodeInputChannel(),
				ReasonForFailure::Input,1);
			BufStat->SetReason(the_problem);
			return 0 ;
		}
		ExecCount-- ;
	}
	// LogOut << "ExecCount = " << ExecCount << ", after decrement\n" ;
	while (ExecCount > 0 && (DataNeeded = MinIncrement * (ExecCount + Overlap))
		> BufStat->GetDesiredSize()) {
/*
 *	LogOut << "DataNeeded = " << DataNeeded << ", ExecCount = " << ExecCount
 *			<< "\n" ;
 */ 
		ExecCount-- ;
	}
	// LogOut << "ExecCount = " << ExecCount << ", after decrement2\n" ;
	switch (BufStat->GetSizeGoal()) {
case BufferStatus::DesiredSizeExact:
case BufferStatus::DesiredSizeExactRequired:
case BufferStatus::DesiredSizeUpperBound:
		if (!ExecCount) ExecCount++ ;
		break ;
case BufferStatus::DesiredSizeLowerBound:
		ExecCount++ ;
		break ;
default:
		DbgError("ExecutionSequence::GetExecCount",
			"bad size case");
	}
/*
 *	DataNeeded = MinIncrement * (ExecCount + Overlap) ;
 *	LogOut << "DataNeeded = " << DataNeeded << "\n" ;
 *	int32 Return = (DataNeeded - MinIncrement * Overlap) / IncrementIn ;
 *	LogOut << "Returning " << Return << "\n" ;
 *	return Return ;
 */
	return ExecCount ;
}

TargetAdjustState ExecutionSequence::CheckMaxExec(TraverseObject &)
{
	int32 HighestCount = BufStat->GetTotalInitExecCountHighestRateNode() ;
	// LogOut << "CheckMaxExec, HighestCount = " << HighestCount << "\n" ;
	if (HighestCount) return TargetAdjustOK ;
	for (int i = 0 ; i < GetNode().GetIn(); i++) {
		DfNodeInLink * InLink = GetNode().GetInLink(i) ;
		TimingDescription& Timing =
			*(InLink->GetTiming());
/*
 *		LogOut << "MaxSampling Ratio = " <<
 *			BufStat->GetMaxSamplingRatio() <<
 *			", GetSamplingRatio = " << Timing.GetSamplingRatio()
 *			<< "\n" ;
 */

		if (BufStat->GetMaxSamplingRatio() < Timing.GetSamplingRatio())
			continue ;
		
		if (BufStat->GetDoubMinBufInc() > BufStat->GetMaxSize()) {
			BufStat->SetReason(new ReasonForFailure (
	"least common multiple of ratios of sampling rates is too large",
			GetNode().GetName(),-1,-1,
			ReasonForFailure::Input));
			return TargetAdjustFail ;
		}
		int32 ExecCount = GetExecCount(*(GetNode().GetInLink(i)));
		if (BufSize <= 0) return TargetAdjustFail ;
		double DoubCountRatio = BufStat->GetMaxSamplingRatio() /
            Timing.GetSamplingRatio() ;
		int32 total = (int32) (ExecCount * DoubCountRatio) ;
/*
 *		LogOut << "DCR = " << DoubCountRatio << ", ExecCount = " <<
 *			ExecCount << "\n" ;
 */
		if (total < 1) {
			ReasonForFailure * the_problem = new ReasonForFailure
                ("maximum buffer size is too small to initialize buffer",
                GetNode().GetName(),-1, InLink->GetNodeInputChannel(),
                ReasonForFailure::Input);
            BufStat->SetReason(the_problem);
            return TargetAdjustFail ;
		}
		// LogOut << "SetTotalInitExecCountHighestRateNode(" << total << ")\n" ;
		BufStat->SetTotalInitExecCountHighestRateNode(total) ;
		break ;
	} 
	return TargetAdjustOK ;
}

TargetAdjustState ExecutionSequence::DoInitInit(TraverseObject &obj)
{
/*
 *	LogOut << "DoInitInit for `" << GetNode().GetName() <<
 *		"' state is " << BufStat->StateToString() << ".\n" ;
 */
	int In = GetNode().GetIn();
	if (!In) DbgError("ExecutionSequence::DoInitInit", "has no inputs");

	if (BufStat->IsPreInitMaxBufState()) return CheckMaxExec(obj);
	else if (BufStat->IsInitState()) {
		TargetAdjustState Return = TargetAdjustOK ;
		for (int i = 0 ; i < In; i++) {
			TargetAdjustState LocReturn = ChannelInit(obj,
				*(GetNode().GetInLink(i)));
			if (LocReturn > Return) Return = LocReturn ;
			if (Return >= TargetAdjustFail) return Return ;
		}
		return Return ;
	}
	// LogOut << "Exiting ExecutionSequence::DoInitInit\n" ;
	return TargetAdjustOK ;
}


TargetAdjustState ExecutionSequence::ExecuteInit(TraverseObject& )
{
	// This is called from `ExecutionSequence::InitInit' because
	// we need to set the buffer size that point and is most
	// straightforward to compute the entire execution sequence
	// and set the buffer size at this point.
/*
 *	LogOut << "ExecutionSequence::ExecuteInit for " << GetNode().GetName()
 *		<< ", size = " << GetSize() << "\n" ;
 */
	// Check for FlushSize
	if (!GetSize()) {
		int32 MaxExecCount =
			BufStat->GetTotalInitExecCountHighestRateNode() ;
		// if multiple input streams they all have same data rate
		TimingDescription& Timing =
			*(GetNode().GetInLink(0)->GetTiming());
		double DoubCountRatio = BufStat->GetMaxSamplingRatio() /
			Timing.GetSamplingRatio() ;
		int32 LocCount = (int32) (MaxExecCount / DoubCountRatio)  ;
		if (LocCount * DoubCountRatio != MaxExecCount) {
/*
 *			LogOut << "Bad count ratio in `" <<  GetNode().GetName()
 *				<< "'.\n" ;
 *			LogOut << "DCR = " << DoubCountRatio << ", LocCount = " <<
 *				LocCount << ", MaxE = " << MaxExecCount << "\n" ;
 */
			BufStat->SetReason(new ReasonForFailure (
            "bad count ratio", GetNode().GetName(), -1 ));
            return TargetAdjustFail ;
		}
		SetSequence(1);
		SetValue(LocCount,0);
	}
	TargetAdjustState Return = CheckFlushSize() ;
	if (Return >= TargetAdjustFail) return Return ;

	if (PreviousExecutionSequenceMultiple != ExecutionSequenceMultiple) {
		// Increase sequence by ratio of two multipliers.
		int32 Ratio = ExecutionSequenceMultiple /
			 PreviousExecutionSequenceMultiple ;
		if (Ratio * PreviousExecutionSequenceMultiple !=
			ExecutionSequenceMultiple) {
			BufStat->SetReason(new ReasonForFailure (
            "bad multiples", GetNode().GetName(), -1 ));
            return TargetAdjustFail ;
		}
		int OldSize = GetSize();
		TargetAdjustState Return = SetSequence(Ratio * OldSize) ;
		if (Return > TargetAdjustChange) return Return ;
		int WriteIndex = OldSize ;
		for (int i = 0; i <= Ratio-1; i++)
		    for (int j = 0; j <= OldSize; j++) 
			SetValue(Count(j),WriteIndex++);
		// LogOut << "After Ratio Size = " << GetSize() << "\n" ;
		return Return ;
	}
	// LogOut << "At exit Size = " << GetSize() << "\n" ;
	return TargetAdjustOK ;
}


TargetAdjustState ExecutionSequence::ReconcileExecute(DfNodeOut * one_consumer,
		TraverseObject& obj) 
{
	if (State.IsError()) return TargetAdjustFail ;
	TargetAdjustState Return = TargetAdjustOK ;
/*
 *	LogOut << "ExecutionSequence::ReconcileExecute for " <<
 *		GetNode().GetName() << "\n" ;
 */
	OneConsumer = one_consumer ;
	Obj= &obj ;
	InitLinks();
	ConsumerSequence = &(OneConsumer->GetNode()->GetTargetParameters()
		->GetExecute());
	if (!ConsumerSequence) DbgError("ExecutionSequence::ReconcileExecute",
		"consumer sequence void");
	int32 DataAtLoopStart = TargetReader->GetLeftOver();
	Return = AdjustSequence(DataAtLoopStart);
/*
 *	LogOut << "ExecutionSequence::ReconcileExecute returning " << Return
 *		<< " from " << GetNode().GetName() << "\n" ;
 */
	return Return ;
} 

TargetAdjustState ExecutionSequence::ComputeConsumption(int SeqIndex,
	int SeqEnd)
{
/*
 *	LogOut << "ExecutionSequence::ComputeConsumption(" << SeqIndex
 *		<< ", " << SeqEnd << ")\n" ;
 *	LogOut << "OverlapWords = " << OverlapWords << ", LeftOver = " << LeftOver
 *		<< "\n" ;
 */

	DataConsumed = 0 ;
	DataNeeded = OverlapWords ;
	DataAvailable = LeftOver ;
	OrigLeftOver = LeftOver ;
	// int32 TheDelay = 0 ;
	for (int Index = SeqIndex; Index <=SeqEnd; Index++) {
		int ConsumerCount = ZeroEnd(ConsumerSequence->Count(Index));
		int ProviderCount = ZeroEnd(Count(Index));
/*
 *		LogOut << Index << "::ConsumerCount = " << ConsumerCount <<
 *			", ProviderCount = " << ProviderCount << "\n" ;
 *		LogOut << "InputPerExecution = " << InputPerExecution <<
 *			", OutputPerExecution = " << OutputPerExecution <<
 *			"\n" ;
 */			
		DataConsumed = ConsumerCount * InputPerExecution ;
		DataNeeded += DataConsumed ;
		DataAvailable += ProviderCount * OutputPerExecution ;
/*
 *		LogOut << GetNode().GetName() << ":DataNeeded = " <<
 *			DataNeeded << ", DataAvailable = "
 *			<< DataAvailable << "\n" ;
 */
	}
	ExcessData = DataAvailable - OutBufSize ;
	LeftOver = DataAvailable - DataNeeded ;
/*
 *	LogOut << "ExecutionSequence::ComputeConsumption exit, OutBufSize = "
 *		<< OutBufSize << ", LeftOver = " << LeftOver << "\n" ;
 */
 
	return TargetAdjustOK ;
}

TargetAdjustState ExecutionSequence::UpdateStateOut(TargetAdjustState Check)
{
	// LogOut << "StateOut = " << StateOut << ", Check = " << Check << "\n";
	if (Check > StateOut) StateOut = Check ;
	if (BufStat) BufStat->UpdateState(Check);
	return Check ;
}

TargetAdjustState ExecutionSequence::ComputeConsumptionAndBuffer(int SeqIndex,
	int SeqEnd)
{
/*
 *	LogOut << "ExecutionSequence::ComputeConsumptionAndBuffer(" << SeqIndex
 *		<< ", " << SeqEnd << ")\n" ;
 */
	TargetBufferParameters * TargetBuffer =
		ConsumerInLink->GetTargetBuffer();
	int DoOnce = 1 ;
	while (DoOnce || !TargetBuffer) {
		DoOnce = 0 ;
		if (TargetBuffer) OutBufSize = TargetBuffer->GetSize();
		else OutBufSize = 0 ;
		ComputeConsumption(SeqIndex,SeqEnd);
		if (!TargetBuffer) {
			// ConsumerInLink->AdjustTargetBuffer(BufSize);
			// LogOut<<"EnlargeBuffer from ComputeConsumptionAnd\n" ;
			EnlargeBuffer(OutBufSize,OutBufSize);
			TargetBuffer=ConsumerInLink->GetTargetBuffer();
			DoOnce = 1 ;
		}
	}
	return TargetAdjustOK ;
}

void ExecutionSequence::Clear()
{
	CurrentSize = 0 ;
	delete Sequence ;
	Sequence = 0 ;
}

