/*  flstatus.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "sysintfc.h"
#include "sysconst.h"
#include "newaloc.h"
#include "cgidbg.h"
// #include "textwin.h"
#include "txtfls.h"
// #include "winpres.h"
#include "wfiles.h"
#include "flstatus.h"
#include "dsp_app.h"

void FileStatus::CheckWrite(char * Buf,int N)
{
	int Error = 0;
	if (!N) DbgError("CheckWrite","Null line");
	if (Buf[N-1] != '\n') {
		TheLog << "FileStatus::CheckWrite ***************EOL Missing\n" ;
		Error=1;
	}
	for (int i = 0 ; i < N-1; i++) if (Buf[i] || Error)
		if (!isprint(Buf[i]) || Error) {
		// LogForm("i = %d, N = %d", i,N);
		// LogMsg("Line ::",Buf);
		Error = 1;
		break ;
	}
	long Seek ;
	if (NextByteToRead != (Seek = lseek(TheFile,(long)0,1))) {
/*
 *		LogForm("Seek = %d, NextByteToRead = %d",
 *			Seek,NextByteToRead );
 *		LogMsg("NextByteToRead wrong");
 */
		Error = 1;
	}
	if (Error) DbgError("FileStatus::CheckWrite","Error");
}

static void ClearNBytes (int TheFile, int32 NumBytes)
{
	const BufSize = 1024 ;
	char Buf[BufSize];
	for (int32 i = 0 ; i < BufSize ; i++) Buf[i] = '\0' ;
	for (i = 0 ; i < NumBytes ; i+=BufSize ) {
		unsigned NumWrite = BufSize ;
		if (NumWrite > NumBytes - i) NumWrite = NumBytes - i;
		if (write(TheFile,Buf,NumWrite) != NumWrite)
			DbgError("TextFile::ClearNBytes", "bad write");
	}
}


FileStatus::FileStatus(TextFile * link)
{
	// LogMsg("FileStatus constructor called");
	FileLink = link ;
	Name = DspApplication::open_file(TheFile) ;
	ChangedBufSize = 4096 ;
	ChangedBufSize = 256 ; 
	ClearNBytes (TheFile, (int) (NextByteToRead=ChangedBufSize));
	NextFreeByteAtHead = 0 ;
	NextByteInFile = NextByteToRead ;
	MaxNumberChangedLines = 100;
	MaxNumberChangedLines = 3 ;  // for debugging

	NextChangedLine = 0;
	Updates = new ChangedLines [MaxNumberChangedLines] ;
	for (int i = 0; i < MaxNumberChangedLines; i++)
		Updates[i].Line = UpdateEnd ;
	NextWriteLineInFile = 0;

	// Table if byte addresses for every 10th line
	FileLinesSize = 100 ;
	FileLinesSize = 3 ;  // for debugging

	FileLines = new long [FileLinesSize] ;
	FileLines[0] = NextByteInFile ;
	NextFileLine=0 ;
}

FileStatus::~FileStatus()
{
	delete Updates ;
	if (TheFile > -1) {
		close(TheFile);
		unlink(Name);
	}
	delete (void *) Name ;
}

void FileStatus::UpdateFileLines()
{
	if (NextFileLine > FileLinesSize -1) {
		int NewFileLinesSize = FileLinesSize + (FileLinesSize >> 2) ;
		if (NewFileLinesSize <= FileLinesSize) NewFileLinesSize =
			FileLinesSize + 1;
		long * NewFileLines = new long [NewFileLinesSize] ;
		if (!NewFileLines) DbgError("FileStatus::UpdateFileLines",
			"no room");
		for (int i = 0 ; i < FileLinesSize ; i++)
			NewFileLines[i] = FileLines[i] ;
		delete FileLines ;
		FileLines = NewFileLines ;
		FileLinesSize = NewFileLinesSize ;
	}
	FileLines[NextFileLine++] = NextByteInFile ;
}

void FileStatus::DoWriteLine(unsigned NumBytes,char * Data)
{
	// CheckWrite(Data,NumBytes);
	SeekEnd();
	if (write(TheFile,Data,NumBytes)!=NumBytes) DbgError(
		"TextFile::DoWriteLine","bad write") ;
	if (!(NextWriteLineInFile++ % 10)) UpdateFileLines();
/*
 *	LogOut << "DoWriteLine - NextWriteLineInFile = " <<
 *		NextWriteLineInFile << "\n" ;
 */
	NextByteInFile += NumBytes;
	NextByteToRead += NumBytes;

	// All of the following is for debugging
/*	char Buf[1024];
 *	MoveNBytes(Buf,Data,NumBytes);
 *	Buf[NumBytes] = '\0' ;
 *	LogMsg("DoWriteLine::",Buf);
 */
}


void FileStatus::WriteLine(int32 LineIndex,char * Line)
{
	// LogOut << "FileStatus::WriteLine(" << LineIndex << ",\n" ;
	// LogOut << "\"" << Line << "\")\n" ;
	// LogOut << "NextWriteLineInFile = " << NextWriteLineInFile << "\n" ;
	// if this line is greater than the last line written
	// the intervening lines are all blanked

	if (NextWriteLineInFile > LineIndex) {
		TheLog << "NextWriteLineInFile = " << NextWriteLineInFile <<
			" > LineIndex = " << LineIndex << "\n" ;
		DbgError("TextFile::WriteLine","bad line");
	}

	while (NextWriteLineInFile < LineIndex) DoWriteLine(1,"\n");
	DeleteTrailingSpaces(Line) ;
	int Size = strlen(Line) ;
	strcpy(FileLink->LineBuf,Line);
	FileLink->LineBuf[Size++] = '\n' ;
	DoWriteLine(Size,FileLink->LineBuf);
	// LogOut << "Exit FileStatus::WriteLine\n" ;
}

void FileStatus::SeekHead()
{
	if (lseek(TheFile,NextByteToRead=NextFreeByteAtHead,0) !=
		NextByteToRead) DbgError("TextFile::SeekHead","bad seek");
}

void FileStatus::SeekEnd()
{
	if (NextByteToRead != NextByteInFile) {
		NextByteToRead = NextByteInFile;
		if (lseek(TheFile,NextByteToRead=NextByteInFile,0) != 
		    NextByteToRead) DbgError("TextFile::SeekEnd","bad seek");
	}
}


int16 FileStatus::ReadUpdateLine(long ByteInFile, char * Dest)
{
	if (lseek(TheFile,NextByteToRead=ByteInFile,0) != ByteInFile)
		DbgError("ReadUpdateLine", "bad seek");
	if ( read(TheFile,FileLink->LineBuf,FileLink->LineBufSize)
		!= FileLink->LineBufSize) 
		DbgError("ReadUpdateLine", "bad read");
	NextByteToRead += FileLink->LineBufSize ;
	int16 Length;
	MoveNBytes((char *)&Length,FileLink->LineBuf+sizeof(int32),
		sizeof(int16));
	MoveNBytes(Dest,FileLink->LineBuf+sizeof(int16) + sizeof(int32),Length);
	Dest[Length-1] = '\0' ;  // clear line feed
	return Length - 1 ;
}

