/*  axslab.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include <stream.h>
#include <stdio.h>
#include "portable.h"
#include <math.h>
#include "axslab.h"
#include "plotdatg.h"
#include "cgidbg.h"
#include "iv_graph.h"

void AxisLabelBase::Check()
{
	if (!GetDataPlot()) DbgError("AxisLabelBase::Check","no plot");
}


double PlotIncrement(double ScaledSize)
// ScaledSize is ratio of total plot range to largest power of 10 <= this range
// Value returned is the multiplier of this power of 10 that is the
// generates the increment between ticks.
{
	if (ScaledSize < 1. || ScaledSize >= 10.) DbgError("PlotIncrement",
		"invalid parameter");
	if (ScaledSize > 5.) return 1. ;
	if (ScaledSize > 2.5) return .5 ;
	if (ScaledSize > 2.0) return .25 ;
	return .2 ;
}

static const double very_small = 1.e-200 ;

static void PlotTicks (double Begin, double End, double& Size, double& Start)
// Begin and end are the end points of the data to be plotted.
// Size and Start are returned. They are the Position of the first tick mark
// and the space between tick marks as a fraction of the total data range.
{
	double Diff = End - Begin ;

/*
 *	LogOut << "PlotTicks - Begin = " << Begin << ", End = " << End <<
 *		", Diff = " << Diff << "\n" ;
 */

	if (fabs(Begin) > 1.e50 || fabs(End) > 1.e50 || Diff< 1.e-50) {
		// if (Diff <= 0) Size = 5. ;
		// else Size = Diff * .2 ;
		Size = 5.0 ;
		Start = Begin ;
		// if (Size = 0.0) Size = 1.0;
		// LogOut<< "Size = " << Size << ", Start = " << Start << "\n" ;
		return ;
	}
	double ScaledSize ;
	double LogDiff = 0.;
	if (Diff > very_small) LogDiff = log10(Diff);
	double Power10;
	double Factor;
	int sign = 1 ;
	if (LogDiff < 0) {
		LogDiff = -LogDiff+1 ;
		sign = -1;
	}
	Power10 = (int32) (LogDiff + 1.e-8);
	// LogOut <<"LogDiff = "<<LogDiff << ", Power10 = " << Power10 << "\n";
	Factor = 0.0 ;
	if (Power10 < 200.) Factor = pow(10.,Power10);
	if (Factor < 0x7fffffff) Factor = (int32) (Factor * (1 +1.e-12));
	if (sign < 0) Factor = 1./Factor ;
	ScaledSize = Diff/Factor ;
/*
 *	LogOut << "ScaledSize = " << ScaledSize << ", Factor = "
 *		<< Factor << ", Power10 = " << Power10 << "\n" ;
 */


	Size = PlotIncrement(ScaledSize);
	Size *= Factor ;

/* else {
 *		Power10 =(int32) (-.999999-LogDiff) ;
 *		Factor = pow(10.,Power10);
 *		ScaledSize = Diff*Factor ;
 *
 *
 *		LogOut << "ScaledSize = " << ScaledSize << ", Factor = "
 *		 	<< Factor << ", Power10 = " << Power10 << "\n" ;
 *
 *
 *
 *
 *		Size = PlotIncrement(ScaledSize);
 *		Size /= Factor ;
 *	}
 */
	// LogOut << "Begin = " << Begin << "\n" ;
	double PosBegin = fabs(Begin);
	// LogOut << "PosBegin = " << PosBegin << "\n" ;
	if (PosBegin > Size * 0x70000000) Start = 0.0 ;
	else {	
		int32 Mult = 0;
		if (Size > 0.0) Mult = (int32) (PosBegin/Size) ;
		// LogOut << "Mult = " << Mult << ", Size = " << Size << "\n" ;
		if (Begin < 0.0) {
			Start = -Mult * Size ;
			while (Start > Begin) Start -= Size ;
			Start += Size ;
		} else {
			Start = Mult*Size ;
			while (Start < Begin) Start += Size ;
		}
		// LogOut << "Start = " << Start << "\n" ;
		Start = Start - Begin ;
		// LogOut << "Start(-B) = " << Start << "\n" ;
	}
	if (Diff > 0.0) {
		Size /= Diff ;
		Start /= Diff ;
	}
	// LogOut<<"PlotTicks - Start = " <<Start<<", Size = " << Size << "\n";
}

double AxisLabelingLinearX::GetDynamicSampleRateFactor()
{
	DataPlotHeader * PlotHeader = GetDataPlotHeader();
/*
 *	LogOut << "Computing DynamicSampleRateFactor for `" <<
 *		PlotHeader->GetCaption() << "'.\n" ;
 */
	DataPlot * ThePlot = GetDataPlot();
	int BaseChannel = PlotHeader->GetBaseChannel();
	double Result = 1. ;
 	AxisScalingX& ScaleX = GetDataPlotHeader()->GetScaleX() ;

	double RateFactor = ThePlot->GetSampleRateAdjustment(BaseChannel);
	if (ScaleX.IsTwoDimensionalPlot()) {
/*
 *		PlotChannel * ThePlotChannel = GetDataPlotHeader()->
 *			GetChannel(GetDataPlotHeader()->GetBaseChannel());
 *		double BlockSize = ThePlotChannel->GetInputBlockSize();
 */
		double Factor = ThePlot->GetAdjustedSampleRate(BaseChannel);
		Result = Factor ;
		// LogOut << "Factor = " << Factor << "\n" ;
	} else {
		if (RateFactor > 1.e-50) Result /= RateFactor ;
		// LogOut << "RateFactor = " << RateFactor << "\n" ;
	}
	// LogOut <<"AxisLabelingLinearX::GetDyn returning " << Result << "\n" ;
	return Result ;	
}

void AxisLabelingLinearX::SetTickSpacing()
{
	// LogMsg("AxisLabelingLinearX::SetTickSpacing");
	Check();

	// Compute total samples in one screen
	// 	If PlotPaging is set then if Min >= Max and
	//	if SamplesPerPlot is not 0 then this is a 2-D
	//	plot. Min and Max are labels in the dimension
	//	across a plot. The time is the time for each entire
	//	plot. It is displayed on a separate line from X axis 
	//	labeling. If SamplesPerPlot is set and Min+Max then
	//	we have a 1-D plot with time running across the X
	//	axis.  If Min and Max are set and SamplesPerPlot is 0
	//	we again have a 1 -D plot. In both of these latter cases
	//	the samples displayed is determined by the header.
	//	If Min >= Max and SamplesPerPlot is 0 then the samples
	//	per plot is determined by the screen resolution.
	//
	//	If there is not plot paging than all these samples
	//	are displayed on a single plot. This is not yet implemented.

	if (!GetDataPlotHeader()) DbgError("AxisLabelingLinearX",
		"no DataPlotHeader");
	if (!GetPlotWindow()) DbgError("AxisLabelingLinearX",
		"no PlotWindow");
	AxisScalingX& ScaleX = GetDataPlotHeader()->GetScaleX() ;
	double FirstTime = GetDataPlotHeader()->GetFirstSampleTime() ;
	double MaxSampleRate = GetDataPlotHeader()->GetHighestSampleRate() ;
/*
 *	LogOut << "Tick:`" << GetDataPlotHeader()->GetCaption() << 
 *		"' FirstTime = " << FirstTime << ", MaxRate = "
 *		<< MaxSampleRate << "\n" ;
 */
	PlotScale Scaling = ScaleX.GetPlotScale();
	PlotPaging Paging = ScaleX.GetPaging();

	double Begin,End ;
	int32 BaseSample = GetDataPlot()->GetFirstBlockOnCurrentPlot();
	double SamplesPerScreen = ScaleX.GetSamplesPerPlot() ;
	double PreviousSamples = BaseSample /* * MaxSampleRate */ ;
/*
 *	LogOut << "BaseSample = " << BaseSample << ", perplot = " <<
 *		SamplesPerScreen << "\n" ;
 */

	// LogOut << "Scaling = " << Scaling << "\n" ;

	double NoSamples =1.0 ;
	switch (Scaling) {
case PlotScaleFixed:
		double Min = ScaleX.GetMinimum();
		double Max = ScaleX.GetMaximum();
		if (SamplesPerScreen && Min < Max) {
			NoSamples = SamplesPerScreen;
			Begin = Min ;
			End = Max ;
		} else {
			NoSamples = /* MaxSampleRate * */
				(Max - Min)  ;
			Begin = Min + PreviousSamples -1 ;
			if (Paging == PlotPagingOnePage) End = Max ;
			else if(SamplesPerScreen) End = Begin + MaxSampleRate *
				(SamplesPerScreen) ;
			else End = Begin + MaxSampleRate *
				(GetDataPlot()->GetNumberSamplesInPlot());
		}
		if (NoSamples < 1) DbgError(
		"AxisLabelingLinearX::SetTickSpacing","samples in page < 1");

		break ;
case PlotScaleAuto:
		Begin = FirstTime + MaxSampleRate * PreviousSamples ;
/*
 *		LogOut << "FirstTime = " << FirstTime << ", MaxSampleRate = "
 *			<< MaxSampleRate << ", PreviousSamples = " <<
 *			PreviousSamples << "\n" ;
 */
		if (SamplesPerScreen) End = Begin +
				(NoSamples=SamplesPerScreen)*
			MaxSampleRate ;
		else End = Begin + MaxSampleRate * (NoSamples =
				GetDataPlot()->GetNumberSamplesInPlot());
/*
 *		LogOut << "SamplesPerScreen = " << SamplesPerScreen <<
 *			", Samples In Plot = " << GetDataPlot()->
 *			GetNumberSamplesInPlot() << "\n" ;
 */
		// LogOut << "Begin = " << Begin << ", End = " << End << "\n" ;
		// LogOut << "PreviousSamples = " << PreviousSamples << "\n" ;
		break ;
case PlotScaleRangeAuto:
default:
		DbgError("AxisLabelingLinearX","bad scale type");
	}


	double Size, Start;
	double Sfac = GetDynamicSampleRateFactor();
/*
 *	LogOut << "Begin = " << Begin << ", End = " << End<< " SetTickSpacing `"
 *		<< GetDataPlotHeader()->GetCaption() << "'\n" ;
 */
	if (Sfac > 0.0) {
		Begin *= Sfac ;
		End *= Sfac ;
	}

	// LogOut << "Begin = " << Begin << ", End = " << End<< "\n" ;
/*
 *	LogOut << "NoSamples = " << NoSamples << ",IsTwoDim = " <<
 *		ScaleX.IsTwoDimensionalPlot() << "\n" ;
 */

	PlotTicks(Begin, End, Size, Start) ;
	// double Diff = End - Begin ;
	// SetTickParms(Start/Diff,Size/Diff);
	SetTickParms(Start,Size);
	// LogOut << "After XSetTickParms\n" ;
}


static const CharactersInNumber = 7 ;

static const char * GetNumberString(double Diff, double Val)
{
	static char StrBuf[64+CharactersInNumber+1];
	Val *= 1.000001 ;  // avoid truncation 
	const char * Format = "";
	int Precision = -1 ;
	if (fabs(Diff) < 1.e-50) Diff = 1.e-50;
	if (fabs(Val) < 1.e-50) strcpy(StrBuf,"0") ;
	else {
		double Log10 = 0. ;
		if (Diff > very_small) Log10 = log10(Diff) ;
		if (Log10 <  CharactersInNumber && Log10 > -3) {
			// %f format
			Format = "%-7.*f" ;
			if ( Log10 > 4.) Precision = 0 ;
			else Precision = (int) (5. - Log10) ;
		} else {
			/* %e format */
			Format = "%-7.*e" ;
			Precision = 0 ;
		}
		sprintf(StrBuf,Format,Precision,Val);
		// strcpy(StrBuf,form(Format,Precision,Val));
		for (char * SetNull = StrBuf; *SetNull; SetNull++)
			if (*SetNull == ' ') *SetNull = '\0' ;
		if (strlen(StrBuf) > CharactersInNumber) {
/*
 *			LogOut << "Numer label too big ****** : " << 
 *					StrBuf << "\n" ;
 */
			StrBuf[CharactersInNumber]= '\0' ;
		}
	}
	return StrBuf ;
}

static const char * CenterNumber(const char * Source)
{
	static char Result[CharactersInNumber+1] ;
	int Length = strlen(Source);
	// if (Length > CharactersInNumber - 2) return Source ;
	int Start = (CharactersInNumber - Length + 1) >> 1 ;
	for (int i = 0 ; i < Start ; i++) Result[i] = ' ' ;
	strcpy(Result+Start,Source);
	for (i = strlen(Result) ; i < CharactersInNumber ; i++) 
		Result[i] = ' ' ;
	Result[CharactersInNumber] = '\0' ;
	return Result ;
}

void AxisLabelBase::WriteLabelText( const char * Text, int32 x, int32 y)
{
/**********
	Screen& TheScreen = *GetScreen();
	TheScreen.SetTextColor(White) ;
	TheScreen.SetAlphaTextPosition(x,y);
	TheScreen.WriteAlphaText(Text);
**********/
}

void AxisLabelingLinearX::WriteLabel(int Ix, int32 x)
{
	

	// Labeling is based on scaling

/**********
	LabeledPlot& PltWindow = *((LabeledPlot *) GetPlotWindow());
	int NoPer = PltWindow.GetNoXTicksPerLabel();
	if (NoPer > 1) if (Ix % NoPer) return ; 
	
	DataPlot& PlotDesc = *((DataPlot *) GetDataPlotHeader()) ;
	double FirstTime = PlotDesc.GetFirstSampleTime() ;
	PlotChannelPointer& RateBase = *(PlotDesc.GetSamplingRatioBase());
	AxisScalingX& Scaling = PlotDesc.GetScaleX();

	double Rate = (double)(PlotDesc.GetNumerator()) /
		PlotDesc.GetDenominator();
**********/
/*
 *	LogOut << "Write:`" << GetDataPlotHeader()->GetCaption() << 
 *		"' FirstTime = " << FirstTime << ", Rate = "
 *		<< Rate << "\n" ;
 */	
}

void AxisLabelingLinearY::SetTickSpacing()
{
	// LogOut << "AxisLabelingLinearY::SetTickSpacing\n";
	Check();
	// Compute total samples in one screen
	// Determinates in order are:
	// 1 plot scaling fixed (Min and Max)
	//	If there is not plot paging than all these samples
	//	are displayed on a single plot, If there is plot paging
	//      then conditions 2 and 3 determine the number of samples
	//	on a page.
	// 2 SamplesPerScreen not zero
	// 3 Number of pixels in plot region

	if (!GetDataPlotHeader()) DbgError("AxisLabelingLinearY",
		"no DataPlotHeader");
	if (!GetPlotWindow()) DbgError("AxisLabelingLinearY",
		"no PlotWindow");
	AxisScalingY& ScaleY = GetDataPlotHeader()->GetScaleY() ;
	PlotScale Scaling = ScaleY.GetPlotScale();
	double Min, Max;
	switch (Scaling) {
case PlotScaleFixed:
		Min = ScaleY.GetMinimum();
		Max = ScaleY.GetMaximum();
/*
 *		LogOut << "FixedScaling: Min = " << Min << ", Max = " <<
 *			Max << "\n" ;
 */
		// double Diff = (Max - Min) ;
		/* if (Diff < 1) DbgError(
		 * a"AxisLabelingLinearY::SetTickSpacing","Diff < 1");
 		 */
		break ;
case PlotScaleAuto:
			// Base scaling on values of actual data
		DataPlot * PlotDesc = (DataPlot *) GetDataPlotHeader() ;
		PlotChannelPointer * Base = PlotDesc->GetYScaleBase();
/*
 *		LogOut << "PlotScaleAuto:Base-Min = " << Base->GetMinYVal() << 
 *			", Base-Max = " << Base->GetMaxYVal() << "\n" ;
 */
		Min = Base->GetMinYVal();
		Max = Base->GetMaxYVal();
		break ;
case PlotScaleRangeAuto:
			// Base scaling on rescaled values of actual data
		double MinData = Base->GetMinYVal();
		double MaxData = Base->GetMaxYVal();
/*
 *		LogOut << "PlotScaleAutoRange::MinData = " << MinData <<
 *			", MaxData = " << MaxData << "\n" ;
 */
		if (MaxData < MinData) MaxData=MinData=0;

		double ScMin = ScaleY.GetMinimum();
		double ScMax = ScaleY.GetMaximum();

		double DiffScale = (ScMax - ScMin) / (2. * 32767.) ;
		// LogOut <<"ScMin = "<<ScMin << ", ScMax = " << ScMax << "\n" ;

		Min = (int32) (ScMin + DiffScale * MinData) ;
		Max = (int32) (ScMin + DiffScale * MaxData) ;
		
		break ;
default:
		DbgError("AxisLabelingLinearY","bad scale type");
	}

	 // LogOut << "Min = " << Min << ", Max = " << Max << "\n" ;
	if (Min>Max) {
		// LogOut << "************** Max < Min\n" ;
		Max = Min = 0;
	}
	if (Max==Min) {
		// LogOut << "************** Max == Min\n" ;
		if (Min > -32767 ) Min-- ;
		if (Max < 32767) Max++ ;
	}

	double Size, Start;
	double Begin = Min ;
	double End = Max ;
	// LogOut << "PlotTicks\n" ;
	PlotTicks(Begin, End, Size, Start) ;
	// LogOut << "PlotTicks back\n" ;
	// double Diff = End - Begin ;
	// SetTickParms(Start/Diff,Size/Diff);
	SetTickParms(Start,Size);
	// LogOut << "After YSetTickParms\n" ;
}

void AxisLabelingLinearX::Init()
{
	SetMaxNoCharacters(7);
}

void AxisLabelingLinearY::Init()
{
	SetMaxNoCharacters(7);
}

void AxisLabelingLinearY::WriteLabel(int Ix, int32 y)
{
	// Labeling is based on scaling
}


class DataPlot * AxisLabelBase::GetDataPlot()
{
	return ThePlotWindow->get_data_plot();
}

class DataPlotHeader * AxisLabelBase::GetDataPlotHeader()
{
	return ThePlotWindow->get_data_plot_header();
}

void AxisLabelBase::Init()
{
	// LogForm("AsisLabelBase::Init, ThePlotWindow =0x%x",
	 //	(long) ThePlotWindow);
}

double AxisLabelingLinearX::GetSampleRate()
{
	return GetDataPlot()->GetDynSampleRate();
}

void AxisLabelX::Init()
{
	// LogMsg("AxisLabelX::Init");
}

void AxisLabelY::Init()
{
 	// LogMsg("AxisLabelY::Init");
}

void AxisLabelingLogarithmicY::SetTickSpacing()
{
}


void AxisLabelingLogarithmicX::SetTickSpacing()
{
}

AxisLabelBase::AxisLabelBase(Graph * Win)
{
	// LogMsg("AxisLabelBase::_ctor");
	ThePlotWindow = Win;
	Init();
}


void AxisLabelX::WriteLabel(int, int32)
{
	// LogMsg("AxisLabelX::WriteLabel");
}



void AxisLabelY::WriteLabel(int, int32)
{
 	// LogMsg("AxisLabelY::WriteLabel");

}

