/*  bufstat.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 "execseq.h"
#include "tarnodpar.h"
#include "bufstat.h"
#include "gcd.h"


void BufferStatus::Clear()
{
	MaxSize=0;
	TotalSize=0;
	delete Reason ;
	Reason= 0;
	TryLargerBuffer = 0 ;
	ExecutionSequenceIndex = 0 ;
	ForwardFlag = 0 ;
	MaxSamplingRatio = 0.0 ;
	NumeratorMaxRatio = 1 ;
	NumLeastCommonMul = 1 ;
	DenominatorMaxRatio = 1 ;
	DenLeastCommonMul = 1 ;
	TotalInitExecCountHighestRateNode = 0;
	
}

void BufferStatus::SetGoals(Goal goal, SizeGoal s_goal,int32 desired, int32 max,
	int32 min)
{
	TheGoal = goal;
	TheSizeGoal = s_goal ;
	DesiredSize = desired;
	MaxAllowedSize = max ;
	MinAllowedSize = min ;
	Clear();
}

BufferStatus::BufferStatus():
	TheGoal(FixedSequence),
	TheSizeGoal(DesiredSizeUpperBound),
	Reason(0),
	State(TargetAdjustOK),
	MaxAllowedSize(0),
	MinAllowedSize(0),
	DesiredSize(0),
	ExecuteSequenceLength(0),
	InitSequenceLength(0)
{
	Clear();
}

BufferStatus::BufferStatus(int32 desired, int32 max, int32 min, Goal goal,
	SizeGoal size_goal):
	Reason(0),
	TheGoal(goal),
	TheSizeGoal(size_goal),
	DesiredSize(desired),
	MaxAllowedSize(max),
	MinAllowedSize(min),
	ExecuteSequenceLength(0),
	InitSequenceLength(0)
{
	Clear();
}

const char * BufferStatus::GoalToString(Goal goal) const
{
	switch(goal) {
case ExistingSize:
		return "ExistingSize" ;
case FixedSequence:
		return "FixedSequence" ;
default:
		DbgError("BufferStatus::GoalToString", "bad case");
	}
	return 0 ;
}

const char * BufferStatus::SizeGoalToString(SizeGoal size_goal) const
{
	switch(size_goal) {
case DesiredSizeLowerBound:
		return "DesiredSizeLowerBound" ;
case DesiredSizeUpperBound:
		return "DesiredSizeUpperBound" ;
default:
		DbgError("BufferStatus::GoalToString", "bad case");
	}
	return 0 ;
}

void BufferStatus::Report(ostream& Out) const
{
	Out << "Desired size = " << DesiredSize << ", maximum = "
		<< MaxAllowedSize << ", minimum = " << MinAllowedSize << "\n" ;
	Out << "The objectives are " << GoalToString(TheGoal) << " and " <<
		SizeGoalToString(TheSizeGoal) << ".\n" ;
	if (!Reason) {
		Out << "The largest buffer is " << MaxSize << " words.\n" ;
		// Out << "The total buffer space is " << TotalSize << " words.\n" ;
	}
}

void BufferStatus::Explain(ostream& Out) const
{
	if (IsFailure()) {
		Reason->Explain(Out,"set buffer size");
		Report(Out);
	}
}

int BufferStatus::CheckError()
{
	// LogOut << "BufferStatus::CheckError\n" ;
	if (!IsFailure()) return 0 ;
	Explain(OutputToWindow(OutputCppHelp)) ;
	Clear();
	return 1 ;
}


int32 BufferStatus::AllowedSize(int32 minimum, int32 maximum)
{
	if (minimum > MaxAllowedSize) {

/*
 *		LogOut << "BufferStatus::AllowedSize " << minimum  <<
 *			" > " << MaxAllowedSize << "\n" ;
 */

		return -1 ;
	}
	if (minimum < MinAllowedSize) minimum = MinAllowedSize ;
	if (maximum > MaxAllowedSize) maximum = MaxAllowedSize ;
	if (maximum < minimum) maximum = minimum ;
	int32 ReturnSize = 0 ;
	switch (TheSizeGoal) {
case DesiredSizeUpperBound:
		ReturnSize = minimum ;
		break ;
case DesiredSizeExact:
case DesiredSizeExactRequired:
		if (DesiredSize < minimum || DesiredSize > maximum)
			if (TheSizeGoal == DesiredSizeExact) {
			return -1;
		} else {
			ReturnSize = minimum ;
			break ;
		}
		ReturnSize = DesiredSize ;
		break ;
case DesiredSizeLowerBound:
		ReturnSize = maximum ;
		break ;
default:
		DbgError("BufferStatus::AllowedSize","bad case");
	}
	if (MaxSize < ReturnSize) MaxSize = ReturnSize ;

/*
 *	LogOut << "BufferStatus::AllowedSize Desired returning " <<
 *		ReturnSize << "\n" ;
 */

	return ReturnSize ;
}

TargetAdjustState BufferStatus::UpdateState(TargetAdjustState Check)
{
/*
 *	LogOut << "BufferStatus::UpdateStateOut State = "
 *			<< State << ", to Check = " << Check << "\n" ;
 */
	if (Check > State) {
/*
 *		LogOut << "BufferStatus::UpdateStateOut moving StateOut from "
 *			<< State << " to " << Check << "\n" ;
 */
		State = Check ;
	}
	return Check ;
}

int BufferStatus::AdvanceStateExecute()
{
	switch (TheState) {
case InitState:
		TheState = FlushState ;
		return 1 ;
case FlushState:
		TheState = MultipleState ;
		return 1 ;
case MultipleState:
		TheState = CheckState ;
		return 1 ;
case CheckState:
		TheState = FinalState ;
		return 1;
case FinalState:
		return 0;
case PreInitState:
case PreInitMaxBufState:
default:
		DbgError("BufferStatus::AdvanceStateExecute","bad state");
		return 0 ;
	}
}

int BufferStatus::AdvanceStateInit()
{
	switch (TheState) {
case InitState:
		TheState = FlushState ;
		return 1 ;
case FlushState:
		TheState = FinalState ;
		return 1;
case FinalState:
		return 0 ;
case CheckState:
case MultipleState:
case PreInitState:
case PreInitMaxBufState:
default:
		DbgError("BufferStatus::AdvanceStateExecute","bad state");
		return 0 ;
	}
}

const char * BufferStatus::StateToString()
{
	switch (TheState) {
case PreInitState:
		return "PreInitState" ; 
case PreInitMaxBufState:
		return "PreInitMaxBufState" ; 
case InitState:
		return "InitState" ; 
case FlushState:
		return "FlushState" ;
case CheckState:
		return "CheckState" ;
case MultipleState:
		return "MultipleState" ;
case FinalState:
		return "FinalState" ;
default:
		return "UNDEFINED" ;
	}
}

int BufferStatus::IsFatal() const
{
	// LogOut << "BufferStatus::IsFatal Reason = " << GetReason() << "\n" ;
	if (!GetReason()) return 0 ;
/*
 *	LogOut << "GetReason()->IsFatal() = " << GetReason()->IsFatal() <<
 *		"\n" ;
 */
	return GetReason()->IsFatal() ;
}

static CommandState& stupid = State ;

TargetAdjustState BufferStatus::NewResamplingForTerminalNode(int32 Num,
	int32 Denom)
{
	double ratio = 1. ;
	if (Denom > 1.e-100) ratio = ((double) Num) / Denom ;
	else {
		stupid.Error("bad denominator for timing");
		return TargetAdjustFail ;
	}
	if (ratio > MaxSamplingRatio) {
		MaxSamplingRatio = ratio ;
		NumeratorMaxRatio = Num ;
		DenominatorMaxRatio = Denom ;
	}
	int32 CheckLcmNum = LeastCommonMultiple(Num, NumLeastCommonMul);
	int32 CheckLcmDen = LeastCommonMultiple(Denom, DenLeastCommonMul);
	if (CheckLcmNum<1 || CheckLcmDen<1) return TargetAdjustFail ;
	if (CheckLcmNum > NumLeastCommonMul) NumLeastCommonMul = CheckLcmNum ;
	if (CheckLcmDen > DenLeastCommonMul) DenLeastCommonMul = CheckLcmDen ;
	return TargetAdjustOK ;
}

double BufferStatus::GetDoubMinBufInc() const
{
	int32 NumRatio = NumLeastCommonMul / NumeratorMaxRatio ;
	int32 DenRatio = DenLeastCommonMul / DenominatorMaxRatio ;

	return ((double) NumRatio) * DenRatio ;
}

int32 BufferStatus::GetMinBufInc() const
{
	int32 NumRatio = NumLeastCommonMul / NumeratorMaxRatio ;
	int32 DenRatio = DenLeastCommonMul / DenominatorMaxRatio ;

	return  NumRatio * DenRatio ;
}

void BufferStatus::ClearExecutionSequences()
{
	ExecuteSequenceLength = 0 ;
	InitSequenceLength = 0 ;
	ExecutionSequenceIndex = 0 ;
}

