#include <stream.h>
#include "buffer.h"
#include "cgidbg.h"
#include "ramio.h"

ErrCode BufferReadStatus::Reset()
{
	ReadPtr = 0 ;
	FullFlag = 0 ;
	TheState = BufferOK ;
	return OK ;
}

ErrCode OutputBuffer::Reset()
{
	ErrCode Ret = OK ;
	ErrCode Loc ;
	for (int i = 0 ; i < Readers; i++)
		if ((Loc = ReadersStatus[i].Reset()) > Ret) Ret = Loc ;
	WritePtr = 0 ;
	return Ret ;
}

int32 OutputBuffer::GetAvailableData(int Index) const 
{
	int32 Return ;
	BufferReadStatus * Status = ReadersStatus + Index ;
	if (Status->FullFlag) return Size ;
	Return = WritePtr - Status->ReadPtr ;
	if (Return < 0) Return += Size;
	return Return ;
}

int32 OutputBuffer::GetContiguousAvailableData(int Index) const 
{
	// TheLog<<"OutputBuffer::GetContiguousAvailableData(" <<Index<<")\n";
	int32 Return ;
	BufferReadStatus * Status = ReadersStatus + Index ;
	Return = WritePtr - Status->ReadPtr ;
	if (Return > 0) return Return ;
	if (!Return) if (!Status->FullFlag) return 0 ;
	return Size - Status->ReadPtr ;
}

int32 OutputBuffer::GetAvailableSpace() const
{
	int32 Used = 0 ;
	for (int i = 0 ; i < Readers; i++) {
		int32 UsedHere = GetAvailableData(i);
		if (UsedHere > Used) Used = UsedHere ;
	}
	return Size - Used ;
}

int32 OutputBuffer::GetContiguousAvailableSpace()
{
	int32 Space = Size ;
	for (int i = 0 ; i < Readers; i++) {
		int32 LocalSpace = Size - WritePtr ;
		BufferReadStatus * Status = ReadersStatus + i ;
		if (Status->FullFlag) return 0 ;
		int32 Temp = Status->ReadPtr - WritePtr;
		if (Temp > 0) LocalSpace = Temp ;
		if (LocalSpace < Space) Space = LocalSpace ;
	}
	return Space ;
}


void OutputBuffer::UpdateRead(int index, int32 size)
{
	if (!size) return ;
	int32 AvailData = GetAvailableData(index);
	BufferReadStatus * Status = ReadersStatus + index ;
	if (AvailData < size)  {
#if DEBUG
		TheLog << "Buffer wrap read for reader " <<
				index << "\n" ;
		TheLog << "size = " << size << ", AvailData = "
			<< AvailData << "\n";
#endif
		Status->TheState = BufferWrapRead ;
		DebugCodeError(45,"OutputBuffer::UpdateRead","buffer wrap",0);
	}
	int NewRead = Status->ReadPtr+size ;
	if (NewRead >= Size) NewRead -= Size ;
	Status->ReadPtr = NewRead ;
	Status->FullFlag = 0 ;
}

void OutputBuffer::UpdateWrite(int32 size)
{
	if (!size) return ;
	int32 Used = 0 ;
	for (int i = 0 ; i < Readers; i++) {
		int32 UsedHere = GetAvailableData(i) + size;
		if (UsedHere >= Size) {
			BufferReadStatus * Status = ReadersStatus + i ;
			if (UsedHere == Size)  Status->FullFlag = 1 ;
			else {
				TheLog << "size = " << size << ", i = "
					<< i << "\n" ;
				TheLog << "UsedHere = " << UsedHere <<
					", Size = " << Size << "\n" ;
				TheLog << "Wptr = " << WritePtr  << "\n" ;
				TheLog << "Buffer wrap write\n" ;
				Status->TheState = BufferWrapWrite ;
				
				DebugCodeError(46,"OutputBuffer::UpdateWrite","buffer wrap",0);
			}
		}
	}
	WritePtr += size ;
	if (WritePtr >= Size) WritePtr -= Size ;
}

void OutputBuffer::WriteCxWord(CxMachWord Data)
{
	WriteWord(MachReal(Data));
	WriteWord(MachImag(Data));
}

CxMachWord OutputBuffer::ReadCxWord(int Index)
{
	MachWord r = ReadWord(Index);
	MachWord i = ReadWord(Index);
	return CxMachWord(r,i);
}

MachWord * OutputBuffer::GetPtrWriteWord()
{
	int i;
	int Difference ;
#ifdef DEBUG4
	TheLog << "Wptr = " << WritePtr << " \n";
#endif
	for (i= 0 ; i < Readers; i++) {
		struct BufferReadStatus * Status = ReadersStatus + i;
		Difference = Status->ReadPtr - WritePtr ;
		if (Difference == 1 || Difference == (1 - Size)) {
#ifdef DEBUG3
			TheLog << "Setting full on write\n";
#endif
			Status->FullFlag = 1;
		} else if (!Difference) if (Status->FullFlag) {
			TheLog << "Wptr = " << WritePtr << ", State = "
				<< Status->TheState << ", Full = " <<
				Status->FullFlag << "\n" ;
			TheLog << "Buffer wrap write\n" ;
			Status->TheState = BufferWrapWrite ;
			DebugCodeError(47,"OutputBuffer::GetPtrWriteWord","buffer wrap",0);
		}
	}
	MachWord * Return = Data + WritePtr++ ;
	if (WritePtr >= Size) WritePtr = 0;
	return Return ;
}

MachWord * OutputBuffer::ReadPtrWord(int Index)
{
	struct BufferReadStatus * Status = ReadersStatus+Index;
#ifdef DEBUG4
	TheLog <<"Reading read chan " << Index << ", Rptr = " << Status->ReadPtr
		<< ", Status = " << Status << " \n";
#endif
	static MachWord Zero = 0 ;
	MachWord * Value = & Zero;
	if (Status->TheState == BufferEndOfDataEmpty) return Value ;
	if (Status->ReadPtr == WritePtr) if (!Status->FullFlag) {
		if (Status->TheState == BufferEndOfData) 
			Status->TheState = BufferEndOfDataEmpty ;
		else {
			TheLog << "Reading Rptr = " << Status->ReadPtr <<
				", Wptr = " << WritePtr << ", State = " <<
				Status->TheState <<
				", Full = " << Status->FullFlag << "\n";
			TheLog << "Buffer wrap read for reader " <<
				Index << "\n" ;
			Status->TheState = BufferWrapRead ;
			DebugCodeError(48,"OutputBuffer::ReadPtrWord","buffer wrap",0);
		}
	}
	Status->FullFlag = 0;
	Value = Data + Status->ReadPtr++;
	if (Status->ReadPtr >= Size) Status->ReadPtr = 0;

#ifdef DEBUG4
	TheLog << "Reading " << *Value << ", Rptr = " << Status->ReadPtr <<
		", Wptr = " << WritePtr << ", State = " << Status->TheState <<
		", Full = " << Status->FullFlag << "\n";
#endif
 
	return Value ;
}

