#include "blckwrt.h"
#include "netlnk.h"
#include "cgidbg.h"
#include "tarnod.h"

ReadWriteBlock::ReadWriteBlock(TargetNode& node, int cx_in, int cx_out):
	ReadWriteSingleChannel(node, cx_in, cx_out),
	ReadPtrB(0),
	WritePtrB(0)
{

	if (TheNode.GetIn() == 2) {
		if (ComplexIn) DebugCodeError(13,"ReadWriteBlock::Ctor","bad input",0);
		ReadBaseB = TheNode.GetReadBase(1) ;
		ReadEndB = TheNode.GetReadEnd(1) ;
	} else {
		ReadBaseB = 0 ;
		ReadEndB = 0 ;
	}


	if (TheNode.GetOut() == 2) {
		if (ComplexOut) DebugCodeError(14,"ReadWriteBlock::Ctor","bad output",0);
		WriteBaseB = TheNode.GetWriteBase(1) ;
		WriteEndB = TheNode.GetWriteEnd(1) ;
	} else {
		WriteBaseB = 0 ;
		WriteEndB = 0 ;
	}
}

void ReadWriteBlock::InitPtr()
{
	ReadWriteSingleChannel::InitPtr();
	InitPtr();
}

void ReadWriteBlock::InitPtrBase()
{
	if (TheNode.GetIn() == 2) ReadPtrB = TheNode.GetReadPtr(1); 
	if (TheNode.GetOut() ==2) WritePtrB = TheNode.GetWritePtr(1) ;
}



int32 ReadWriteBlock::GetCount(int32 MaxCount)
{
	InitPtrBase();
	int32 CountToExecute = ReadWriteSingleChannel::GetCount(MaxCount);
	if (TheNode.GetOut() ==2) {
		int32 CountOut = TheNode.GetContiguousSpace(1) ;
		if (CountToExecute > CountOut) CountToExecute = CountOut ;
	}

	if (TheNode.GetIn() == 2) {
		int32 CountOut = TheNode.GetContiguousAvailableData(1) ;
		if (CountToExecute > CountOut) CountToExecute = CountOut ;
	}
	return CountToExecute ;
}


int32 ReadWriteBlock::Update(int32 CountToExecute)
{
	ReadWriteSingleChannel::Update(CountToExecute);
	if (TheNode.GetIn() == 2) TheNode.UpdateRead(CountToExecute,1);
	if (TheNode.GetOut() == 2) TheNode.UpdateWrite(CountToExecute,1);
	return CountToExecute ;
}

ReadWriteSingleChannel::ReadWriteSingleChannel(
	TargetNode& node, int cx_in, int cx_out):
	TheNode(node),
	ReadBase(node.GetReadBase()),
	ReadEnd(node.GetReadEnd()),
	WriteBase(node.GetWriteBase()),
	WriteEnd(node.GetWriteEnd()),
	ReadPtr(0),
	WritePtr(0),
	ComplexIn(cx_in),
	ComplexOut(cx_out)
{
}

void ReadWriteSingleChannel::InitPtr()
{
	ReadPtr = TheNode.GetReadPtr(); 
	WritePtr = TheNode.GetWritePtr() ;
}

int32 ReadWriteSingleChannel::GetCount(int32 MaxCount)
{
	InitPtr();
	int32 CountToExecute = MaxCount ;

	int32 CountOut = TheNode.GetContiguousSpace() ;
	if (ComplexOut) CountOut >>= 1;
	if (CountToExecute> CountOut) CountToExecute = CountOut ;

	CountOut = TheNode.GetContiguousAvailableData(0) ;
	if (ComplexIn) CountOut >>=1 ;
	if (CountToExecute > CountOut) CountToExecute = CountOut ;

	return CountToExecute ;
}

int32 ReadWriteSingleChannel::Update(int32 CountToExecute)
{
	int32 ReadUpdate = CountToExecute ;
	if (ComplexIn) ReadUpdate <<= 1 ;
	TheNode.UpdateRead(ReadUpdate);

	int32 WriteUpdate = CountToExecute ;
	if (ComplexOut) WriteUpdate <<= 1 ;
	TheNode.UpdateWrite(WriteUpdate);

	return CountToExecute ;
}

void ReadWriteSingleChannel::ReadBlock(int32 TooMove, MachWord * InputBuffer)
{
	while (TooMove) {
		ReadPtr = TheNode.GetReadPtr();
		int32 Count = TheNode.GetContiguousAvailableData();
		if (Count > TooMove) Count = TooMove ;
		const MachWord * Limit = ReadPtr + Count ;
		while(ReadPtr < Limit) *InputBuffer++ = *ReadPtr++ ;
		TooMove -= Count ;
		TheNode.UpdateRead(Count);
	}
}

void ReadWriteSingleChannel::WriteBlock(int32 TooMove,
	const MachWord * OutputBuffer)
{
	while (TooMove) {
		WritePtr = TheNode.GetWritePtr();
		int32 Count = TheNode.GetContiguousSpace();
		if (Count > TooMove) Count = TooMove ;
		const MachWord * Limit = WritePtr + Count ;
		while(WritePtr < Limit) *WritePtr++ = *OutputBuffer++  ;
		TooMove -= Count ;
		TheNode.UpdateWrite(Count);
	}
}

void ReadWriteSingleChannel::WriteBinaryBlock(int32 TooMove,
	const BinMachWord * OutputBuffer)
{
	BinMachWord * BinWritePtr ;
	while (TooMove) {
		BinWritePtr = (BinMachWord *) TheNode.GetWritePtr();
		int32 Count = TheNode.GetContiguousSpace();
		if (Count > TooMove) Count = TooMove ;
		const BinMachWord * Limit = BinWritePtr + Count ;
		while(BinWritePtr < Limit) *BinWritePtr++ = *OutputBuffer++  ;
		TooMove -= Count ;
		TheNode.UpdateWrite(Count);
	}
	WritePtr = (MachWord *) BinWritePtr ;
}

MachWord * ReadWriteSingleChannel::GetInputBuffer()
{
	int32 size = ReadEnd-ReadBase ;
	return (MachWord *) new MachWordCast[size] ;
}

MachWord * ReadWriteSingleChannel::GetOutputBuffer()
{
	int32 size = WriteEnd-WriteBase ;
	return (MachWord *) new MachWordCast[size] ;
}

