/*  plotdat.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <string.h>
#include "plotdat.h"
#include "newaloc.h"
#include "cgidbg.h"
#include "coord.h"
#include "mkstr.h"

// void TestAlloc(const char * msg);

double LargeDouble = 1.5e308 ;

void * DataPlotHeader::clear_new(int size)
{
    // LogOut << "PlotChannel::clear_new(" << size << ")\n" ;
    void * ret = ::operator new(size);
#ifndef __NT_VC__
    bzero(ret,size);
#else
    char * tmp = (char *) ret ;
    for (int i = 0 ; i < size ;i++) tmp[i] = '\0' ;
#endif
    return ret ;
}

// The following is to clear the space for the structures.
// They are written to disk files and these are compared for
// validation. We had hoped to avoid spurious errors this way.
// However the structures also contain pointers that would be
// a real pain to clear in the file. Thus we ignore the
// header information in the comparison program instead,
// but we did not bother to change this code back.


void * StrAxisScalingY::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * StrAxisScalingX::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * AxisScalingY::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * AxisScalingX::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * MultiplexedElement::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * StrMultiplexedElement::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * ChannelIndex::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * StrPlotChannel::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * PlotChannel::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * StrDataPlotHeader::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

void * DataPlotHeader::operator new(unsigned int size)
{
	return DataPlotHeader::clear_new(size);
}

AxisScalingX::AxisScalingX(PlotScale scale, double maximum, double minimum,
	LabelingPlotType label, int16 size,const char * label_parameter,
	PlotPaging paging, PlotFading fading, int32 samples_in_page,
	int16 plots_per_page)
{
	// LabelParameter and LabelParameterSize specify an
	// an arbitrary size parameter block for the labeling routine
	Scale = scale ;
	Max = maximum ;
	Min = minimum ;
	Label = label ;
	Fading = fading ;
	Paging = paging ;
	SamplesPerPlot = samples_in_page ;
	PlotsPerPage = plots_per_page;
	LabelParameterSize = size ;
	LabelParameter = Concatenate(label_parameter) ;
	BlockRateFactor=1.0;
}

AxisScalingX::AxisScalingX()
{
	LabelParameter = 0;
	Max= 0.0;
	Min=0.0;
	Scale=PlotScaleAuto;
	Label = LabelingNone;
	Fading =PlotWrapErase;
	Paging=PlotPagingWrap;
	SamplesPerPlot = 0;
	PlotsPerPage=1;
	BlockRateFactor=1.0;
}

#define AssignForAxisScalingX(X)		\
	D(X,Scale) ;				\
	D(X,Max) ;  				\
	D(X,Min) ;  				\
	D(X,BlockRateFactor) ;			\
	D(X,Fading)  ;				\
	D(X,Paging)  ;				\
	D(X,SamplesPerPlot)  ; 			\
	D(X,PlotsPerPage)  ; 			\
	D(X,LabelParameterSize)	
	
AxisScalingX::AxisScalingX(StrAxisScalingX& X):
	LabelParameter(0)
{
#define D(x,z) z = x.z
	AssignForAxisScalingX(X);
#undef D 
}

AxisScalingX::~AxisScalingX()
{
    // TestAlloc("~AxisScalingX");
    // delete LabelParameter;
    // TestAlloc("~AxisScalingX after");
}



StrAxisScalingX * AxisScalingX::GetStructure()
{
	StrAxisScalingX * X = new StrAxisScalingX;
#define D(x,z) x->z = z
	AssignForAxisScalingX(X);
#undef D
#undef AssignForAxisScaling
	return X;
}

void AxisScalingX::SetLabelParameter(const char * label_parameter)
{
	LabelParameter = Concatenate(label_parameter);
}

void AxisScalingX::CopyLabelParameter(int Size,const char * label_parameter)
{
	if (Size = LabelParameterSize) DbgError(
		"PlotChannel::CopyLabelParameter","bad size");
	LabelParameter = new char [LabelParameterSize] ;
	MoveNBytes(LabelParameter,label_parameter,LabelParameterSize);
}

int AxisScalingX::Differ(AxisScalingX& Compare)
{
	if (Compare.GetPlotScale() != Scale) return 1;
	if (Compare.GetMaximum() != Max) return 1;
	if (Compare.GetMinimum() != Min) return 1;
	if (Compare.GetSamplesPerPlot() != SamplesPerPlot) return 1;
	return 0 ;
}

void AxisScalingX::SetScaling(AxisScalingX& Sc)
{
	Scale = Sc.GetPlotScale();
	Max = Sc.GetMaximum();
	Min = Sc.GetMinimum();
	SamplesPerPlot = Sc.GetSamplesPerPlot();
}

double AxisScalingX::GetIncrementPerSample()
{
	double Return ;
	if (SamplesPerPlot < 2.0 ) Return = 1.0 ;
	else if (Min < Max) {
		Return = (Max - Min) / (SamplesPerPlot-1) ;
/*
 *		LogOut << "Max = " << Max << ", Min = " << Min <<
 *			", Diff = " << Max - Min << ", Samps = " <<
 *			SamplesPerPlot << "\n" ;
 */
	} else Return = 1. / (double) (SamplesPerPlot-1) ;
	// LogOut << "GetIncrementPerSample = " << Return << "\n" ;
	return Return ;
}

int AxisScalingX::IsTwoDimensionalPlot()
{
	if (GetMinimum() < GetMaximum() && GetSamplesPerPlot() &&
		(GetPlotScale() == PlotScaleFixed)) return 1;
	return 0;
}

AxisScalingY::AxisScalingY(PlotScale scale, double maximum, double minimum,
		LabelingPlotType label, int16 size,const char * label_parameter)
{
	// LabelParameter and LabelParameterSize specify an
	// an arbitrary size parameter block for the labeling routine
	Scale = scale ;
	Max = maximum ;
	Min = minimum ;
	Label = label ;
	LabelParameterSize = size ;
	LabelParameter = Concatenate(label_parameter) ;
}

AxisScalingY::AxisScalingY():
	LabelParameter(0),
	Max(0.0),
	Min(0.0)
{
}

AxisScalingY::AxisScalingY(StrAxisScalingY& Y):
	LabelParameter(0)
{
	Scale = Y.Scale ;
	Max = Y.Max ;
	Min = Y.Min ;
/*
 *	PlotMax = Y.Max ;
 *	PlotMin = Y.Min ;
 *	if (PlotMin >= PlotMax) {
 *		PlotMin = Min ;
 *		PlotMax = Max ;
 *	}
 */
	Label = Y.Label ;
	LabelParameterSize = Y.LabelParameterSize ;
}

AxisScalingY::~AxisScalingY()
{
	// TestAlloc("~AxisScalingY");
	// delete LabelParameter;
	// TestAlloc("~AxisScalingY after");
}

void AxisScalingY::SetLabelParameter(const char * label_parameter)
{
	LabelParameter = Concatenate(label_parameter);
}

void AxisScalingY::CopyLabelParameter(int Size,const char * label_parameter)
{
	if (Size = LabelParameterSize) DbgError(
		"PlotChannel::CopyLabelParameter","bad size");
	LabelParameter = new char [LabelParameterSize] ;
	MoveNBytes(LabelParameter,label_parameter,LabelParameterSize);
}

int AxisScalingY::Differ(AxisScalingY& Compare)
{
	if (Compare.GetPlotScale() != Scale) return 1;
	if (Compare.GetMaximum() != Max) return 1;
	if (Compare.GetMinimum() != Min) return 1;
	// if (Compare.GetPlotMaximum() != PlotMax) return 1;
	// if (Compare.GetPlotMinimum() != PlotMin) return 1;
	return 0 ;
}

void AxisScalingY::SetScaling(AxisScalingY& Sc)
{
	Scale = Sc.GetPlotScale();
	Max = Sc.GetMaximum();
	Min = Sc.GetMinimum();
	// PlotMax = Sc.GetPlotMaximum();
	// PlotMin = Sc.GetPlotMinimum();
}

static const double NormFrac = 32768. ;

#define AssignForDataPlotHeader(X)	\
	D(X,PlotIdentifier) ;		\
	D(X,ScaleXBaseChannel) ;	\
	D(X,NumberOfChannels) ;		\
	D(X,StreamType) ;		\
	D(X,PlotChannelToSet) ;		\
	D(X,Spacing)


DataPlotHeader::DataPlotHeader(StrDataPlotHeader& X)
{
	DoInit();
	ScaleX = X.ScaleX ;
#define D(x,z) z = x.z
	AssignForDataPlotHeader(X);
#undef D 
	ThePlotChannels = AllocPlotChannels();
	Caption = 0;

}

DataPlotHeader::~DataPlotHeader()
{
	// LogOut << "DataPlotHeader::dtor enter\n" ;
	// TestAlloc("DataPlotHeader::dtor") ;
	// LogOut << "DataPlotHeader::dtor exit\n" ;
}

StrDataPlotHeader * DataPlotHeader::GetStructure()
{
	// LogOut << "DataPlotHeader::GetStructure()\n" ;
	StrDataPlotHeader *  X = new StrDataPlotHeader;
	// X->ScaleX = *(ScaleX.GetStructure()) ;		
	MoveNBytes((char *) &(X->ScaleX), (char *) ScaleX.GetStructure(),
		sizeof(X->ScaleX));
#define D(x,z) x->z = z
	AssignForDataPlotHeader(X);
#undef D
	return X;
}
#undef AssignForDataPlotHeader


void DataPlotHeader::DoInit()
{
	BaseChannel = -1 ;
	PlotChannelToSet = 0 ;
	ThePlotChannels = 0 ;
}

DataPlotHeader::DataPlotHeader(int16 id, int16 NumChan, AxisScalingX& X,
	PlottingStreamType streaming, DataSpacing spacing,
	const char * capt)
{
	DoInit();
	PlotIdentifier = id;
	NumberOfChannels = NumChan;
	ScaleX = X ;
	StreamType = streaming;
	ThePlotChannels = AllocPlotChannels() ;
	Spacing = spacing ;
	Caption = capt ;
/*
 *	LogOut << "DataPlotHeader::ctor, id = " << id << ",NumChan = "
 *		<< NumChan << "\n" ;
 */
}



PlotChannel ** DataPlotHeader::AllocPlotChannels()
{
	ThePlotChannels = new PlotChannel * [GetNumberOfChannels()] ;
	return ThePlotChannels ; 
}



int16 AxisScalingY::DoScale(double Value)
{
/*
 *	if (Max - Min <= 0.0) DbgError("AxisScaling::DoScale","Max Min bad");
 *	double Return = (Value - Min) * (65534. / (Max - Min)) - 32767. ;
 *	if (Return < -32767.) Return = - 32767. ;
 *	if (Return > 32767.) Return = 32767. ;
 *	LogForm("Max = %d, Min = %d, Val = %d, Return = %d",
 *		Max, Min, Value, Return);
 *	return (int16) Return ;
 */
	double Return ;
	return ::DoScale(Min,Value,Max,Return);
}


PlotChannel::~PlotChannel()
{
	// LogOut << "PlotChannel::dtor\n" ;
	// TestAlloc("PlotChannel::dtor");
}

ChannelIndex PlotChannel::ComputeSampleIndex(double BaseIndex,
	int16 BaseNumerator, int16 BaseDenominator, int16 norm_res)
{
	// LogForm("PlotChannel::ComputeSampleIndex(%d,%d,%d,%d)", BaseIndex,
	//	BaseNumerator, BaseDenominator, norm_res);
	// formula is index = Base * {(B_D)/(B_N)} * {N/D}
	// must do all the divisions first to guard against overflow
	// must save residues do compute exact index
	int32 Numerator = BaseDenominator * NumeratorResamplingFactor ;
	int32 Denominator = BaseNumerator * DenominatorResamplingFactor ;

	if (Denominator ==0) DbgError("ComputSampleIndex","0 Denominator");
	double Base = BaseIndex + ((double)norm_res)/NormFrac ;
	int32 Index = (int32) ((Base*Numerator)/Denominator) ;
	int16 Residue = (int16) ((Base*Numerator) - Index * Denominator) ;
	int16 NormalizedResidue =
		(int16) (((NormFrac) * Residue) / Denominator) ;
/*
 *	LogOut << "At exit : Index = " << Index << ", Residue = " << Residue <<
 *		", Norm = " << NormalizedResidue << "\n" ;
 */
	return ChannelIndex(Index,Residue,NormalizedResidue) ;
}

void PlotChannel::InitMultiplexedElements()
{
	TheMultiplexedElements =
		new MultiplexedElement[NumberMultiplexedElements];
}

void DataPlotHeader::SetPlotChannel(StrPlotChannel& channel)
{
	if (PlotChannelToSet >= NumberOfChannels)
		DbgError("DataPlotHeader::SetPlotChannel","All channels set");
	// LogOut << "Setting channel " << PlotChannelToSet << "\n" ;
	ThePlotChannels[PlotChannelToSet] = &(MakePlotChannel(channel)) ;
/*
 *	LogOut << "ThePlotChannels[" << PlotChannelToSet <<
 *		"].Numerator = " <<
 *		ThePlotChannels[PlotChannelToSet]->GetNumerator() <<
 *		", ...Denominator = " << ThePlotChannels[PlotChannelToSet]->
 *		GetDenominator() << "\n" ;
 *
 *	LogOut << "ThisChannel = 0x" <<
 *		hex((long)ThePlotChannels[PlotChannelToSet])  << "\n";
 */
	if (ThePlotChannels[PlotChannelToSet]->GetChannelNumber() !=
		PlotChannelToSet) {
/*
 *		LogOut << "PlotChannelToSet = " << PlotChannelToSet <<
 *			", value from structure = " <<
 *			ThePlotChannels[PlotChannelToSet]->GetChannelNumber() 
 *			<< "\n" ;
 */
		DbgError("DataPlotHeader::SetPlotChannel", "bad channel");
	}
/*
 *	LogOut << "ThePlotChannels[PlotChannelToSet]->GetChannelNumber() = " <<
 *		ThePlotChannels[PlotChannelToSet]->GetChannelNumber()  << "\n" ;
 */
	ThePlotChannels[PlotChannelToSet]->Init();
	ThePlotChannels[PlotChannelToSet]->SetChannelNumber(PlotChannelToSet);
	ThePlotChannels[PlotChannelToSet++]->InitMultiplexedElements();
}

void DataPlotHeader::SetMultiplexedElement(
	StrMultiplexedElement& multiplexed_element)
{
	if (!PlotChannelToSet) DbgError("DataPlotHeader::SetMultiplexedElement",
		"no channel to set");
	ThePlotChannels[PlotChannelToSet-1]->SetMultiplexedElement(
		multiplexed_element);
}


void DataPlotHeader::SetLabelParameter(int Size, const char * label_parameter)
{
	if (!ScaleX.LabelParameter) {
		ScaleX.CopyLabelParameter(Size, label_parameter);
		return ;
	}
	if (!PlotChannelToSet) DbgError("DataPlotHeader::SetLabelParameters",
		"no channel to set");
	ThePlotChannels[PlotChannelToSet-1]->SetLabelParameter(Size,
		label_parameter);
}


void PlotChannel::SetLabelParameter(int Size,const char * label_parameter)
{
	if (!ScaleY.LabelParameter) ScaleY.CopyLabelParameter(Size,
		label_parameter);
	else DbgError("PlotChannel::SetLabelParameter","labels set already");
	
}

int PlotChannel::NotComplete()
{
	if (MultiplexedElementToSet < NumberMultiplexedElements) return 1 ;
	if (ScaleY.LabelParameterSize && !ScaleY.LabelParameter) return 1;
	return 0;
}

void PlotChannel::SetMultiplexedElement(
	StrMultiplexedElement& MxElement)
{
	if (MultiplexedElementToSet > NumberMultiplexedElements-1) 
		DbgError("PlotChannel::SetMultiplexedElement","already set");
	TheMultiplexedElements[MultiplexedElementToSet++] = *(new
		MultiplexedElement(MxElement)) ;
}

double DataPlotHeader::DisplaySampleRateFactor(int Channel, int TimeLabel)
{
	return GetChannel(Channel)->DisplaySampleRateFactor(TimeLabel,
		GetScaleX().IsTwoDimensionalPlot());
}

double PlotChannel::DisplaySampleRateFactor(int TimeLabel, int TwoDim)
{
/*
 *	LogOut << "DisplaySampleRateFactor(" << TimeLabel << ", "
 *		<< TwoDim << ")\n" ;
 *	LogOut << "SamleRate = " << SampleRate << "\n" ;
 */
	if (TwoDim) {
		// LogOut << "SampleRateFactor = " << SampleRateFactor << "\n" ;
		if (TimeLabel) return 1./SampleRate ;
		if (SampleRateFactor == 0.0) return SampleRateFactor ;
		return SampleRateFactor * SampleRate ;
	} else return 1./SampleRate ;
}


PlotChannel& DataPlotHeader::MakePlotChannel(StrPlotChannel& channel)
{
	return *(new PlotChannel(channel));
}

PlotChannel * DataPlotHeader::GetChannel(int Channel)
{
	if (Channel > -1 && Channel < NumberOfChannels)
		return ThePlotChannels[Channel];
	return 0;
}

double DataPlotHeader::GetFirstSampleTime()
{
	// LogMsg("DataPlotHeader::GetFirstSampleTime");
	double Earliest = LargeDouble ;
	for (int i = 0 ; i < NumberOfChannels; i++) {
		double ChannelTime = GetChannel(i)->GetFirstSampleTime() ;
		if (ChannelTime < Earliest) Earliest = ChannelTime ;
 
	}
	// LogMsg("GetFirst Exit");
	return Earliest ;
}

void DataPlotHeader::SetBaseChannel()
{
	BaseChannel = -1;
	double Highest = 0.0 ;
	for (int i = 0 ; i < NumberOfChannels; i++) {
		double ChannelRate = GetChannel(i)->GetSamplingRatio() ;
		if (ChannelRate > Highest) {
			Highest = ChannelRate ;
			BaseChannel = i;
		}
	}
	if (BaseChannel < 0) DbgError("DataPlotHeader::SetBaseChannel",
		"cannot set channel");
}
	
int DataPlotHeader::GetBaseChannel()
{
	if (BaseChannel< 0) SetBaseChannel();
	return BaseChannel ;
}

double DataPlotHeader::GetHighestSampleRate()
{
	// LogOut << "DataPlotHeader::GetHighestSampleRate\n" ;
	if (BaseChannel <0) SetBaseChannel();
/*
 *	LogOut << "Numerator = " << GetChannel(BaseChannel)->GetNumerator()
 *		<< ", Denominator = " <<
 *		GetChannel(BaseChannel)->GetDenominator() << "\n" ;
 *	LogOut << "BaseChannel = " << BaseChannel << "\n" ;
 */
	return GetChannel(BaseChannel)->GetSamplingRatio();
}

int32 DataPlotHeader::GetInputElementSize(int Channel)
{
	return GetChannel(Channel)->GetInputElementSize();
}


int32 DataPlotHeader::GetBaseChannelElementSize()
{
	if (BaseChannel <0) SetBaseChannel();
	return GetChannel(BaseChannel)->GetInputElementSize();
}

void DataPlotHeader::SetScaleX(AxisScalingX& Sc)
{
	ScaleX.SetScaling(Sc);
}

void DataPlotHeader::SetScaleY(AxisScalingY& Sc, int i)
{
	GetScaleY(i).SetScaling(Sc);
}

void AxisScalingX::Dump()
{
	TheLog << "AxisScalingX::Dump Scale = " << (int) Scale << ", Max = " <<
		Max << ", Min = " << Min << ", ParmSize = " <<
		LabelParameterSize << "\n" ;
	TheLog << "Fading = " << (int) Fading << ", Paging = " << (int) Paging
		<< ", SamplesPerPlot = " << SamplesPerPlot << ", LabelType = "
		<< (int) Label << "\n" ;
}

void AxisScalingY::Dump()
{
	TheLog <<  "AxisScalingY::Dump\n";
	TheLog << "AxisScalingY::Dump Scale = " << (int) Scale << ", Max = " <<
		Max << ", Min = " << Min << ", ParmSize = " <<
		LabelParameterSize << "\n" ;
	TheLog << "LabelType = " << (int) Label << "\n" ;
}

void StrMultiplexedElement::Dump()
{
	TheLog<< "MultiplexedElement::Dump:ScaleFactor = " << ScaleFactor <<
		", Color = " << Color << ", LineType = " << LineType << "\n" ;
}

void MultiplexedElement::Dump()
{
	TheLog << "MultiplexedElement::Dump:ScaleFactor = " << ScaleFactor <<
		", Color = " << Color << ", LineType = " << LineType << "\n" ;
}

void ChannelIndex::Dump()
{
	TheLog << "ChannelIndex::Dump:Index = " << Index << ", ExtRes = " <<
		ExactResidue << ", NormRes = " << NormalizedResidue << "\n" ;
}

void StrPlotChannel::Dump()
{
	TheLog << "StrPlotChannel::Dump()\n" ;
	TheLog << "Channel = " << ChannelNumber << ", elts = " <<
		NumberMultiplexedElements << ", ElementToSet = " <<
		MultiplexedElementToSet << "\n" ;
	TheLog << "Numerator = " << NumeratorResamplingFactor <<
		",  Denominator = " << DenominatorResamplingFactor << "\n" ;
	TheLog << "ArithType = " << ThePlotArithType << ", InputElementSize = "
		<< InputElementSize << ", BlockSize = " << InputBlockSize << "\n" ;
	TheLog << ", SampleRate = " << SampleRate << ", FirstTime = " <<
		FirstSampleTime << ", Factor = " << SampleRateFactor << "\n" ;
}


void PlotChannel::Dump()
{
	TheLog << "PlotChannel::Dump, index = " << ChannelNumber << "\n" ;
	ScaleY.Dump();
	TheLog << "PlotChannel::Dump: NumMpx=" << NumberMultiplexedElements
		<< ", ToSet = " << MultiplexedElementToSet << ", Num = " <<
		NumeratorResamplingFactor << ", Den = " <<
		DenominatorResamplingFactor << "\n" ;
		
	TheLog << "FirstSampleTime = " << FirstSampleTime << "\n" ;
}

void PlotChannel::DumpFull()
{
	Dump();
	TheLog << "Multiplexed Elements are:\n";
	for (int i = 0 ; i < NumberMultiplexedElements; i++)
		TheMultiplexedElements[i].Dump();
}
	


void StrDataPlotHeader::Dump()
{
	TheLog << "StrDataPlotHeader::Dump()\n" ;
	TheLog << "PlotId = " << PlotIdentifier << ", channels = " <<
		NumberOfChannels << ", StreamType = " << (int)  StreamType << "\n" ;
	TheLog << "ChannelToSet = " << PlotChannelToSet << ", Spacing = "
		<< (int) Spacing << "\n" ;
}

void DataPlotHeader::Dump()
{
	TheLog << "DataPlotHeader::Dump\n";
	TheLog << "DataPlotHeader::Dump:PltId=" << PlotIdentifier << ", XBase="
		<< ScaleXBaseChannel << ",NumChan=" << NumberOfChannels << ",StrTyp="
		<< (int) StreamType << "\n" ;
	ScaleX.Dump();
	TheLog << "PlotChannelToSet = " << PlotChannelToSet << ", Spacing = "
		<< (int) Spacing << "\n" ;
	if (Caption) TheLog << "Caption is `" << Caption << "'.\n" ;
	else TheLog << "Null caption\n";
}

void DataPlotHeader::DumpFull()
{
	Dump();
	TheLog << "The " << NumberOfChannels << " plot channels are:\n";
	for (int i = 0 ; i < NumberOfChannels;i++) 
		if (ThePlotChannels[i]) ThePlotChannels[i]->Dump();
}

double PlotChannel::GetSamplingRatio() const 
{
	if (!DenominatorResamplingFactor) return 1. ;
	return ((double) NumeratorResamplingFactor) /
		DenominatorResamplingFactor;
}

