#import "TextDiff.h"
#import <appkit/appkit.h>
#import "ClientText.h"


@implementation TextDiff

+ firstInitObject:anObject
{
	return [anObject init];
}

+ reInitObject:anObject
{
	NXStream   *aStream = [anObject stream];
	
	NXCloseMemory(aStream, NX_FREEBUFFER);
	return [anObject init];
}

- init
{
	return [self initWithStream:NXOpenMemory(NULL, 0, NX_READWRITE)];
}

- initWithStream:(NXStream *)aStream
{
	[super init];
	channelID = senderUName = fromID = NULL;
	traceNr = 0;
	
	selStart = selEnd = selClick = 0;

	memStream = aStream;
	if (memStream)
		return self;
	else
		return nil;
}

- encodeRemotelyFor:(NXConnection *)connection
	freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isBycopy
{
	if (isBycopy) return self;
	return [super encodeRemotelyFor:connection 
		freeAfterEncoding:flagp isBycopy:isBycopy];
}

- encodeUsing:(id <NXEncoding>)portal
{
	void    *buffer;
	int      size, max;
	
	NXGetMemoryBuffer(memStream, (char **)&buffer, &size, &max);
	[portal encodeData:&size ofType:"i"];
	[portal encodeVM:buffer count:size];
	[portal encodeData:&selStart  ofType:"i"];
	[portal encodeData:&selEnd    ofType:"i"];
	[portal encodeData:&selClick  ofType:"i"];
	return self;
}

- decodeUsing:(id <NXDecoding>)portal
{
	vm_address_t  buffer;
	int           size;
	
	[super init];

	[portal decodeData:&size ofType:"i"];
	vm_allocate(task_self(), &buffer, size, YES);
	[portal decodeVM:(void **)&buffer count:&size];
	[portal decodeData:&selStart  ofType:"i"];
	[portal decodeData:&selEnd    ofType:"i"];
	[portal decodeData:&selClick  ofType:"i"];
	memStream = NXOpenMemory((void *)buffer, size, NX_READWRITE);

	return self;
}

- (NXStream *)stream
{
	return memStream;
}

- getSelection:(int *)start :(int *)end
{
	*start = selStart;
	*end = selEnd;
	return self;
}

- setSelection:(int)start :(int)end :(int)click
{
	selStart = start;
	selEnd = end;
	selClick = click;
	return self;
}

- setStreamFrom:(NXStream *)aStream
{
	vm_address_t  newBuf;
	void         *buffer;
	int           size, max;
	
	if (!aStream)
		return nil;
	NXGetMemoryBuffer(aStream, (char **)&buffer, &size, &max);
	if (!size)
		return nil;
	if (memStream)
		NXCloseMemory(memStream, NX_FREEBUFFER);
	vm_allocate(task_self(), &newBuf, size, YES);
	bcopy(buffer, (char *)newBuf, size);
	memStream = NXOpenMemory((void *)buffer, size, NX_READWRITE);
	
	return self;
}

- applyTo:(ClientText *)aText
{
	[aText setSel:selStart :selEnd];
	[aText setClickCount:selClick];
	NXSeek(memStream, 0, NX_FROMSTART);
	if (memStream->eof)
		[aText replaceSelWithRTFD:memStream];
	else
		[aText delete:nil];
	return self;
}


- read:(NXTypedStream *)stream
{
	vm_address_t  buffer;
	int           size;
	
	[super read:stream];
	if (memStream)
		NXCloseMemory(memStream, NX_FREEBUFFER);
	NXReadType(stream, "i", &size);
	vm_allocate(task_self(), &buffer, size, YES);
	NXReadArray(stream, "c", size, (void *)buffer);
	NXReadType(stream, "i", &selStart);
	NXReadType(stream, "i", &selEnd);
	NXReadType(stream, "i", &selClick);
	memStream = NXOpenMemory((void *)buffer, size, NX_READWRITE);
	
	return self;
}

- write:(NXTypedStream *)stream
{
	void*         buffer;
	int           size, max;
	
	[super write:stream];
	NXGetMemoryBuffer(memStream, (char **)&buffer, &size, &max);
	NXWriteType(stream, "i", &size);
	NXWriteArray(stream, "c", size, buffer);
	NXWriteType(stream, "i", &selStart);
	NXWriteType(stream, "i", &selEnd);
	NXWriteType(stream, "i", &selClick);
	
	return self;
}

- free
{
	NXCloseMemory(memStream, NX_FREEBUFFER);
	return [super free];
}

- (const char *)channelID { return channelID; }
- (const char *)senderUName { return senderUName; }
- (const char *)fromID { return fromID; }
- (unsigned int)traceNr { return traceNr; }

- (void)setChannel:(char *)aChannelID
	senderIs:(char *)uName from:(char *)anID
	traceNr:(unsigned int)aTraceNr
{
	channelID = aChannelID;
	senderUName = uName;
	fromID = anID;
	traceNr = aTraceNr;
	return;
}

@end