/*  plotfile.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#include "sysintfc.h"
#include "sysconst.h"
#include "plotdatg.h"
// #include "labplot.h"
#include "shared.h"
#include "plotfile.h"
#include "wfiles.h"
#include "copyright.h"

PlotFileManager ThePlotFileManager ;

PlotFileManager::PlotFileManager()
{
	OutFile = InFile = 0 ;
	InChannels = OutChannels = 0 ;
	InChannelSize = OutChannelSize = 0 ;
	InPlotId = 0 ;
}

int PlotFileManager::GetPlotId()
{
	return 0;
}

int PlotFileManager::WritePacket(PacketHeader& Head, const char * Data)
{
	if (OutFile < 1) DbgError("PlotFileManager::WritePacket","bad file id");
	if (!Write((char *) &Head, sizeof(Head))) return 0 ;
	if (Head.DataSize) if (!Write(Data,Head.DataSize)) return 0 ;
	return 1 ;
}

int PlotFileManager::ReadPacket(PacketHeader& Head, char * Data)
{
	if (InFile < 1) DbgError("PlotFileManager::ReadPacket","bad file id");
	if (!Read((char *) &Head, sizeof(Head))) return 0 ;
	if (Head.DataSize) if (!Read(Data,Head.DataSize)) return 0 ;
	return 1 ;
}


int PlotFileManager::Write(const char * Data, int Size)
{
	int WriteLength = write(OutFile,Data,Size);
	if (WriteLength == Size) return 1 ;
	*Output + OutputHelp << "Error in writing file for plot data.\n"
		<< "Plot write aborted.\n" ;
	close(OutFile);
	OutFile = 0 ;
	return 0;
}

void PlotFileManager::ReadError()
{
	*Output + OutputHelp << "Error reading plot file.\n" <<
		"Plot file read aborted.\n" ;
	close(InFile);
	InFile = 0 ;
}

int PlotFileManager::Read(char * Data, int Size)
{
	int ReadLength = read(InFile,Data,Size);
	if (ReadLength == Size) return 1 ;
	ReadError();
	return 0;
}


int PlotFileManager::WritePrologue(DataPlot& ThePlot)
{
	if (!Write(AddCopyright::plot_file_prologue,
		strlen(AddCopyright::plot_file_prologue))) return 0;

	// Write 2 32 bit words - first gives number of channels
	//	second gives bytes in each channel

	const BIG = 0x7fffffff ;
	OutChannelSize = BIG ;

	PlotChannelPointer * ThisChannel ;
	for (int Channels = 0; ThisChannel = ThePlot.GetChannel(Channels) ;
		Channels++) {
		DataFile * Fle = ThisChannel->GetDataFile();
		int32 LocalEnd = Fle->GetNextByteToWrite();
		if (LocalEnd < OutChannelSize) OutChannelSize = LocalEnd ;
	}
	// LogOut << "OutChannelSize = " << OutChannelSize << "\n" ;
	if (!OutChannelSize || OutChannelSize == BIG) {
		*Output + OutputHelp <<
			"Warning: there is no data in the plot being saved.\n";
		return 1;
	}

	if (!Write((char *) &OutChannelSize,sizeof(OutChannelSize))) return 0 ;
	return 1 ;
}


int PlotFileManager::ReadPrologue()
{
	int Length = strlen(AddCopyright::plot_file_prologue);
	char * Buf = new char[Length+1];
	int LengthRead = read(InFile,Buf,Length);
	Buf[Length] = '\0' ;
	if (LengthRead != Length || strcmp(Buf,AddCopyright::plot_file_prologue)) {
		delete Buf ;
		return 0;
	}
	delete Buf ;
	if (!Read((char *) &InChannelSize,sizeof(InChannelSize))) return 0 ;
/*
 *	LogOut << "PlotFileManager::ReadPrologue, Size = " <<
 *		InChannelSize << "\n" ;
 */
	return 1 ;
}




int PlotFileManager::WritePlotData(DataPlot& ThePlot)
{
	int Return = 1 ;
	const BufSize = 8192 ;
	int16 Buffer[BufSize];
/*
 *	LogOut << "PlotFileManager::WritePlotData OutChannels = " 
 *		<< OutChannels << ", Size = " << OutChannelSize << "\n" ;
 */
	for (int i = 0 ; i < OutChannels ; i ++) {
		// LogOut << "Writing channel " << i << "\n" ;
		DataFile * ChannelData = ThePlot.GetDataFile(i);
		if (!ChannelData) DbgError("PlotFileManager::WritePlotData",
			"cannot get channel data");
		int32 SaveRead = ChannelData->GetNextByteToRead();
		int32 ChannelSize = OutChannelSize >> 1 ;
		for (long WrdPtr=0 ; WrdPtr < ChannelSize; WrdPtr+=BufSize) {
			long ToWrite = ChannelSize - WrdPtr ;
			if (ToWrite > BufSize) ToWrite = BufSize ;
			ChannelData->Read( 2*ToWrite,(char *)Buffer,WrdPtr);
/*
 *			LogOut << "Writing " << ToWrite << " words for channel "
 *				<< i << "\n" ;
 */
			if (!Write((char *) Buffer, ToWrite*sizeof(int16))) {
				Return = 0;
				break ;
			}
		}
		ChannelData->Seek(SaveRead);
		if (!Return) break ;
	}
	return Return ;
}

int PlotFileManager::ReadPlotData()
{
	const BufSize = MaxPacketSize >> 1 ;
	int16 Buffer[BufSize];
	long WordSize = InChannelSize >> 1 ;
	for (int i = 0 ; i < InChannels;i++) {
		for (long WrdPtr = 0;WrdPtr < WordSize;WrdPtr+=BufSize) {
			long ToRead = WordSize - WrdPtr ;
			if (ToRead > BufSize) ToRead = BufSize ;
			int ToReadBytes = ToRead * sizeof(int16) ;
/*
 *			LogOut << "WrdPtr = " << WrdPtr << ", ToRead = "
 *				<< ToRead << ", ToReadBytes = " <<
 *				ToReadBytes << "\n" ;
 */
			if (!Read((char *) Buffer, ToReadBytes))
				return 0 ;
			PacketHeader Head = PlotPacketHeader(
				PacketWindowPlotData,InPlotId,i, ToReadBytes);
			ThePlotsManager->PlotServer(Head,(char *)Buffer, -1);
		}
	}
	return 1 ;
}

int PlotFileManager::WritePlot(const char * FileName, DataPlot& ThePlot)
{
	OutFile = open(FileName, O_WRONLY | O_CREAT, OpenFileMode) ;
	if (OutFile < 1) {
		// TheWindowsManager->SuspendRedraw(OutputHelp);
		*Output + OutputHelp << "Can't create file `" << FileName <<
			"'.\n";
		SystemErrorMessage(0);
		// TheWindowsManager->ClearSuspendRedraw(OutputHelp);
		*Output << "\n" ;
		return 0 ;
	}
/*
 *	OutFile = open(FileName,O_WRONLY | O_CREAT, 0644);
 *	if (OutFile < 1) {
 *		*Output + OutputHelp << "Cannot create file `" << FileName <<
 *			"' to write plot `" << ThePlot.GetName() <<
 *			"' to.\n" ;
 *		return ;
 *	}
 */
	int Return = 0 ;
	for (;;) { // Dummy loop so we can exit with break 
		OutChannels = ThePlot.GetNumberOfChannels();
		// LogOut << "OutChannels = " << OutChannels << "\n" ;
		if(!WritePrologue(ThePlot)) break ;

		StrDataPlotHeader * StrPlotHead = ThePlot.GetStructure();
		PacketHeader Head = PlotPacketHeader(PacketWindowPlotControl,
			GetPlotId(),PlotControlHeader,sizeof(*StrPlotHead));
		if (!WritePacket(Head,(char *) StrPlotHead)) break ;
		delete StrPlotHead ;

		const char * PlotCaption = ThePlot.GetCaption();
		if (PlotCaption) {
			Head = PlotPacketHeader(PacketWindowPlotControl,
				GetPlotId(), PlotControlCaption,
				1+strlen(PlotCaption));
			if (!WritePacket(Head,PlotCaption)) break ;
		}
	
		Head = PlotPacketHeader(PacketWindowPlotControl, GetPlotId(),
			PlotControlName,1+strlen(ThePlot.GetName()));
		if (!WritePacket(Head,ThePlot.GetName())) break ;
	
		for (int i = 0;ThePlot.GetChannel(i);i++)
			WriteChannelHeader(i, &ThePlot);

		Head = PlotPacketHeader(PacketWindowPlotControl,GetPlotId(),
			PlotControlComplete, 0);
		if (!WritePacket(Head,(char *) 0)) break ;

		if (WritePlotData(ThePlot)) Return = 1;
		break ;
	}
	close(OutFile);
	OutFile = 0 ;
	return Return ;
}

int PlotFileManager::WriteChannelHeader(int Channel,DataPlot * PlotHead)
{
/*
 *	LogOut << "DataPlot * PlotHead = 0x" << hex((long)PlotHead) <<
 *		"\n" ;
 */
	PlotChannel * ThisChannel = PlotHead->GetChannel(Channel) ;
	// LogOut << "ThisChannel = 0x" << hex((long)ThisChannel) << "\n" ;
	if (!ThisChannel) DbgError("WriteChannelHeader","bad channel");
/*
 *	LogOut << "ThisChannel->GetChannelNumber() = " <<
 *		ThisChannel->GetChannelNumber() << "\n" ;
 */
	StrPlotChannel * StrPlotChan = &(ThisChannel->GetStructure());

	PacketHeader Head = PlotPacketHeader(PacketWindowPlotControl,
		GetPlotId(), PlotControlChannel, sizeof(*StrPlotChan));

	if(!WritePacket(Head,(char *) StrPlotChan)) return 0;
/*
 *	LogOut << "PlotFileManager::WriteChannelHeader - Channel = " <<
 *		Channel << ", from structure = " <<
 *		StrPlotChan->ChannelNumber << "\n" ;
 */
	delete StrPlotChan ;

	for (int EltIndex = 0 ; EltIndex < ThisChannel->GetNumberElements();
		EltIndex++) {
		MultiplexedElement * ThisElement = &(ThisChannel->
			GetMultiplexedElements()[EltIndex]);
		if (!ThisElement)DbgError("PlotFileManager::WriteChannelHeader",
			"bad element index");
			
		StrMultiplexedElement * StrElement =
			&(ThisElement->GetStructure());

		Head = PlotPacketHeader(PacketWindowPlotControl,GetPlotId(),
			PlotControlElement, sizeof(*StrElement));
		if (!WritePacket(Head,(char *) StrElement)) return 0 ;
		delete StrElement ;
	}
	return 1 ;
}


int PlotFileManager::ReadHeader()
{
	// Go through protocol to get a plot Id
	InPlotId = ThePlotsManager->GetPlotId();
	int MainHeaderRead = 0 ;
	for (;;) {
		PacketHeader Head ;
		char Buffer[MaxPacketSize];
		ReadPacket(Head,Buffer);
		if (!MainHeaderRead) {
			StrDataPlotHeader * TheHeader =
				(StrDataPlotHeader *) Buffer ;
			InChannels = TheHeader->NumberOfChannels ;
			TheHeader->PlotChannelToSet = 0 ;
			TheHeader->PlotIdentifier = InPlotId ;
		
/*
 *			LogOut << "PlotFileManager::ReadHeader, Channels = "
 *				<< InChannels << "\n" ;
 */
			MainHeaderRead = 1 ;
		}
		Head.SetPlotId(InPlotId);
		ThePlotsManager->PlotServer(Head,Buffer,-1);
		if (Head.ThePacketType == PacketWindowPlotControl)
			if (Head.GetPlotChannel()==PlotControlComplete) break ;
	}
	return 1 ;
}

void PlotFileManager::CompleteReadPlot()
{
	if (!ReadPlotData()) return ;
	close(InFile);
	InFile = 0 ;
}

void PlotFileManager::ReadPlot(const char * FileName)
{
	InFile = open(FileName,O_RDONLY);
	if (InFile < 1) {
		*Output + OutputHelp << "Cannot open file `" << FileName <<
		"'.\nRequest to read a plot file aborted.\n" ;
		return ;
	}
	if (!ReadPrologue()) {
		*Output + OutputHelp << "File `" << FileName <<
			"' is not a DSP++ plot file.\n" <<
			"Request to read a plot file aborted.\n" ;
		return ;
	}
	if (!ReadHeader()) return ;
	DataPlot * ThisPlot = ThePlotsManager->GetPlot(InPlotId);
	if (!ThisPlot) ReadError() ;
	else ThisPlot->SetPlotFileManager(this);
	// set call back to complete processing of data
}


