
#import <remote/NXProxy.h>
#import <gamekit/gamekit.h>
#import <daymisckit/daymisckit.h>
#import <appkit/appkit.h>
#import <objc/typedstream.h>	// highscore tables

@implementation HighScoreSlot

+ initialize
{
	if (self == [HighScoreSlot class]) {
		[HighScoreSlot setVersion:GKHighScoreSlot_VERSION];
	}
	return self;
}

- init	// implement to generate an empty slot for server
{
	return [self initName:"Nobody" score:0];
}

- initName:(const char *)initName score:(int)initScore
{	// for games that don't use the level variable
	return [self initName:initName score:initScore endLevel:0];
}

- initName:(const char *)initName score:(int)initScore endLevel:(int)initLevel
{	// designated initializer
	[super init];
	playerName =  [[DAYString allocFromZone:[self zone]]
			initString:initName];
	endLevel = initLevel;
	finalScore  = initScore;
	// make a bunch of empty objects.
	startTime =   [[DAYTime      allocFromZone:[self zone]] init];
	endTime =     [[DAYTime      allocFromZone:[self zone]] init];
	elapsedTime = [[DAYStopwatch allocFromZone:[self zone]] init];
	userName =    [[DAYString    allocFromZone:[self zone]] init];
	machineName = [[DAYString    allocFromZone:[self zone]] init];
	return self;
}

- dumpToLog:aLogFile	// used by server when logging
{	// aLogFile must be a kind of the DAYLogFile class
	char *string = (char *)malloc(256);
	id tempString = [[DAYString alloc] init];
	sprintf(string, "    finalScore = %d    startLevel = %d    endLevel = %d\n    startTime = \"%s\"    endTime = \"%s\"    elapsedTime = \"%s\"\n    playerName = \"%s\"    userName = \"%s\"    machineName = \"%s\"\n",
			finalScore, startLevel, endLevel,
			[startTime stringValue], [endTime stringValue],
			[elapsedTime stringValue], [playerName stringValue],
			[userName stringValue], [machineName stringValue]);
	[tempString setStringValue:string];
	[aLogFile addLineToLogFile:tempString];
	free(string);
	[tempString free];
	return self;
}

- free
{	// free all the sub-objects.
	[startTime free]; [endTime free];
	[elapsedTime free]; [playerName free];
	[userName free]; [machineName free];
	return [super free];
}

// The following methods access value of the slot.
- (const char *)playerName { return [playerName stringValue]; }
- (const char *)userName { return [userName stringValue]; }
- (const char *)machineName { return [machineName stringValue]; }
- (int)finalScore { return finalScore; }
- (int)startLevel { return startLevel; }
- (int)endLevel { return endLevel; }
- startTime { return startTime; }
- endTime { return endTime; }
- elapsedTime { return elapsedTime; }

// The following methods change the values of the slot.
- setFinalScore:(int)t { finalScore = t; return self; }
- setStartLevel:(int)t { startLevel = t; return self; }
- setEndLevel:(int)t { endLevel = t; return self; }

- setPlayerName:(const char *)t
{
	[playerName setStringValue:t];
	return self;
}

- setUserName:(const char *)t
{
	[userName setStringValue:t];
	return self;
}

- setMachineName:(const char *)t
{
	[machineName setStringValue:t];
	return self;
}

- setStartTime:aTime
{
	if (startTime) [startTime free];
	startTime = aTime;
	return self;
}

- setEndTime:aTime
{
	if (endTime) [endTime free];
	endTime = aTime;
	return self;
}

- setElapsedTime:aTime
{
	if (elapsedTime) [elapsedTime free];
	elapsedTime = aTime;
	return self;
}

- (BOOL)isAbove:aSlot
{	// override this if you want a custom ordering of slots
	if (finalScore > [aSlot finalScore]) return YES;
	return NO;
}

// for archiving to/from a file
- read:(NXTypedStream *)stream
{
	[super read:stream];
	if (NXTypedStreamClassVersion(stream, "HighScoreSlot") ==
			[HighScoreSlot version]) { // current version read code
		NXReadTypes(stream, "iii", &finalScore, &startLevel, &endLevel);
		startTime = NXReadObject(stream);
		endTime = NXReadObject(stream);
		elapsedTime = NXReadObject(stream);
		playerName = NXReadObject(stream);
		userName = NXReadObject(stream);
		machineName = NXReadObject(stream);
	} else { // read old version
		int pos;	//  a throwaway
		char *tmpStr = malloc(1024); // should be plenty big
		[self init]; // clear all ivars before reading in new
		NXReadTypes(stream, "iii*", &pos, &endLevel, &finalScore, &tmpStr);
		[playerName setStringValue:tmpStr];
		free(tmpStr);
	}
	return self;
}

- write:(NXTypedStream *)stream
{
	[super write:stream];
	NXWriteTypes(stream, "iii", &finalScore, &startLevel, &endLevel);
	NXWriteObject(stream, startTime);
	NXWriteObject(stream, endTime);
	NXWriteObject(stream, elapsedTime);
	NXWriteObject(stream, playerName);
	NXWriteObject(stream, userName);
	NXWriteObject(stream, machineName);
	return self;
}

// NXTransport protocol implementation:
- encodeUsing:(id <NXEncoding>)portal
{
	[portal encodeObjectBycopy:startTime];
	[portal encodeObjectBycopy:endTime];
	[portal encodeObjectBycopy:elapsedTime];
	[portal encodeObjectBycopy:playerName];
	[portal encodeObjectBycopy:userName];
	[portal encodeObjectBycopy:machineName];
	[portal encodeData:&finalScore ofType:"i"];
	[portal encodeData:&startLevel ofType:"i"];
	[portal encodeData:&endLevel ofType:"i"];
	return self;
}

- decodeUsing:(id <NXDecoding>)portal
{
	startTime = [portal decodeObject];
	endTime = [portal decodeObject];
	elapsedTime = [portal decodeObject];
	playerName = [portal decodeObject];
	userName = [portal decodeObject];
	machineName = [portal decodeObject];
	[portal decodeData:&finalScore ofType:"i"];
	[portal decodeData:&startLevel ofType:"i"];
	[portal decodeData:&endLevel ofType:"i"];
	return self;
}

- encodeRemotelyFor:(NXConnection *)connection
	freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isByCopy
{
	if (isByCopy) {
		*flagp = NO; // object will copy.
		return self; //encode object (copy it)
	}
	*flagp = NO; // object will copy.
	// super will encode the proxy otherwise
	return [super encodeRemotelyFor:connection
				freeAfterEncoding:flagp isBycopy:isByCopy];
}

- copy
{ // this is to make sure that the id instance vars are actually _copied_
	id newObj = [[[self class] alloc] init];
	[newObj setPlayerName:[self playerName]];
	[newObj setUserName:[self userName]];
	[newObj setMachineName:[self machineName]];
	[newObj setStartTime:[[self startTime] copy]];
	[newObj setEndTime:[[self endTime] copy]];
	[newObj setElapsedTime:[[self elapsedTime] copy]];
	[newObj setFinalScore:[self finalScore]];
	[newObj setStartLevel:[self startLevel]];
	[newObj setEndLevel:[self endLevel]];
	return newObj;
}

@end
