/*  plotdatg.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */

#include <string.h>
#include <complex.h>
#include <unistd.h>
#include "iv_graph.h"
#include <InterViews/window.h>
#include <InterViews/leave-scope.h>
#include "coord.h"
#include "plotdatg.h"
#include "newaloc.h"
#include "usercom.h"

#include "shared.h"
#include "remcom.h"
#include "wfiles.h"
#include "help.h"
#include "plotfile.h"
#include "dsp_app.h"

const XYSampleSize = 2 ;

// static const double very_big = 1.e200 ;
// static const double rec_very_big = 1./1.e200 ;
#include "plot_lim.h"

class WindowOverlay ;


DataPlot::DataPlot(StrDataPlotHeader& Hd, Transform t):
	DataPlotHeader(Hd),
	the_transform(t)
{
	// LogOut << "DataPlot::DataPlot, t = " << t << "\n" ;
	Init();
}

DataPlot::DataPlot():
	first_page_plotted(0),
	the_transform(none)
{
	// LogOut << "DataPlot::DataPlot\n" ;
	Init();
}

DataPlot::~DataPlot()
{
	// LogOut<<"~DataPlot called, channels = "<<GetNumberOfChannels() << "\n" ;
	// LogOut << "Caption `" << GetCaption() << "'\n" ;
	// TestAlloc();
	// DataPlot * clone ;
	// DataPlotListIterator Next(clones);
	// while (clone = Next()) delete clone ;
	for (int i = 0 ; i < GetNumberOfChannels(); i++) delete GetPlotChannel(i);
	// delete[] (void *) Name ;
	// TestAlloc();
	// LogOut << "~DataPlot exit\n" ;
}


int32 DataPlot::GetBlockSize()
{
	return GetChannel(GetBaseChannel())->GetInputBlockSize();
}

int16 DataPlot::GetNumerator()
{
	if (BaseChannelNumerator < 0) ComputeBaseChannel();
	return BaseChannelNumerator;
}

int16 DataPlot::GetDenominator()
{
	if (BaseChannelDenominator < 0) ComputeBaseChannel();
	return BaseChannelDenominator;
}

double DataPlot::GetSampleRate()
{
	return GetNumerator() / (double) GetDenominator();
}

PlotChannel& DataPlot::MakePlotChannel(StrPlotChannel& channel)
{
	PlotChannelPointer * this_cloned_from = 0 ;
	if (the_transform != none) {
		if (!cloned_from) DbgError("DataPlot::MakePlotChannel","no clone_from");
		int chan = channel.ChannelNumber ;
		this_cloned_from = cloned_from->GetChannel(chan);
	}
	PlotChannelPointer * Chan = new PlotChannelPointer(channel,the_transform,
		this_cloned_from);
	return *Chan ;
}

void DataPlot::InitPlotChannels()
{
	// LogForm("InitPlotChannels channels = %d",GetNumberOfChannels());
	for (int i = 0; i < GetNumberOfChannels() ; i ++) {
		PlotChannelPointer * TheChannel =
			(PlotChannelPointer *) GetPlotChannel(i);
		// LogOut << "SetIndex(" << i << ")\n" ;
		TheChannel->SetIndex(i);
		TheChannel->SetPlot((DataPlot *) this);
/*
 *		LogForm("Inited(%d) 0x%x to Plot 0x%x", i,
 *			(long) TheChannel, (long) this);
 */
	}
	ComputeBaseChannel();
	OriginalScaleX = GetScaleX() ;
	PreviousScaleX = GetScaleX() ;
}

/*	
 * 	Data is sent and stored consecutively. However, in some applications
 *	the true data rate will not be an exact rational multiple of other
 *	data rates in the system and may actually change over time. For
 *	example in Modem transmissions over the telephone network variable
 *	delays due to doopler shift are possible. Thus there may be
 *	embedded in a data stream for plotting a timing correction. This
 *	a sequence starting with the value -very_big (a disallowd data value)
 *	and followed by words specifying the exact correction.
 *	
 *	This is handled in data storage by putting the data as close as
 *	possible to its actual time (missing data is interpolated with
 *	zeros and data samples may be discarded as well) and keeping
 *	a link list of the exact nature of each timing correction.
 */

double DataPlot::TimeToIndex(double Time)
{
	double Return  = GetChannel(GetScaleXBaseChannel())->TimeToIndex(Time);
/*	
 *	LogForm("DataPlot::TimeToIndex(%d * .001) = %d",
 *		(long)(1000*Time), Return);
 */
	return Return ;
}

double DataPlot::IndexToTime(double Index)
{
	double Return = GetChannel(GetScaleXBaseChannel())->IndexToTime(Index);
/*
 *	LogForm("DataPlot::IndexToTime(%d) %d * .001", Index,
 *		(long) (Return * 1000));
 */
	return Return;
}



PlotChannelPointer::PlotChannelPointer()
{
	// LogOut << "PlotChannelPointer::PlotChannelPointer()\n" ;
	the_data_file  = new DataFile ;
	DoInit();
}

PlotChannelPointer::PlotChannelPointer(class StrPlotChannel& Chan,
	int the_transform, PlotChannelPointer * cloned_from):
	PlotChannel(Chan)
{
	// LogOut << "PlotChannelPointer::PlotChannelPointer(StrPlotChannel&)\n" ;
	// LogOut << "transform = " << the_transform << "\n" ;
	if (the_transform != DataPlot::none)
		the_data_file = new DataFileClone(this,
		(DataPlot::Transform)the_transform,
		cloned_from);
	else the_data_file  = new DataFile ;
	DoInit();
}

PlotChannelPointer::~PlotChannelPointer()
{
	// LogOut << "delete PlotChannelPointer called\n" ;
	delete the_data_file ;
}

double PlotChannelPointer::GetPlotMaximum()
{
	return GetOriginalScaleY().GetMaximum();
}

double PlotChannelPointer::GetPlotMinimum()
{
	return GetOriginalScaleY().GetMinimum();
}


	
void PlotChannelPointer::SeekToSample(int32 SampleIndex)
{
/*
 *	LogOut << "PlotChannelPointer::SeekToSample(" << SampleIndex << ")\n" ;
 */
	ChannelIndex Temp = GetPlot()->GetChannel(GetPlot()->GetBaseChannel())->
		ComputeSampleIndex( SampleIndex, GetNumerator(),GetDenominator(),0);
	int32 seek_to = Temp.Index * GetNumberElements() * size_of() ;
	// LogOut << "Seeking to " << seek_to << "\n" ;
	GetDataFile()->Seek(seek_to) ;
}

int32 PlotChannelPointer::ComputeDataAvailable(int16 Numerator,
	int16 Denominator)
{
/*
 *	LogOut << "PlotChannelPointer::ComputeDataAvailable(" <<
 *		Numerator << ", " << Denominator << ")\n" ;
 */

	TimingCorrection * Correction = TimingCorrections.GetLast();
	// compute samples since last timing correction
	// compute time interval for these samples
	// report the the difference of this time and base time
	int32 CurrentSample = PhysicalSampleIndex() ;
	if (GetNumberElements() > 1) CurrentSample = CurrentSample /
		GetNumberElements() ;
	int32 FractionalOffset = 0;
	if (Correction) {
		// LogMsg("Adjusting for TimingCorrection");
		CurrentSample +=  -Correction->PhysicalIndexOfNewBaseSample +
			Correction->NewBaseSampleIndex ;
		FractionalOffset = Correction->FractionalOffset >> 16 ;
	}
	ChannelIndex Temp = ComputeSampleIndex(CurrentSample, Numerator,
		Denominator, FractionalOffset);
	
	return Temp.Index ;
}

double PlotChannelPointer::GetAdjustedSampleRate() const 
{
/*
 *	LogOut << "Numerator = " << GetNumerator() << ", Denominator = "
 *		<< GetDenominator() << ", Adj = " << GetSampleRateAdjustment()
 *		<< "\n" ;
 *	LogOut << "GetSampleRate() = " << GetSampleRate() << "\n" ;
 */
/*
 *	LogOut << "GetAdjustedSampleRate(), adj = " << GetSampleRateAdjustment()
 *		<< ", Base = "  << GetBaseSampleRate() << "\n" ;
 */
	return GetSampleRateAdjustment() * GetBaseSampleRate();
}



/* 
 * int32 DataPlot::FirstSampleOnPlot()
 * {
 *  	return TimeToIndex(GetFirstSampleTime());
 * }
 */

void DataPlot::Init()
{
	Name = 0;
	the_window = 0 ;
	the_graph = 0 ;
	// TheWindow = 0;
	NextPlotPosition = 0;
	BasePixelIncrement = 0.0 ;
	// DataPlotHeader::Init();
	BaseChannelNumerator = BaseChannelDenominator = -1;
	// SampleIndexLastPlotUpdate = NotInitialized;
	NumberSamplesInPlot = 0;
	FirstBlockOnCurrentPlot = 0;
	SampleIndexLastPlotUpdate = -1;
	PixelWidth = 0;
	WarnedMoreData = 0;
	TheInputFile = 0 ;
	cloned_from = 0 ;
}


void PlotChannelPointer::Reset(double Time)
{
	// LogOut << "PlotChannelPointer::Reset Time = " <<  Time << "\n" ;
	NextBlockToPlot = (int32) (TimeToIndex(Time) / GetInputBlockSize()) ;
	NextSampleOffset = 0 ;
	// LogOut << "NextBlockToPlot = " << NextBlockToPlot << "\n" ;
	for (int i = 0 ; i < GetNumberElements() ; i++) 
		LastXPlotted[i] = LastYPlotted[i] = -very_big ;
	OldMaxYVal = MaxYVal ;
	OldMinYVal = MinYVal ;
	if (GetPlot()->is_eye_plot()) {
		OldMaxXVal = MaxXVal ;
		OldMinXVal = MinXVal ;
	}
		
}

void DataPlot::RefreshData()
{
	graph()->reset();
}

void DataPlot::Redraw()
{
	graph()->redraw_x();
	graph()->redraw_y();
	graph()->redraw();
}

void DataPlot::ResetData()
{
	if (!cloned_from) return ;
	if (GetNumberSamplesInPlot() < 1.) return ;
	graph()->do_damage();
	SampleIndexLastPlotUpdate = FirstBlockOnCurrentPlot * GetBlockSize() ;
	// LogOut << "DataPlot::ResetData SampleIndexLastPlotUpdate reset\n" ;
	graph()->reset();
	// UpdateDisplay();
}

void DataPlot::Reset()
{
	// LogOut << "DataPlot::Reset `" << GetCaption() <<"'\n" ;
	// LogOut << "Samples = " << GetNumberSamplesInPlot() << "\n" ;
	graph()->reset();
	SampleIndexLastPlotUpdate = FirstBlockOnCurrentPlot * GetBlockSize() ;
/*
 *	LogOut << "DataPlot::Reset, SampleIndexLastPlotUpdate(reset) = " <<
 *		SampleIndexLastPlotUpdate << "\n" ;
 */
/*
 *	if (SampleIndexLastPlotUpdate == NotInitialized)
 *		SampleIndexLastPlotUpdate = FirstBlockOnCurrentPlot ;
 */
	double TimeReset = IndexToTime(SampleIndexLastPlotUpdate);
/*
 *	LogOut << "DataPlot::Reset:\n" ;
 *	LogOut << "SampleIndexLast = " << SampleIndexLastPlotUpdate <<
 *		", FirstBlockOn = " << FirstBlockOnCurrentPlot <<
 *		", TimeReset = " << TimeReset << "\n" ;
 */
	for (int i = 0 ; i < GetNumberOfChannels();i++)
		GetChannel(i)->Reset(TimeReset);
	// SampleIndexLastPlotUpdate = FirstBlockOnCurrentPlot * GetBlockSize();
}

const char * DataPlot::GetCaption()
{
	// LogMsg("DataPlot::GetCaption");
	const char * Ret = DataPlotHeader::GetCaption();
/*
 *	if (Ret) LogMsg("Header caption is ",Ret);
 *	else LogMsg("No header caption");
 */
	if (!Ret) Ret = GetName();
	// LogMsg("Ret is ",Ret);
	return Ret ;
}

double DataPlot::GetBasePixelIncrement()
{
	if (BasePixelIncrement> 0.0) return BasePixelIncrement ;
	if (GetNumberSamplesInPlot() < 2) BasePixelIncrement = 16384 ;
	else BasePixelIncrement = 32767. / (GetNumberSamplesInPlot()-1);
/*
 *	LogForm("DataPlot::GetBasePixelIncrement, Pixels = %d, Number = %d: %d",
 *		GetPixelWidth(), GetNumberSamplesInPlot(), 
 *		(long) BasePixelIncrement);
 */
	return BasePixelIncrement;
}


double DataPlot::GetNumberSamplesInPlot()
{
	// NumberSamplesInPlot is determined by:
	// 1. Fixed scaling if specified
	// 2. Number of Samples In Plot if specified
	// 3. Number of Pixels in Plot

	if (NumberSamplesInPlot) return NumberSamplesInPlot ;

	AxisScalingX& BaseScaling = GetScaleX();
	// BaseScaling.Dump();
/*
 *	if (BaseScaling.Scale == PlotScaleFixed) {
 *		if (BaseScaling.Max - BaseScaling.Min <= 0.0) DbgError(
 *			"DataPlot::GetNumberSamplesInPlot", "scaling bad");
 *		TimeInPlot = BaseScaling.Max - BaseScaling.Min ;
 *	} else
 */

	if (BaseScaling.SamplesPerPlot>0.0) {
		NumberSamplesInPlot = BaseScaling.SamplesPerPlot ;
		return NumberSamplesInPlot ;
	} else {
		NumberSamplesInPlot = GetPixelWidth() ;
/*
 *		LogForm("ComputeDataAvailable returning %d",
 *			NumberSamplesInPlot);
 */
	}

	// Must normalize samples from this channel to common indexing base
	int BaseChannelForXScaling = GetScaleXBaseChannel();
	// LogForm("BaseChannelForXScaling = %d", BaseChannelForXScaling);
	PlotChannel * BaseChannel =
		(PlotChannel *) GetChannel(BaseChannelForXScaling);
	ChannelIndex TheIndex = BaseChannel->ComputeSampleIndex(
		NumberSamplesInPlot, GetNumerator(), GetDenominator());
	return NumberSamplesInPlot = TheIndex.Index ;
}
	

void DataPlot::ComputeBaseChannel()
{
	// Find channel with highest effective sample rate
	// this can be done by computing maximum ratio of
	// Numerator / Denominator

	// int BaseChannel = -1 ;
	int BaseChannel = -1 ;
	PlotChannel * HighPointer = 0;
	// double HighestRate = -1.0 ;
	double HighestRate = 0 ;
	for (int i = 0 ; i < GetNumberOfChannels();i++) {
		PlotChannel * Chan = (PlotChannel *) GetPlotChannel(i) ;
		double Denom = 1. ;
		int32 IntDenom = Chan->GetDenominator();
		if (IntDenom > 0) Denom = IntDenom ;
		double TestRate =
			((double)Chan->GetNumerator()) / Denom ;
		if (TestRate >= HighestRate) {
			HighestRate = TestRate ;
			BaseChannel = i;
			HighPointer = Chan ;
		}
	}
	if (!HighPointer) DbgError("DataPlot::ComputeBaseChannel",
		"no channels or bad data");
	SetScaleXBaseChannel(BaseChannel);
	BaseChannelNumerator = HighPointer->GetNumerator();
	BaseChannelDenominator = HighPointer->GetDenominator() ;
}

// All scaling regards the actual plot as being a rectangle of size
// 32767 x 32767 (Just as GKS does for the full screen) the values
// are scaled and Offset using infor in the PlotWindow structure

struct PlotInfo {
	double ScaleFactor ;
	enum ScaleType {ScaleShiftProd, ScaleShiftSample} TheScaleType ;
	int32 PixelIncrement ;
	int32 PixelBase ;
	PlotChannelPointer * plot_channel ;
	int16 Multiplexing ;
	MultiplexedElement * TheElements ;
	double Min ;
	double * PrevX ;
	double * PrevY;
	double MinY;
	double MaxY;
	int32 SamplesSkip ;

	PlotInfo() {plot_channel = 0;}
	PlotInfo(double fact, ScaleType scl_typ, int32 incr,
		int32 base, PlotChannelPointer * chan, int16 multiplex,
		MultiplexedElement * e,
		double Min, double * x, double * y,
		double min_y, double max_y, int32 skip = 0);
	void Dump();
	int16 channel() const {return plot_channel->GetChannelNumber();}
};

void PlotInfo::Dump()
{

	TheLog << "PlotInfo::Dump:Scale="
		<< ScaleFactor << ",PixIncr=," << PixelIncrement <<
		",PixBase=," << PixelBase << ",File=0x" << (void *) plot_channel
		<< "\n" ;
	TheLog << "ScaleType = " << TheScaleType << ", Min = " << Min <<
		", Multiplexing = " << Multiplexing << "\n" ;
	for (int i = 0 ; i < Multiplexing ; i++)
		TheLog << "PrefX[" << i << "] = " << PrevX[i] << ", PrevY[" <<
			i << "] = " << PrevY[i] << "\n" ;
}

PlotInfo::PlotInfo(double fact, ScaleType scl_typ, 
	int32 incr, int32 base, PlotChannelPointer * chan, int16 multiplexing,
	MultiplexedElement * e, double min, double * x, double * y,
	double min_y, double max_y,int32 skip):
		plot_channel(chan)
{
	// LogOut << "PlotInfo::ctor, skip = " << skip << "\n" ;
	ScaleFactor = fact;
	TheScaleType = scl_typ ;
	PixelIncrement = incr;
	PixelBase = base;
	Multiplexing = multiplexing ;
	TheElements = e ;
	PrevX = x;
	PrevY = y;
	Min = min ;
	// WinOvl = ovl ;
	MinY = min_y;
	MaxY = max_y ;
	SamplesSkip = skip * multiplexing ;
}


void DataPlot::CheckXYPlotBuffer()
{
	// LogOut << "CheckXYPlotBuffer, Next = " << NextPlotPosition << "\n" ;
	if (NextPlotPosition >= PlotBufferSize - 1) WriteXYPlotBuffer();
}

void DataPlot::CheckPlotBuffer()
{
	if (NextPlotPosition >= PlotBufferSize - 1) WritePlotBuffer();
}

void DataPlot::TwoSamplesLeft()
{
	if (NextPlotPosition >= PlotBufferSize - 3) WritePlotBuffer();
	// Make sure we do not try and plot a single point
	// LogForm("TwoSamplesLeft: NextPlotPosition = %d, PlotBufferSize = %d",
	//	NextPlotPosition, PlotBufferSize);
}


void DataPlot::PlotOnePoint(double Xpos, double Ypos, PlotInfo& Info)
{
	if (Xpos < 0) return ;
	double PlotY =  0;
	double BigPlotY ;
	double Diff ;
	switch (GetStreamType()) {
case PlotPairs:
		DbgError("DataPlot::PlotOnePoint","bad stream type");
/*
 *		CheckPlotBuffer();
 *		LogOut << "PlotBuffer[" << NextPlotPosition << "] = (" <<
 *			Info.WinOvl->X(Xpos) << ", " <<
 *			Info.WinOvl->Y(Ypos) << ") (" << Xpos << "," <<
 *			Ypos << ")\n" ;
 *		PlotBuffer[NextPlotPosition++] = Position(Info.WinOvl->X(Xpos),
 *				Info.WinOvl->Y(Ypos));
 */
		break ;
case PlotYs:
		switch (Info.TheScaleType) {
case PlotInfo::ScaleShiftProd:
			Diff =  Ypos - Info.Min ;
			BigPlotY = Diff * Info.ScaleFactor ;
			break ;
case PlotInfo::ScaleShiftSample:
			BigPlotY = Ypos * Info.ScaleFactor + Info.Min ;
			break ;
		}
		if (BigPlotY > AxisSize) PlotY = AxisSize ;
		else if (BigPlotY > 0) PlotY = BigPlotY ;
/*
 *		LogOut << "Ypos = " << Ypos << ", Info.Min = " << Info.Min  <<
 *			", Diff = " << Diff << ", PlotY = " << PlotY << "\n" ;
 *		LogOut << "Xpos = " << Xpos << "\n" ;
 *
 *		LogOut << "Plotting(" << Xpos << ", " << Ypos << ") = ("
 *			<< Xpos << ", " << PlotY << ")\n" ;
 */
		CheckPlotBuffer();
		if (PlotY < 0.) PlotY = 0. ;
		if (PlotY > 1.) PlotY = 1. ;
	 	PlotBuffer[NextPlotPosition++] = RelativePosition(Xpos,PlotY);
		break ;
	}
	CheckPlotBuffer();
}

void DataPlot::FetchAndPlotData(int32 FirstSampleIndex,
	int32 NumberSamples, PlotInfo& Info)
{
	current_channel=Info.channel() ;
/*
 *	LogOut << "FetchAndPlotData:First = " << FirstSampleIndex <<
 *		", Number = " << NumberSamples << "\n" ;
 */

	// Info.Dump();
	double LastX, LastY;
	if (!NumberSamples) return ;
	int32 Skip = Info.SamplesSkip ;
	// LogOut << "Info.SamplesSkip = " << Info.SamplesSkip << "\n" ;
	if (FirstSampleIndex < 0) {
		if (NumberSamples - FirstSampleIndex <= 1) return ;
		// Info.PixelBase += (-FirstSampleIndex)*Info.PixelIncrement;
		Skip += FirstSampleIndex * Info.Multiplexing ;
		NumberSamples += FirstSampleIndex ;
		FirstSampleIndex = 0 ;
/*
 *		LogOut << "NumberSamples = " << NumberSamples <<
 *			", PixelBase = " << Info.PixelBase << "\n" ;
 */
	}
	int32 NumberWords = NumberSamples * Info.Multiplexing ;
	while (NumberWords) {
		int32 FirstPlot ;
		int32 ToRead ;
		if (NumberWords > ReadBufferSize) ToRead = ReadBufferSize ;
		else ToRead = NumberWords ;
		int32 SamplesToRead = ToRead / Info.Multiplexing ;
		NumberSamples -= SamplesToRead ;
		if (NumberSamples == 1 && SamplesToRead > 2 ) {
			NumberSamples++ ;
			SamplesToRead-- ;
		} else if (SamplesToRead == 1 && NumberSamples > 2) {
			NumberSamples-- ;
			SamplesToRead++;
		}
		ToRead = SamplesToRead * Info.Multiplexing ;
		if (!ToRead) return ;
		NumberWords -= ToRead ;
		if (Skip < ToRead) {
			Info.plot_channel->convert_read(ToRead,ReadBuffer,
				FirstSampleIndex*Info.Multiplexing);
/*
 *			LogOut << "Read " << SamplesToRead << " samples (" <<
 *				ToRead << " words) at " << FirstSampleIndex
 *				<< "\n" ;
 */
		}

		FirstSampleIndex += SamplesToRead ;
		int32 PixelBase ;
		FirstPlot = 0 ;
		// LogOut << "Skip = " << Skip << "\n" ;
		if (Skip) {
			FirstPlot = Skip ;
			// LogOut << "SamplesSkip = " << Skip << "\n" ;
			Skip -= ToRead ;
			if (Skip > -1 ) continue ;
			else Skip = 0 ;
		}
/*
 *		LogOut << "Executing, ToRead = " << ToRead << ", FirstPlot = "
 *			<< FirstPlot << "\n" ;
 */
		for (int j =  0 ; j < Info.Multiplexing; j++) {
			if (NextPlotPosition < 2)
			    // LogOut << "WritePlotBuffer - j = " << j << "\n" ;
			WritePlotBuffer();
			current_element = j ;
			PixelBase = Info.PixelBase ;
			for (int i = FirstPlot + j ; i < ToRead;
				i+= Info.Multiplexing) {
				PlotOnePoint((LastX = PixelBase >> 15)/32767.,
					LastY=ReadBuffer[i], Info);
/*
 *				LogOut << "Plotted " << i << " : " << LastY << " at " << 
 *					PixelBase << "\n" ;
 */
				PixelBase += Info.PixelIncrement ;
			}
			WritePlotBuffer();
/*
 *			LogOut << "FirstSampleIndex = " <<  FirstSampleIndex
 *				<< ", LastX = " << LastX << ", LastY = " <<
 *				LastY << "\n" ;
 */

		}
		Info.PixelBase = PixelBase ;
	}
}

double DataPlot::RelVDCToTime(int32 Pos)
{
	double Base = IndexToTime(FirstBlockOnCurrentPlot /* GetBlockSize()*/) ;
/*
 *	LogOut << "FirstBlockOnCurrentPlot = " << FirstBlockOnCurrentPlot <<
 *		", Base = " << Base << "\n" ;
 */
	double Result = ( Pos * NumberSamplesInPlot / 32767. ) ;
	if (is_two_dimensional()) {
		Result = Base + Result /
		GetChannel(GetBaseChannel())->GetTimeFactor() ;
	}
	else return Base ;
	return Result ;
}

int32 DataPlot::TimeToVDCPosition(double Time)
{
	// converts time to PixelPosition on current plot
	// Pixel position is multiplied by 2^15 so it can be
	// used in accurate integer arithmetic
	// Assumes a full 32767 position width - result will
	// be scaled to current plot window

	double Base = IndexToTime(FirstBlockOnCurrentPlot) ;
	double Factor = 1. ;
	if (NumberSamplesInPlot) Factor = (Time-Base)/NumberSamplesInPlot ;
	double Result = Factor * 32767. *
		GetChannel(GetBaseChannel())->GetTimeFactor();
	int32 Return = ((int32) Result) << 15 ;
	return Return ;
}



void PlotChannelPointer::PlotBlockData(int32 IndexEnd)
{
/*
 *	LogOut << "PlotChannelPointer::PlotBlockData(" <<  IndexEnd <<
 *		")\n" ;
 */
	// Get block index
	double BaseBlockSize = GetPlot()->GetBlockSize() ;
	int32 BlockIndex = (int32)  NextBlockToPlot ;
	int32 FirstSampleIndex = BlockIndex * GetInputBlockSize();
	double BlockScaleFactor = GetInputBlockSize() / (double) BaseBlockSize ;

	// Get first sample index
	int32 FirstSample = FirstSampleIndex + NextSampleOffset ;

	// Get last sample index - do not go past end of block
	int32 LastBaseSample = IndexEnd - (int32) (BlockIndex * BaseBlockSize) ;
	// LogOut << "LastBaseSample = " << LastBaseSample << "\n" ;
	if (LastBaseSample < 0) return ;
	if (LastBaseSample > BaseBlockSize) LastBaseSample =
		(int32) BaseBlockSize ;
	int32 LastSample = (int32) (LastBaseSample * BlockScaleFactor) ;
/*
 *	LogOut << "LastSample = " << LastSample << ", ScalFac = " <<
 *		BlockScaleFactor << "\n" ;
 */

	int32 IndexEnd = FirstSampleIndex + LastSample ;
/*
 *	LogOut << "IndexEnd = " << IndexEnd << ", FirstSampleIndex = "
 *		<< FirstSampleIndex << "\n" ;
 *	LogOut << "BasePixelIncrement = " << GetPlot()->GetBasePixelIncrement()
 *		<< "\n" ;
 */
	int32 PixelIncrement = (int32) (GetPlot()->GetBasePixelIncrement() *
		BlockScaleFactor * 32768.) ;
	AxisScalingX& XScale = GetPlot()->GetScaleX() ;
	double TickIncrement = XScale.GetIncrementPerSample();
	
	int32 PixelBase = 0 ;
	double Min = XScale.GetMinimum();
	double Max = XScale.GetMaximum();
	int32 skip = 0 ;
	if (Min < Max) {
		double Offset = GetPlot()->GetBaseOffset() ;
		Offset =Offset * BlockScaleFactor + NextSampleOffset ;
		// LogOut << "Offset = " << Offset << "\n" ;
		if (Offset < 0) {
			skip = (int32) -Offset + 1 ;
			Offset += skip ;
		}
		PixelBase = (int32) (Offset * PixelIncrement+.5);

	}
	if (GetPlot()->cloned_from) SeekToSample(IndexEnd);
	DoPlotData(PixelBase,PixelIncrement,IndexEnd,skip);
}

int32 inline PlotToVDC(int32 Value)
{
	return (Value >> 1) + 16383 ; 
}

void DataPlot::PlotXYBuffer(int32 Size)
{
	// LogOut << "NextPlotPosition = " << NextPlotPosition << "\n" ;
	for (int i = 0 ; i < Size; i+= XYSampleSize) {
		CheckXYPlotBuffer();
/*
 *		LogOut << "Plotting " << i << ": (" << ReadBuffer[i] << ", " <<
 *			ReadBuffer[i+1] << ")\n" ;
 */
	    PlotBuffer[NextPlotPosition++] =
           	RelativePosition(graph()->x_rel(ReadBuffer[i]),
           		graph()->y_rel(ReadBuffer[i+1]));

	}
	WriteXYPlotBuffer();
}

void PlotChannelPointer::FetchAndPlotXYData(int32 Begin, int32 End)
{
	Begin *= XYSampleSize ;
	End  *= XYSampleSize ;
	DataPlot *TheDataPlot = GetPlot();
	double * ReadBuffer = TheDataPlot->GetReadBuffer();
	int32 BeginWord = Begin ; // * XYSampleSize ;
	int32 DataLeft = End - Begin  ;
	int32 Size = DataLeft ;
	if (Size > ReadBufferSize) Size = ReadBufferSize ;
	int32 Done = 0 ;
	while (DataLeft) {
		if (Size > DataLeft) Size = DataLeft ;
		convert_read(Size,ReadBuffer, BeginWord + Done) ;
/*
 *		for (int i = 0 ; i < Size; i++) LogOut << "XY[" <<
 *			BeginWord + Done + i << "] = " << ReadBuffer[i] << "\n" ;
 */
		TheDataPlot->PlotXYBuffer(Size);
		DataLeft -= Size ;
		Done += Size ;
	}
}

void PlotChannelPointer::PlotXYData(int32 IndexEnd)
{
	int32 FirstSampleIndex = NextBlockToPlot * GetInputBlockSize();
	FetchAndPlotXYData(FirstSampleIndex + NextSampleOffset, IndexEnd);
	NextBlockToPlot = IndexEnd / GetInputBlockSize() ;
	NextSampleOffset = IndexEnd - NextBlockToPlot * GetInputBlockSize() ;
}

void PlotChannelPointer::PlotData(double EndTime, double BaseIncrement)
{
/*
 *	LogOut << "PlotChannelPointer::PlotData(" << EndTime << "," << BaseIncrement
 *		<< ")\n" ;
 */
	int32 PixelIncrement = ((int32)
		(32768. * BaseIncrement * GetDenominator() /
		GetNumerator())) ;

	int32 PixelBase = GetPlot()->
		TimeToVDCPosition(IndexToTime(NextBlockToPlot));
	int32 index_end = (int32)(TimeToIndex(EndTime)+.999);
	if (GetPlot()->cloned_from) SeekToSample(index_end);
	DoPlotData(PixelBase,PixelIncrement,index_end);
}

void PlotChannelPointer::DoPlotData(int32 PixelBase, int32 PixelIncrement,
	int32 IndexEnd, int32 skip)
{
/*
 *	LogOut << "PlotChannelPointer::DoPlotData(" << PixelBase << ", " <<
 *		PixelIncrement << ", " << IndexEnd << "," << skip << ")\n" ;
 *	LogOut << "MaxYVal = " << MaxYVal << ", MinYVal = " << MinYVal
 *		<< ", Scale = " << GetScaleY().GetPlotScale() <<"\n" ;
 */

	if (MaxYVal == very_big) return; // No data yet on this channel
	double MaxV, MinV ;
	double MinY, MaxY ;
	// double PlotMinY, PlotMaxY ;
	switch (GetScaleY().GetPlotScale()) {
case PlotScaleFixed:
		// Actual scaling in this case is done before 
		// converting data to 16 bit integer format
		MinY = GetScaleY().GetMinimum();
		MaxY = GetScaleY().GetMaximum();
/*
 *		LogOut << "Fixed:MinY = " << MinY << ", MaxY = " << MaxY
 *			<< "\n" ;
 */
		MinV = MinY ;
		MaxV = MaxY ;
		break ;
case PlotScaleRangeAuto:
case PlotScaleAuto:
		MaxV = MaxYVal;
		MinV = MinYVal ;
		MinY = GetMinYVal();
		MaxY = GetMaxYVal();
		break ;
default:
		DbgError("PlotChannelPointer::PlotData","bad scale");
	}
	if (MinV > MaxV) {
		MinV = MaxV = 0;
		// LogOut << "******************** Chan MinV > MaxV\n" ;
	}
	if (MaxV == MinV) {
		if (MaxV <  very_big) MaxV = MaxV + 1 ;
		if (MinV > -very_big) MinV = MinV - 1 ;
		// LogOut << "******************** Chan MinV == MaxV\n" ;
	} 

	// LogOut << "MinV = " << MinV << ", MaxV = " << MaxV << "\n" ;
	static double const Log2  = .69314718056 ;
	double Diff = MaxV - MinV ;
	PlotInfo::ScaleType TheScaleType ;

	double MinPlotVal = MinV ;
	double ScaleFactor = 0. ;
	TheScaleType = PlotInfo::ScaleShiftProd ;
	double check = fabs(MaxV);
	if (fabs(MinV) > check) check = fabs(MinV);
	if (Diff > very_small) 
		if (fabs(MaxV) * 5.*ArithType::Accuracy[arith_type()] < Diff)
			ScaleFactor = 1./Diff ;
/*
 *	LogOut << "MinPlotVal = " <<
 *		MinPlotVal << ", TheScaleType = " << TheScaleType << "\n" ;
 *	LogOut << "Scale = " << ScaleFactor << ", Diff = " << Diff <<
 *		", check = " << check << ", Den = " <<
 *		GetDenominator() << ", Num = " << GetNumerator() << "\n" ;
 *
 *	LogOut << "PixelPase = " << PixelBase << "\n" ;
 *	LogOut << "NextBlockToPlot = " << NextBlockToPlot << "\n" ;
 *		LogOut << " IndexEnd = " << IndexEnd << "\n" ;
 */

	delete LastPlotInfo ;
	LastPlotInfo = new PlotInfo( ScaleFactor, TheScaleType,
		PixelIncrement, PixelBase, this, GetNumberElements(),
		GetMultiplexedElements(), MinPlotVal, LastXPlotted,
		LastYPlotted,MinY, MaxY, skip);

	// LastPlotInfo->Dump();
	int32 First = NextBlockToPlot * GetInputBlockSize() + NextSampleOffset ;
/*
 *	LogOut << "NextBlock = " << NextBlockToPlot << ", Size = " <<
 *			GetInputBlockSize() << ", Offset = " << NextSampleOffset << "\n" ;
 */
	GetPlot()->FetchAndPlotData(First, IndexEnd - First,*LastPlotInfo);
	NextBlockToPlot = IndexEnd / GetInputBlockSize() ;
	NextSampleOffset = IndexEnd - NextBlockToPlot * GetInputBlockSize() ;
}

void DataPlot::PlotXYData(int32 IndexEnd)
{
	double EndTime = IndexToTime(IndexEnd);
	for (int i = 0 ; i < GetNumberOfChannels(); i++)
		GetChannel(i)->PlotXYData(IndexEnd);
}

void DataPlot::PlotData(int32 IndexEnd)
{
	// LogOut << "DataPlot::PlotData(" << IndexEnd << ")\n" ;
	
	if (GetStreamType() == PlotPairs) {
		PlotXYData(IndexEnd);
		return ;
	}

	if (GetBlockSize() < 2) {
		double NormalizedBasePixel = GetBasePixelIncrement() *
			GetNumerator() / GetDenominator() ;
		double EndTime = IndexToTime(IndexEnd);
		// LogOut << "EndTime = "  << EndTime << "\n" ;
		for (int i = 0 ; i < GetNumberOfChannels(); i++)
			GetChannel(i)->PlotData(EndTime,NormalizedBasePixel);
	} else for (int i = 0 ; i < GetNumberOfChannels(); i++)
		GetChannel(i)->PlotBlockData(IndexEnd) ;

	// SampleIndexLastPlotUpdate = IndexEnd ;
}

void DataPlot::WriteXYPlotBuffer()
{
	 // LogOut << "WriteXYPlotBuffer entry\n" ;
	if (!NextPlotPosition) return ;
	if (NextPlotPosition >= PlotBufferSize) DbgError(
		"DataPlot::WriteXYPlotBuffer","Buffer too big");
	PlotBuffer[NextPlotPosition] = RelativePosition( -1, -1);
	// ThePlot->PlotMarkers(PlotBuffer);
	graph()->add_points(0,0,PlotBuffer);
	NextPlotPosition = 0;
	// LogOut << "WriteXYPlotBuffer exit\n" ;
}

void DataPlot::WritePlotBuffer()
{
	if (!NextPlotPosition) return ;
	if (NextPlotPosition < 2) {
		return ;
	}
	if (NextPlotPosition < 2) DbgError("DataPlot::WritePlotBuffer",
		"only one position");
	if (NextPlotPosition >= PlotBufferSize) DbgError(
		"DataPlot::WritePlotBuffer","Buffer too big");
	PlotBuffer[NextPlotPosition] = RelativePosition( -1, -1);
	// ThePlot->PlotLines(PlotBuffer);
	graph()->add_points(current_channel,current_element,PlotBuffer);
	NextPlotPosition = 0;
}

int PlotChannelPointer::IsRescalingNeeded()
{
	if (MaxYVal != OldMaxYVal) return 1;
	if (MinYVal != OldMinYVal) return 1;
	if (GetPlot()->is_eye_plot()) {
		if (MaxXVal != OldMaxXVal) return 1;
		if (MinXVal != OldMinXVal) return 1;
	}
	return 0;
}


int DataPlot::IsRescalingNeeded()
{
	for (int i = 0; i < GetNumberOfChannels();i++)
		if(GetChannel(i)->IsRescalingNeeded()) return 1;
	return 0;
}


int32 DataPlot::ComputeRegionToUpdate()
{
/*
 *	LogOut << "ComputeRegionToUpdate: SampleIndexLastPlotUpdate = "
 *		<< SampleIndexLastPlotUpdate << "\n" ;
 */
	for (int loop_count =0 ;;loop_count++) {
			// loop is for clones
		const LARGE_NUMBER = 0x7fffffff ;
		int32 MinSample = LARGE_NUMBER ;
		for (int i = 0 ; i < GetNumberOfChannels();i++) {
			// find maximum region that can be updated on all channels
			int32 LastSample = GetPlotChannel(i)->ComputeDataAvailable(
				GetNumerator(), GetDenominator()) ;
			if (LastSample < MinSample) MinSample = LastSample ;
		}
		if (MinSample == LARGE_NUMBER) MinSample = 0 ;
		LargestIndexAvailableToPlot = MinSample ;
		int32 NewSamplesToPlot = MinSample - SampleIndexLastPlotUpdate ;

		double SamplesInPlot = GetNumberSamplesInPlot() ;
		double SamplesLeftToPlot = SamplesInPlot ;
		if (SamplesInPlot > -1) {
			int32 SamplesAlreadyPlotted = SampleIndexLastPlotUpdate -
				FirstBlockOnCurrentPlot * GetBlockSize() ;
			SamplesLeftToPlot = SamplesInPlot-SamplesAlreadyPlotted;
			if (NewSamplesToPlot > SamplesLeftToPlot) NewSamplesToPlot =
				(int32) SamplesLeftToPlot ;
		}
		if (cloned_from && !loop_count) {
			// do seek to needed data to update min/max values
			// do not seek past largest available
			for (int i = 0 ; i < GetNumberOfChannels();i++) {
				long update = (int32) (
					SampleIndexLastPlotUpdate + SamplesLeftToPlot);
				if (update > LargestIndexAvailableToPlot)
					update = LargestIndexAvailableToPlot ;
				GetPlotChannel(i)->SeekToSample(update) ;
			}
			continue ;
		}
		
		return NewSamplesToPlot ;
	}
}

void DataPlot::UpdateDisplay()
{
	// DumpFull();
	if (!the_window->is_mapped()) return ;
	int32 NewSamples = ComputeRegionToUpdate();
	if (NewSamples<1) {
		// CheckNewPage();
		return ;
	}
	if (GetNumberSamples() - GetCurrentSample() < 2) return ;
	if (IsRescalingNeeded()) {
		the_graph->set_y_tick_spacing();
		if (is_eye_plot()) {
			the_graph->rescale_x();
		}
		Reset();
		Redraw();
		NewSamples = ComputeRegionToUpdate();
		// LogOut << "Rescaled, NewSamples = " << NewSamples << "\n" ;
	}
	int32 IndexFirstSample = 0 ;
	if (GetBlockSize()> 1) IndexFirstSample =
		(int32) (-GetBaseOffset() + .5) ;
	int32 EndSample = NewSamples + IndexFirstSample +
		SampleIndexLastPlotUpdate;
/*
 *	LogOut << "EndSample = " << EndSample << ", last update = " <<
 *		SampleIndexLastPlotUpdate << "\n" ;	
 */
	if (EndSample < SampleIndexLastPlotUpdate) return ;
	PlotData(EndSample);
	Redraw();
	if (!first_page_plotted) if (EndSample >= GetNumberSamplesInPlot()) {
/*
 *		LogOut << "Calling check_init from UpdateDisplay for `" <<
 *			GetCaption() << "'\n" ;
 */
		first_page_plotted= 1 ;
		DataPlot * plt ;
		DataPlotListIterator Next(clones);
		while(plt = Next()) plt->check_init();
	}
	// LogOut << "UpdateDisplay, EndSample = " << EndSample << "\n" ;
	SampleIndexLastPlotUpdate = EndSample ;
/*
 *	LogOut << "Exiting, SampleIndexlastPlotUpdate = " <<
 *			SampleIndexLastPlotUpdate << "\n" ;
 */
	the_graph->adjust_adjuster();
}

double DataPlot::RelVDCToX(int32 Pos)
{
	if (GetScaleX().IsTwoDimensionalPlot()) {
		double Base = GetScaleX().GetMinimum();
		double SampleIndex = ( Pos * NumberSamplesInPlot / 32767. ) ;
		double Return = Base + SampleIndex  ;
/*
 *		LogOut << "RelVDCToX(" << Pos << ")\n" ;
 *		LogOut << "Base = " << Base << "\n" ;
 *		LogOut << "SampleIndex = " << SampleIndex << "\n" ;
 */
		// LogOut << "Dyn = " << GetDynSampleRate() << "\n" ;
		double Result =
	    		DisplaySampleRateFactor( GetBaseChannel());
		Result *= GetChannel(GetBaseChannel())->GetInputBlockSize();
		return Return * Result ;
	}
	return RelVDCToTime(Pos) ;
}



void DataPlot::CheckNewPage()
{
/*
 *	LogForm(
 *	"CheckNewPage: LastUp = %d, First = %d, Number = %d, Largest = %d",
 *		SampleIndexLastPlotUpdate,FirstBlockOnCurrentPlot,
 *		NumberSamplesInPlot, LargestIndexAvailableToPlot);
 */

		
	if (SampleIndexLastPlotUpdate < FirstBlockOnCurrentPlot *
		GetBlockSize() + NumberSamplesInPlot) return ;
	long NewSamples = (long)
		(LargestIndexAvailableToPlot - NumberSamplesInPlot) ;
	if (NewSamples > 0 && !WarnedMoreData && HelpDo.ConfirmVisible()) {
		WarnedMoreData = 1 ;
		// TheWindowsManager->SuspendRedraw(OutputHelp);
		*Output + OutputHelp << "There are " << NewSamples <<
		" additional samples in " << GetName() << " to plot.\n";
		*Output <<
		"Click mouse button two anywhere in this window and then use\n";
		*Output <<
		    "the `Page Up', `Page Down', `Begin' (Ctrl-shift F5)\n" ;
		*Output <<
		    "and `End' (Ctrl-shift F6) keys to scan the data stream." ;
		// TheWindowsManager->ClearSuspendRedraw(OutputHelp) ;
		*Output << "\n";
	}
}

void DataPlot::PlotPage(int32 StartBlock)
{
	// LogOut << "PlotPage(" << StartBlock << ")\n" ;
	
	ComputeRegionToUpdate();
	if (StartBlock < 0) StartBlock = 0;
/*
 *	LogOut << "Largest = " << LargestIndexAvailableToPlot << ", BlkSz = "
 *		<< GetBlockSize() << "\n" ;
 */
	if (StartBlock >= LargestIndexAvailableToPlot/GetBlockSize()) {
/*
 *		LogOut << "StartBlock too large\n" ;
 *		LogOut << "LargestAvailable = " <<
 *			LargestIndexAvailableToPlot << ", BlockSize = " <<
 *			GetBlockSize() << "\n" ;
 */
		if (GetBlockSize() > 1) StartBlock-- ;
		else return ;
	}
	if (StartBlock > FirstBlockOnCurrentPlot &&
		LargestIndexAvailableToPlot * GetBlockSize() <=
		SampleIndexLastPlotUpdate) {
		return;
	}
	FirstBlockOnCurrentPlot = StartBlock ;
	// LogOut<<"FirstBlockOnCurrentPlot = " << FirstBlockOnCurrentPlot << "\n";
	Reset() ;
	UpdateDisplay();
	Redraw();
}

void DataPlot::PageUp()
{
	int32 Offset = 1 ;
	if (GetBlockSize() < 2) Offset = (int32) NumberSamplesInPlot ;
	PlotPage(FirstBlockOnCurrentPlot - Offset);
}

void DataPlot::PageDown()
{

	int32 Offset = 1 ;
	if (GetBlockSize() < 2) Offset = (int32) NumberSamplesInPlot ;
/*
 *	LogOut << "PageDown(), Offset = " << Offset << ", FirstBlock = " <<
 *		FirstBlockOnCurrentPlot << "\n" ;
 */
	PlotPage(FirstBlockOnCurrentPlot + Offset);
}

void DataPlot::PageStart()
{
	PlotPage(0);
}

void DataPlot::PlotThisPage()
{
	PlotPage(FirstBlockOnCurrentPlot);
}

void DataPlot::PageEnd()
{
	ComputeRegionToUpdate();
	int32 StartBlock ;
	if (GetBlockSize() < 2) StartBlock = LargestIndexAvailableToPlot -
		(int32) NumberSamplesInPlot ;
	else {
		StartBlock = LargestIndexAvailableToPlot/GetBlockSize();
		int32 Product = StartBlock* GetBlockSize() ;
		if (LargestIndexAvailableToPlot - Product < 3)
		StartBlock-- ;
	}
/*
 *	LogOut << "LargestIndexAvailableToPlot = " << LargestIndexAvailableToPlot
 *		<< ", GetBlockSize() = " << GetBlockSize() << "\n" ;
 *	LogOut << "DataPlot::PageEnd - PlotPage(" << StartBlock << ")\n" ;
 */
	PlotPage(StartBlock);
}


int32 DataPlot::GetPixelWidth()
{
	// LogOut << "DataPlot::GetPixelWidth()\n" ;
	if (!the_graph) return 0 ;
	if (PixelWidth) return PixelWidth ;
	PixelWidth = the_graph->get_plot_pixel_width();
	// LogOut << "PixelWidth = " << PixelWidth << "\n" ;
	if (PixelWidth < 0) DbgError("DataPlot::GetPixelWidth", "no pixel width");
	return PixelWidth ;
}

/*
 * int32 DataPlot::GetVDCWidth()
 * {
 *	// LogMsg("PlotWindow::GetVDCWidth()");
 *	// LogForm("GetPlot() = 0x%x", (long) GetPlot());
 *	int32 Return = GetPlot()->ScaleX(AxisSize);
 *	// LogForm("Returning %d",Return);
 *	return Return ;
 * }
 */

int DataPlot::NotComplete()
{
	if (GetNumberOfChannels() < 1) return 1 ;
	if (GetPlotChannelToSet() < GetNumberOfChannels()) return 1 ;
	for (int i = 0 ; i < GetNumberOfChannels(); i++) {
		if (GetPlotChannel(i)->NotComplete()) return 1 ;
	}
	return 0 ;
}

class DataFile * DataPlot::GetDataFile(int Channel)
{
	return GetPlotChannel(Channel)->GetDataFile();
}

void DataPlot::SendComplete()
{
	if (TheInputFile) {
		TheInputFile->CompleteReadPlot() ;
		TheInputFile = 0 ;
		return ;
	}
	PacketHeader Header = PlotPacketHeader(PacketWindowPlotControl,
		GetPlotIdentifier(), (int) PlotControlComplete );
	WriteSeg->WritePacket(Header) ;
	// LogForm("Send new plot header complete Id = %d",GetPlotIdentifier());
}

PlotChannelPointer * DataPlot::GetSamplingRatioBase() 
{
	return (PlotChannelPointer *) GetChannel(GetScaleXBaseChannel());
}

// This needs to be changed to support a user selectable scale base or
// to default to the largest scaling 
PlotChannelPointer * DataPlot::GetYScaleBase()
{
	return (PlotChannelPointer *) GetChannel(GetScaleXBaseChannel());
}

void PlotChannelPointer::Read(int Size,double * Data, long Where)
{
	convert_read(Size,Data,Where);
}

void PlotChannelPointer::WriteData(int Size,char * Data)
{
	GetDataFile()->WriteData(Size,Data);
}

DataFile * PlotChannelPointer::GetDataFile() 
{
	return the_data_file ;
}

void PlotChannelPointer::DoInit()
{
	// LogOut << "PlotChannelPointer::DoInit()\n" ;
	SampleRateAdjustment = 1. ;
	double SampleRate = ((PlotChannel *) this)->GetSampleRate();
	double AdjRate = GetAdjustedSampleRate() ;
/*
 *	LogOut << "SampleRate = " << SampleRate << ", AdjRate = "
 *		<< AdjRate << "\n" ;
 */
	if (AdjRate > 1.e-50) SampleRateAdjustment =
		 SampleRate / AdjRate ;
/*
 *	LogOut << "SampleRateAdjustment = " << SampleRateAdjustment
 *			<< "\n" ;
 */


	NextBlockToPlot = NextSampleOffset = NextDataToWrite = 0;

	OldMaxYVal = MaxYVal = -very_big ;
	OldMinYVal = MinYVal = very_big ;

	OldMaxXVal = MaxXVal = -very_big ;
	OldMinXVal = MinXVal = very_big ;

	LastXPlotted = new double[GetNumberElements()] ;
	LastYPlotted = new double[GetNumberElements()] ;
/*
 *	LogForm("PlotChannelPointed::DoInit: allocated %d spaces",
 *		GetNumberElements());
 */

	LastPlotInfo = 0 ;

	for (int i = 0 ; i < GetNumberElements(); i++) 
		LastXPlotted[i] = LastYPlotted[i] = -very_big ;
	// LogOut << "PlotChannelPointer::DoInit() exit\n" ;
}

void PlotChannelPointer::SetPlot(DataPlot * plt)
{
	// LogOut << "SetPlot enter\n" ;
	ThePlot = plt;
	OriginalScaleY = GetScaleY() ;
	// LogOut << "SetPlot exit\n" ;
}

/*
 * int PlotChannelPointer::ChangeYScale(int32 Y0,int32 Y1, int Expand)
 * {
 *	LogOut << "ChangeYScale(" << Y0 << ", " << Y1 << ", " << Expand
 *		<< ")\n" ;
 *	if (Y0 > Y1) {
 *		int32 Temp = Y0 ;
 *		Y0=Y1 ;
 *		Y1=Temp ;
 *	}
 *	// return GetScaleY().Rescale(Y0,Y1,GetMinYVal(), GetMaxYVal(), Expand);
 * }
 */

int PlotChannelPointer::RestoreOriginalYScaling()
{
	if (OriginalScaleY.Differ(GetScaleY())) {
		GetScaleY().SetScaling(OriginalScaleY);
		return 1;
	}
	return 0 ;
}

void DataPlot::Dump()
{
	DataPlotHeader::Dump();

	TheLog << "DataPlot::Dump, Name is :",Name?Name:"NULL\n";
	TheLog << "BsNum = " << BaseChannelNumerator << ", BsDen = "
		<< BaseChannelDenominator << ", LastPlot = " << 
		SampleIndexLastPlotUpdate << "\n" ;
	TheLog << "FirstInPlot = " << FirstBlockOnCurrentPlot <<
		", NumInPlot = " << NumberSamplesInPlot <<
		", PixInc = " << BasePixelIncrement << "\n" ;
}

void DataPlot::DumpFull()
{
	DataPlotHeader::DumpFull();
}

void DataPlot::GoToTime(double time)
{
	
	double block_size = GetBlockSize();
	if (block_size < 1.) block_size = 1. ;
	block_size *=block_size ;
	int32 Index = (int32) (time * GetSampleRate() *
			GetSampleRateAdjustment(GetBaseChannel())/block_size) ;
/*
 *	LogOut << "DataPlot::GoToTime(" << time << "), rate = " <<
 *		GetSampleRate() << ", Index = " << Index << "\n" ;
 *	LogOut << "Adjustment = " <<  GetSampleRateAdjustment(GetBaseChannel())
 *		<< "\n" ;
 */
	GoToSampleIndex(Index);
}

void DataPlot::GoToSampleIndex(int32 Index)
{
/*
 *	LogOut << "DataPlot::GoToSampleIndex(" << Index << "), largest = "
 *		<< LargestIndexAvailableToPlot << ", block size = " <<
 *		GetBlockSize() << "\n" ;
 */
	ComputeRegionToUpdate();
	double large = ((double) LargestIndexAvailableToPlot)/GetBlockSize();
	if (large-Index < 1)
		Index = (int32) (large -1) ;
	PlotPage(Index) ;
}

int DataPlot::GetCurrentSample()
{
	return FirstBlockOnCurrentPlot ;
}

double DataPlot::GetDynSampleRate()
{
	return GetChannel(GetBaseChannel())->GetSampleRate();
}

double DataPlot::GetSampleRateFactor()
{
	return GetChannel(GetBaseChannel())->GetSampleRateFactor();
}


int DataPlot::GetNumberSamples()
{
	ComputeRegionToUpdate();
	return LargestIndexAvailableToPlot ;
}

void DataPlot::DisplayAddress(const char * Name)
{
	/* obselete shold be remmoved */	
}

void DataPlot::ResetAfterScalingChange()
{
	// LogOut << "DataPlot::ResetAfterScalingChange()\n" ;
	NumberSamplesInPlot = 0;
	GetNumberSamplesInPlot(); // reinitialize
	the_graph->new_sample_width();

	BasePixelIncrement = 0.0 ;
	GetBasePixelIncrement() ; // reinitalize
}

int DataPlot::ChangeXScale(float min,float max ,int Expand)
{
/*
 *	LogOut << "ChangeXScale(" << min << ", " << max << "," << Expand <<
 *		")\n" ;
 */
 	if (PreviousScaleX.Differ(GetScaleX())) PreviousScaleX = GetScaleX();
	
	double Diff = max - min ;
	// if (Diff < 0) Diff = -Diff ;
	double NoSamples = GetNumberSamplesInPlot();
	int DidChange = GetScaleX().Rescale(min,Diff,Expand,GetPixelWidth(),
		GetSampleRate());
/*
 *	LogOut << "NoSamples = " << NoSamples << ", change = " << DidChange
 *		<< "\n" ;
 */
	if (DidChange) ResetAfterScalingChange();


	if (GetBlockSize() < 2) {
		int32 First = FirstBlockOnCurrentPlot ;
		if (Expand) FirstBlockOnCurrentPlot += (int32) (.5 + NoSamples * min );
		else FirstBlockOnCurrentPlot -= (int32) (.5 +
			GetScaleX().GetSamplesPerPlot() * min) ;

		if (FirstBlockOnCurrentPlot < 0) FirstBlockOnCurrentPlot = 0 ;

		// if (First != FirstBlockOnCurrentPlot) return 1 ;
	}
/*
 *	LogOut << "ChangeXScale - BlockSize = " << GetBlockSize() <<
 *		", First = " << FirstBlockOnCurrentPlot << "\n" ;
 */
	NoSamples = GetNumberSamplesInPlot() ;
	if (DidChange) {
			PlotPage(FirstBlockOnCurrentPlot);
			if (!PreviousScaleX.Differ(OriginalScaleX))
				PreviousScaleX = GetScaleX();
			the_graph->adjust_adjuster();
	}
	return DidChange ;
}


/*
 * int DataPlot::ChangeYScale(int32 Y0,int32 Y1,int Expand,int Channel)
 * {
 *	return GetPlotChannel(Channel)->ChangeYScale(Y0,Y1,Expand);
 * }
 */

int DataPlot::RestorePreviousXScaling()
{
	if (PreviousScaleX.Differ(GetScaleX())) {
		SetScaleX(PreviousScaleX);
		ResetAfterScalingChange();
		return 1;
	}
	return 0 ;
}
int DataPlot::RestoreOriginalXScaling()
{
	if (OriginalScaleX.Differ(GetScaleX())) {
		PreviousScaleX = GetScaleX();
		SetScaleX(OriginalScaleX);
		ResetAfterScalingChange();
		return 1;
	}
	return 0 ;
}

double DataPlot::GetAdjustedSampleRate(int Channel) const 
{
	return GetPlotChannel(Channel)->GetAdjustedSampleRate();
}

double DataPlot::GetSampleRateAdjustment(int Channel) const 
{
	return GetPlotChannel(Channel)->GetSampleRateAdjustment();
}

int DataPlot::RestoreOriginalYScaling(int Channel)
{
	return GetPlotChannel(Channel)->RestoreOriginalYScaling();
}

int DataPlot::RestoreOriginalScaling()
{
	int DidChange = RestoreOriginalXScaling();
	if (RestoreOriginalYScaling()) DidChange = 1 ;
	return DidChange;

}

void DataPlot::NewSampleRate(int Chan, double NewRate)
{
	DataPlot * plt;
	DataPlotListIterator Next(clones);
	while (plt = Next()) plt->NewSampleRate(Chan,NewRate);
/*
 *	LogOut << "DataPlot::NewSampleRate(" << Chan << " ," <<
 *		  NewRate << ")for `" << GetCaption() << "'\n" ;
 */

	if (Chan != GetBaseChannel()) {
		// LogOut<<"SetSample Rate not base channel " << Chan << "\n" ;
		return ;
	}
	if (GetPlotChannel(Chan)->AdjustSampleRate(NewRate)) {
		Reset();
		UpdateDisplay();
/*
 *		if (GetPlot()->IsVisible()) {
 *			ThePlot->SetXTickSpacing();
 *			((LabeledPlot *) ThePlot)->SetXTickOffsets();
 *			GetPlot()->Redraw();
 *		}
 */
	}
}

double DataPlot::GetBaseOffset()
{
/*
 *	LogOut << "DataPlot::GetBaseOffset for `" << GetCaption() << "'\n" ;
 *	LogOut << "OrigX = " << OriginalScaleX.GetMinimum() << ", min = "
 *		<< GetScaleX().GetMinimum() << "\n" ;
 */
	return (OriginalScaleX.GetMinimum() - GetScaleX().GetMinimum()) ; 
}

double DataPlot::GetCurrentAddress()
{
/*
 *	LogOut<< "DataPlot::GetCurrentAddress Current = " << GetCurrentSample()
 *		<< ", rate = " << GetSampleRate() << "\n" ;
 */
	return GetCurrentSample() / GetSampleRate() ;
}

double DataPlot::GetEndTime()
{
/*
 *	LogOut << "DataPlot::GetEndTime Number = " << GetNumberSamples()
 *		<< ", rate = " << GetSampleRate() << "\n" ;
 */
	return GetNumberSamples() / GetSampleRate() ;
}

void DataPlot::new_window_size()
{
	if (!the_graph) DbgError("DataPlot::new_window_size","no graph");
	int32 NewPixelWidth = the_graph->get_plot_pixel_width();
	if (NewPixelWidth > 2) PixelWidth = NewPixelWidth ;
	if (PixelWidth < 3) DbgError("DataPlot::new_window_size","too small");
}

void DataPlot::complete()
{
	new_window_size();
	SendComplete();
}

void DataPlot::set_window(ivWindow *win, Graph * gr)
{
	the_window = win ;
	the_graph  = gr ;
	if (!cloned_from) gr->send_complete_after_draw();
	// new_window_size();
}

int DataPlot::is_eye_plot()
{
	if (GetStreamType() == PlotPairs) return 1 ;
	return 0 ;
}

double DataPlot::GetMinYVal() const
{
	if (!GetThePlotChannels()) return 0.0 ;
	double MinVal = very_big ;
	for (int i = 0 ; i < GetNumberOfChannels() ; i++) {
			double temp = GetPlotChannel(i)->GetMinYVal();
			if (temp < MinVal) MinVal = temp ;
	}
	return MinVal ;
}

double DataPlot::GetMaxYVal() const
{
	if (!GetThePlotChannels()) return 0.0 ;
	double MaxVal = -very_big ;
	for (int i = 0 ; i < GetNumberOfChannels() ; i++) {
			double temp = GetPlotChannel(i)->GetMaxYVal();
			if (temp > MaxVal) MaxVal = temp ;
	}
	return MaxVal ;
}

double DataPlot::GetMinXVal() const
{
	if (!GetThePlotChannels()) return 0.0 ;
	double MinVal = very_big ;
	for (int i = 0 ; i < GetNumberOfChannels() ; i++) {
			double temp = GetPlotChannel(i)->GetMinXVal();
			if (temp < MinVal) MinVal = temp ;
	}
	return MinVal ;
}

double DataPlot::GetMaxXVal() const
{
	if (!GetThePlotChannels()) return 0.0 ;
	double MaxVal = -very_big ;
	for (int i = 0 ; i < GetNumberOfChannels() ; i++) {
			double temp = GetPlotChannel(i)->GetMaxXVal();
			if (temp > MaxVal) MaxVal = temp ;
	}
	return MaxVal ;
}

double DataPlot::get_min_x_current_plot()
{
	// LogOut<<"get_min_x_current_plot(), 2-D = " << is_two_dimensional()<<"\n";
	double Result ;
	if (!GetThePlotChannels()) return 0.0 ;
	if (is_two_dimensional()) {
/*
 *		LogOut << "Adj = " << GetAdjustedSampleRate(GetBaseChannel()) <<
 *				", Min = " << GetScaleX().GetMinimum() << ", return = " <<
 *				GetAdjustedSampleRate(GetBaseChannel()) *
 *				GetScaleX().GetMinimum() << "\n" ;
 */
		Result = GetAdjustedSampleRate(GetBaseChannel()) *
			GetScaleX().GetMinimum() ;
		return Result ;
	}
	double RateFactor = GetSampleRateAdjustment(GetBaseChannel());
	if (RateFactor < 1.e-50) RateFactor = 1. ;
	Result =  IndexToTime(FirstBlockOnCurrentPlot);
/*
 *	LogOut << "RateFactor = " << RateFactor << ", First = " <<
 *		FirstBlockOnCurrentPlot << ", time = " << Result << ", Return = "
 *		<< Result / RateFactor << "\n" ;
 */
		
	// return Result / RateFactor ;
	return Result  ;
}

double DataPlot::get_max_x_current_plot()
{
	double Result ;
	if (!GetThePlotChannels()) return 0.0 ;
	if (is_two_dimensional()) {
		Result =  GetAdjustedSampleRate(GetBaseChannel()) *
			GetScaleX().GetMaximum() ;
		return Result ;
	}
	double RateFactor = GetSampleRateAdjustment(GetBaseChannel());
	if (RateFactor < 1.e-50) RateFactor = 1. ;
	Result = 
		IndexToTime(FirstBlockOnCurrentPlot+GetNumberSamplesInPlot()-1);
	return Result ;
}

int DataPlot::is_two_dimensional()
{
	return GetScaleX().IsTwoDimensionalPlot();
}

double PlotChannelPointer::GetBaseSampleRate() const
{
	double Numerator = GetNumerator() ;
	if (Numerator > 1.e-50) {
/*
 *		LogOut << "GetBaseSampleRate returning " << ((double) 
 *			GetDenominator()) / Numerator << "\n" ;
 */
		return ((double) GetDenominator()) / Numerator ;
	}
	return 1. ;
}

int PlotChannelPointer::AdjustSampleRate(double NewRate)
{
/*
 *	LogOut << "PlotChannelPointer::NewSampleRate(" << NewRate << ")\n" ;
 *	LogOut << "BaseRate = " << GetBaseSampleRate() << ", Current = "
 *		<< SampleRateAdjustment << "\n" ;
 */
	if (GetBaseSampleRate() * SampleRateAdjustment == NewRate ) return 0 ;
	if (GetBaseSampleRate() < 1.e-50 || NewRate < 1.e-50) return 0 ;
	SampleRateAdjustment = NewRate / GetBaseSampleRate() ;
 	// LogOut << "new SampleRateAdjustment = " << SampleRateAdjustment <<"\n";
	return 1 ;
}


void PlotChannelPointer::Dump()
{
	PlotChannel::Dump();
	TheLog << "NextPlot = " << NextBlockToPlot << " * BlockSize + " <<
		NextSampleOffset << ", NextWrite = " <<
		NextDataToWrite << "\n" ;
	for (int i = 0 ; i < GetNumberElements(); i++)
		TheLog << "LastX[" << i << "] = " << LastXPlotted[i] << 
		", LastY[" << i << "] = " << LastYPlotted[i] << "\n" ;
	
	TheLog << "Min (old) = " << MinYVal << " (" << OldMinYVal << "), " <<
		MaxYVal <<  " (" << OldMaxYVal << ")\n" ;
	TheLog << "Index = " << Index << ", ThePlot = 0x" <<
		(long) GetDataFile() << "\n" ;
 
}

void PlotChannelPointer::DumpFull()
{
	PlotChannel::DumpFull();
}

int PlotChannelPointer::size_of() const 
{
	// LogOut << "arith_type = " << arith_type() << "\n" ;
	return DspApplication::size_of(arith_type());
}

int PlotChannelPointer::convert_read(int Size, double * data, long where )
{
	// LogOut << "convert_read(" << Size << ",, " << where << ")\n" ;
	int size_word = size_of();
	if (where>0) where *= size_word ;
	int byte_size = size_word * Size ;
	char * temp_buf = new char[byte_size] ;
	int read = GetDataFile()->Read(byte_size,temp_buf,where);
	if (read !=  byte_size) 
		DbgError("PlotChannelPointer::convert_read","bad read");

	ArithType::ArithTypes type = arith_type();
	const char * source = temp_buf ;
	for (int i = 0 ; i < Size; i++,source+=size_word) {
		data[i] = DspApplication::convert_to_double(source,type);
		// LogOut << "data[" << i << "] = " << data[i] << "\n" ;
	}
	delete temp_buf ;
	// LogOut << "exit convert_read\n" ;
	return Size ;
}

#include "pltclr.h"

static int LineTableSize = 0 ;

static void Init()
{
	for (LineTableSize=0;LineTypeTable[LineTableSize];LineTableSize++);
}

static int ConvertColor(int Color)
{
	for (int i = 0 ; ColorTable[i] > -1; i++)
		if (Color==ColorTable[i]) return i;
	DbgError("ConvertColor","unknown color");
	return -1;
}

static int ConvertLineType(int LineType)
{
	for (int i = 0 ; LineTypeTable[i] > -1; i++)
		if (LineType==LineTypeTable[i]) return i;
	DbgError("ConvertLineType","unknown type");
	return -1;
}


static int TypeTable(int Type, int Color)
{
	if (!LineTableSize) Init();
	return LineTypeTable[(
		ConvertLineType(Type) + ConvertColor(Color)) % LineTableSize] ;
}

void DataPlot::adjust_adjuster()
{
	the_graph->adjust_adjuster();
	clones.adjust_adjuster();
}

void DataPlotList::adjust_adjuster()
{
	DataPlotListIterator next(*this);
	DataPlot *plt ;
	while (plt = next()) plt->adjust_adjuster();
}

void MultiplexedElement::SetPlotLineType(Screen * scr)
{
/*
 *	if (!scr->IsColorCapable()) {
 *		scr->SetLineType(TypeTable(LineType,Color));
 *		return ;
 *	}
 *	scr->SetLineType(LineType);
 *	scr->SetLineColor(Color);
 */
}


