/*  plotmgr.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include "iv_graph.h"

#include "newaloc.h"

#include "shared.h"
#include "remcom.h"
#include "xdrv.h"
#include "dsp_app.h"
// #include "winpres.h"
#include "wfiles.h"
#include "coord.h"
// #include "plot.h"
#include "baseio.h"

#include "plotdatg.h"

// void TestAlloc(const char * Msg=0);

PlotManager * ThePlotsManager ;

// This is the only member of DataPlotHeader not defined in the
// common file plotdat.h - it needs to be different for Dsp and Gui
// because we have a devrived class in Gui that contains additional
// information for PlotChannel

double PlotChannelPointer::GetSampleRateFactor()
{
	double SampleRateFactor = 1.0 ;
	double tmp ;
	if (tmp = PlotChannel::GetSampleRateFactor() != 0.0)
		SampleRateFactor = tmp * GetSampleRate();
	if (SampleRateFactor == 0.0) {
		SampleRateFactor = 1.0;
/*
 *		LogOut << "PlotChannelPointer::GetSampleRateFactor 0!: rt = "
 *			<< GetSampleRate() << ", X.Rate = " << tmp << "\n" ;
 */
			
	}
	// LogOut << "SampleRateFactor = " << SampleRateFactor << "\n" ;
	return SampleRateFactor;
}

double PlotChannelPointer::GetTimeFactor()
{
	return GetSampleRateFactor();
}


double PlotChannelPointer::TimeToIndex(double Time)
{
/*
 *	LogOut << "PlotChannelPointer::TimeToIndex Num = " << GetNumerator()
 *		<< ", Denum = " << GetDenominator() << "\n" ;
 *	LogOut << "First = " << GetFirstSampleTime() << "\n" ;
 */
	double RateFactor = GetSampleRateAdjustment();
    if (RateFactor < 1.e-50) RateFactor = 1. ;
	// LogOut << "RateFactor = " << RateFactor << "\n" ;
	double Return  = (Time  - GetFirstSampleTime()/RateFactor) *
		GetAdjustedSampleRate() ;
/*
 *	LogOut << "PlotChannelPointer::TimeToIndex(" << Time << ") = "
 *		<< Return << "\n" ;
 */
	return Return ;
}

double PlotChannelPointer::IndexToTime(double Index)
{
/*	
 *	LogOut << "PlotChannelPointer::IndexToTime(" << Index << ") :First=" <<
 *		GetFirstSampleTime() << ", Num = " << GetNumerator() <<
 *		", Den = " << GetDenominator() << "\n" ;
 */
	// LogOut << "GetTimeFactor() = " << GetTimeFactor() << "\n" ;
	// double Return = GetFirstSampleTime() + Index / GetTimeFactor();
	double RateFactor = GetSampleRateAdjustment();
    if (RateFactor < 1.e-50) RateFactor = 1. ;

	double Return = GetFirstSampleTime() / RateFactor + Index /
		GetAdjustedSampleRate();
/*
 *	LogOut << "PlotChannelPointer::IndexToTime(" << Index << ") = "
 *		<< Return << "\n" ;
 */
	return Return ;
}

int32 PlotChannelPointer::ThisChannelIndex(int32 BaseChannelIndex)
{
	return (int32) TimeToIndex(GetPlot()->IndexToTime(BaseChannelIndex));
}

int32 PlotChannelPointer::PhysicalSampleIndex()
{
	// LogOut << "PlotChannelPointer::PhysicalSampleIndex() enter\n" ;
	if (!GetDataFile()) return 0;
	long Return  = (GetDataFile()->GetNextByteToWrite() / size_of() );
	// LogForm("PlotChannelPointer::PhysicalSampleIndex = %d", Return);
	return Return ;
}

void PlotChannelPointer::UpdateData(int32 ByteSize, const char * PlotDataBlock)
{
	GetDataFile()->WriteData(ByteSize, PlotDataBlock);

    int size_word = size_of();
	int data_size = ByteSize / size_word ;
    if (data_size * size_word !=  ByteSize)
        DbgError("PlotChannelPointer::UpdateData","bad size");

	// LogOut << "PlotChannelPointer::UpdateData(" << ByteSize << ",)\n" ;
    ArithType::ArithTypes type = arith_type();
	const char * source = PlotDataBlock ;
    for (int i = 0 ; i < data_size; i++,source+=size_word) {
        double val = DspApplication::convert_to_double(source,type);
		UpdateMax(i,val);
	}
/*
 *	if (MinYVal != OldMinYVal || MaxYVal != OldMaxYVal) LogOut <<
 *		"Changed min max in " << GetPlot()->GetCaption() <<
 *		" " << MinYVal << ":" << MaxYVal << " " << OldMinYVal << ":"
 *		<< OldMaxYVal << "\n" ;
 *	LogOut << "y: (" << MinYVal << ":" << MaxYVal << "), x: (" << MinXVal <<
 *		":" << MaxXVal << ")\n" ;
 */
}

void PlotManager::AddRemotePlot(int Size, const char * PlotDescription,
	DataPlot::Transform tr)
{
	if (Size != sizeof(StrDataPlotHeader)) DbgError(
		"PlotManager::AddRemotePlot","bad size");
	if (PlotToComplete) DbgError("PlotManager::AddRemotePlot",
		"Existing PlotToComplete");

	PlotToComplete = new DataPlot(*((StrDataPlotHeader *) PlotDescription),tr);
/*
 *	LogOut << "DataPlot * ThePlotToComplete = 0x" <<
 *		hex((long)PlotToComplete) << "\n" ;
 */
	// PlotToComplete->Dump();
	// PlotToComplete->Dump();
}


void PlotManager::AddRemotePlotName(int Size,const char * Data)
{
	// LogMsg("Plot Name is ", Data) ;
	if (!PlotToComplete) DbgError("PlotManager::AddRemotePlotName",
		"no plot");
	if (PlotToComplete->GetName()) DbgError(
		"PlotManager::AddRemotePlotName","plot has name");
	if (Data[Size-1]) DbgError("PlotManager::AddRemotPlotName",
		"string is not Null terminated");
	char * Buf = new char [Size];
	strcpy(Buf,Data);
	((DataPlot *) PlotToComplete)->AddName(Buf) ;
}

void PlotManager::AddRemotePlotCaption(int Size,const char * Data)
{
	// LogMsg("Plot caption is ", Data) ;
	if (!PlotToComplete) DbgError("PlotManager::AddRemotePlotCaption",
		"no plot");
	if (PlotToComplete->GetCaption()) DbgError(
		"PlotManager::AddRemotePlotCaption","plot has caption");
	if (Data[Size-1]) DbgError("PlotManager::AddRemotPlotCaption",
		"string is not Null terminated");
	char * Buf = new char [Size];
	strcpy(Buf,Data);
	((DataPlot *) PlotToComplete)->SetCaption(Buf);
}

void PlotManager::AddRemotePlotChannel(int Size,
	const char * PlotChannelDescription)
{
/*
 *	LogOut << "PlotManager::AddRemotePlotChannel, Size = " <<
 *		Size << "\n" ;
 */
	if (Size != sizeof(StrPlotChannel)) DbgError(
		"PlotManager::AddRemotePlotChannel","bad size");
	if (!PlotToComplete) DbgError("PlotManager::AddRemotePlotChannel",
		"no plot to add to");
	// ((PlotChannel *) PlotChannelDescription)->Dump();
	PlotToComplete->SetPlotChannel(*((StrPlotChannel *)
		PlotChannelDescription)) ;
}

void PlotManager::AddRemoteLabelParameter(int Size,
	const char * PlotLabelParameterDescription)
{
	if (!PlotToComplete) DbgError("PlotManager::AddRemoteLabelParameter",
		"no plot to add to");
	char * LabelDesc = 0;
	if (Size) {
		LabelDesc = new char[Size];
		MoveNBytes(LabelDesc,PlotLabelParameterDescription,Size);
	}
	PlotToComplete->SetLabelParameter(Size, LabelDesc) ;
}

void PlotManager::AddRemoteMultiplexedElement (int Size,
	const char * PlotMultiplexedElementDescription)
{
	if (Size != sizeof(StrMultiplexedElement)) DbgError(
		"PlotManager::AddRemoteMultiplexedElement","bad size");
	if (!PlotToComplete) DbgError(
		"PlotManager::AddRemoteMultiplexedElement","no plot to add to");
	PlotToComplete->SetMultiplexedElement(
		*((StrMultiplexedElement *)PlotMultiplexedElementDescription));
	// ((MultiplexedElement *)PlotMultiplexedElementDescription)->Dump();
}



void PlotManager::UpdateControl(int PlotId,int Chan, int Size,
	const char * Data, int )
{
	// PlotId 0 is reserved for global control such as
	// requesting a PlotId for a new plot
/*
 * 	LogForm("PlotManager::UpdateControl: PlotId = %d, Chan = %d, Size = %d",
 *		PlotId,Chan,Size);
 */

	if (!PlotId) switch (Chan) {
case PlotControlGetId:
		{
			int16 NewId = GetPlotId();
			PacketHeader Header = PlotPacketHeader(
				PacketWindowPlotControl, PlotGlobalCommand,
				(int) PlotControlSendId, sizeof(NewId));
			// LogForm("Send new plot Id = %d", NewId) ;
			WriteSeg->WritePacket(Header, (char *) &NewId) ;
			// LogForm("Sent new plot Id = %d", NewId) ;
			break ;
		}
default:
		DbgError("PlotManager::UpdateControl","bad control option");
	} else {
/*
 *		*Output + OutputHelp << "At PlotManager Action " << Chan <<
 *			" calling MouseLoopKernel(-40)\n" ;
 *		TheWindowsManager->MouseLoopKernel(-40);
 */
		// ReturnToContinue(OutputPrompt);
		// Plot Id specific control options
		switch (Chan) {
case PlotControlHeader:
			AddRemotePlot(Size, Data) ;
			break ;
case PlotControlCaption:
			AddRemotePlotCaption(Size, Data) ;
			break ;
case PlotControlName:
			AddRemotePlotName(Size, Data) ;
			break ;
case PlotControlChannel:
			AddRemotePlotChannel(Size, Data) ;
			break ;
case PlotControlElement:
			AddRemoteMultiplexedElement (Size, Data);
			break ;
case PlotControlLabelParameter:
			AddRemoteLabelParameter(Size, Data) ;
			break ;
case PlotControlComplete:
			// LogOut << "case PlotControlComplete\n" ;

			if (PlotToComplete->NotComplete())
				DbgError("Update::Control",
				"complete message and plot not complete");
			PlotToComplete->InitPlotChannels();
/*
 *			LogOut << "Plot " <<
 *				PlotToComplete->GetPlotIdentifier() <<
 *				" completed\n" ;
 */
			TheCurrentPlots.Append(PlotToComplete);
			DspApplication::root_window()->create_plot(PlotToComplete);
			// TheWindowsManager->CreatePlot(PlotToComplete) ;
			PlotToComplete = 0 ;
			// PlotToComplete->DumpFull();
			break ;
case PlotControlNewSampleRate:
			// LogOut << "case PlotControlNewSampleRate\n" ;
			DataPlot * ToSet = GetPlot(PlotId);
			if (!ToSet) {
/*
 *				LogOut << "PlotControlNewSampleRate no plot "
 *					<< PlotId << ".\n" ;
 */
				break ;
			}
			if (Size != sizeof(int) + sizeof(double))
				DbgError("PlotManager::UpdateControl",
					"rate bad size");
			int Channel ;
			double NewRate ;
			MoveNBytes((char *) &Channel,Data,sizeof(int));
			MoveNBytes((char *) &NewRate,
				sizeof(int) + Data, sizeof(double));
			ToSet->NewSampleRate(Channel, NewRate);
			break ;
case PlotControlRaiseWindow:
			// LogOut << "TheCurrentPlots.raise_window(" << PlotId << ")\n" ;
			TheCurrentPlots.raise_window(PlotId);
			break ;
default:
			DbgError("PlotManager::UpdateControl","bad type");

		}
	}
	// LogOut<< "Exit PlotManager::UpdateControl\n" ;
}


DataPlot * PlotManager::GetPlot(int16 PlotId)
{
	DataPlotListIterator Next(TheCurrentPlots);
	DataPlot * TestPlot ;
	while (TestPlot = Next()) if (TestPlot->GetPlotIdentifier()==PlotId)
		return TestPlot ;
	return 0;
}

void PlotManager::UpdateData(int PlotId, int Channel, int Size,
		const char * PlotDataBlock, int NextChannel)
	{
/*
 *		LogOut << "PlotManager::UpdateData, Id = " << PlotId <<
 *			", Channel = " << Channel << ", Size = " << Size
 *			<< "\n" ;
 */
		DataPlot * ThePlot = GetPlot(PlotId);
		if (!ThePlot) DbgError("PlotManager::UpdateData","bad plot Id");
		PlotChannelPointer * TheChannel =
			ThePlot->GetChannel(Channel);
/**
 **		float * Temp = (float *) PlotDataBlock ;
 **		int size = Size /sizeof(float);
 **		for (int i = 0 ; i < size ; i++) {
 **			ThePlot->graph()->AddPt(ThePlot->position(),Temp[i]);
 **		}
 **/
		if (!TheChannel)DbgError("PlotManager::UpdateData","bad channel index");
		TheChannel->UpdateData(Size,PlotDataBlock);
		ThePlot->UpdateDisplay() ;	
		ThePlot->adjust_adjuster();
}


void PlotManager::PlotServer (PacketHeader& Head,const char * Data,
	int32 NextWindow)
{
	// TestAlloc("plot server enter");
	PacketType Type = (PacketType) Head.ThePacketType ;
	int PlotId = Head.GetPlotId();
	int Channel = Head.GetPlotChannel();
/*
 *	LogForm("PlotManager::PlotServer, Type = %d, PlotId = %d, Channel = %d",
 *		Type, PlotId, Channel);
 */
	// if (PlotToComplete) PlotToComplete->DumpFull();

	int32 Size = Head.DataSize ;
	if (Size < 0) Size = - Size ;

	int NextChannel = -1 ;
	if (NextWindow > 0) if ((NextWindow >> 16) == PlotId)
		NextChannel = NextWindow & 0xffff ;
	if (Type == PacketWindowPlotData) UpdateData(PlotId,Channel,Size,
		Data,NextWindow);
	else if (Type == PacketWindowPlotControl) UpdateControl(PlotId,Channel,
		Size,Data,NextChannel);
	else DbgError("PlotManager::PlotServer", "bad packet type");
	// TestAlloc("plot server exit");
}

PlotManager::~PlotManager()
{
	// LogOut << "delete PlotManager called\n" ;
	DataPlot * plt ;
	while (plt = TheCurrentPlots.Get()) {
		delete plt ;
	}
}

void DataPlotList::raise_window(int plot_id)
{
	DataPlotListIterator Next(*this);
	DataPlot * plot ;
	while (plot = Next()) {
/*
 *		LogOut << "Checking plot " << plot->GetPlotIdentifier() <<
 *			", caption is:\n" <<
 *			plot->GetCaption() << "\n" ;
 */
		if(plot_id == plot->GetPlotIdentifier()) {
			// LogOut << "raising window for " << plot_id << "\n" ;
			plot->raise_window();
			return ;
		}
	}
	// LogOut << "plot " << plot_id << " not found.\n" ;
}
