
#import <appkit/defaults.h>
#import <appkit/Matrix.h>
#import <appkit/TextField.h>
#import <appkit/TextFieldCell.h>
#import <appkit/Window.h>
#import <pwd.h>
#import <strings.h>
#import <sys/types.h>
#import <ctype.h>
#import "ScoreKeeper.h"
#import "TetApp.h"

#define SCORE_FILE	".TetrisScores"

#define NUM_SCORES	10
#define BEZEL_SIZE	2.0
#define FIELD_X_OFFSET	2.0

extern void setpwent();
extern void endpwent();
extern uid_t getuid();
extern void chmod(char *path, int mode);

@implementation ScoreKeeper
#ifdef FOO
- (int) fileFoundProc(char *)path
{
    strcpy(self->path, path);
    return 0;
}
#endif

- (NXStream *)findScoresFile:(int) mode
{
	NXStream *result;
	char *appName;
	
	strcpy(path, NXArgv[0]);
	if ((appName = rindex(path, '/')))
	  appName++;
	else 
	  appName = path;
	strcpy(appName, SCORE_FILE);
	if (!(result = NXMapFile(path, mode))) {
		strcat(strcat(strcpy(path, NXHomeDirectory()), "/"), SCORE_FILE);
		result = (mode == NX_READONLY) ? NXMapFile(path, NX_READONLY) :
		NXOpenMemory(NULL, 0, mode);
	}
	return result;
}

- init
{
    [super init];
    nameField = nil;
    return self;
}

- (void) readHighScores:(NXStream *)stream
{
	int c;
	char name[BUFSIZ];
	char level[5];
	char myScore[10];
	
	for (c = 0; c < NUM_SCORES; c++) {
    	name[0] = level[0] = myScore[0] = '\0';
		NXScanf(stream, "%[^\7]\7%[^\7]\7%[^\7]\7", name, level, myScore);
		[[names cellAt:c :0] setStringValue:name],
		[[levels cellAt:c :0] setStringValue:level],
		[[scores cellAt:c :0] setStringValue:myScore];
	}
}

- setScoresWindow:anObject
{
	NXStream *inStream;
    
	scoresWindow = anObject;
	[scoresWindow setDelegate:self];
	if ((inStream = [self findScoresFile: NX_READONLY])) {
		[self readHighScores: inStream];
		NXCloseMemory(inStream, NX_FREEBUFFER);
	}
	return self;
}

- setZero
{
	[score setIntValue:0];
	return self;
}

- addScore:(int)amount
{
    [score setIntValue:[score intValue] + amount];
    return self;
}

static char *username()
{
	static char *username = (char *)0;
	struct passwd *pwdentry;
	static char ubuf [128];
	
	if (!username) {
		char * pc;

		setpwent();
		pwdentry = getpwuid(getuid());
		endpwent();
		username = ((pwdentry) ? pwdentry->pw_gecos : "");
		/* extended GECOS field handling added by Detlev Droege,
		* droege@infko.uni-koblenz.de, December 1991 */
		if (pc = index (username, ','))
		  *pc = 0;        /* strip ','-part of gecos field */
		if (index (username, '&')) {
			/* do '&' expansion */
			pc = ubuf;
			while (*username) {
				if (*username == '&') {
					strcpy (pc, pwdentry->pw_name);
					*pc = toupper (*pc);
					while (*pc) pc++;
				}
				else
				  *pc++ = *username;
				username++;
			}
			*pc = 0;
			username = ubuf;
		}
	}
	return username;
}

- (int) findrank:(int) myScore
{
	id window = [names window];
	int myRank;
	int c;

	[window disableFlushWindow];
	for (myRank = 0; myRank < NUM_SCORES; myRank++)
	  if (myScore >= [[scores cellAt:myRank :0] intValue])
		 break;
	for (c = NUM_SCORES - 1; c > myRank; c--) {
		[[names cellAt:c :0] setStringValue:
		 [[names cellAt:(c - 1) :0] stringValue]];

    	[[levels cellAt:c :0] setStringValue:
		 [[levels cellAt:(c - 1) :0] stringValue]];

    	[[scores cellAt:c :0] setStringValue:
		 [[scores cellAt:(c - 1) :0] stringValue]];
	}
	[window reenableFlushWindow];
	return myRank;
}

- updateHighScores:(int)level
{
	id window = [names window];
	int scoreValue = [score intValue];
	NXRect nRect;
	
	if ((rank = [self findrank: scoreValue]) < NUM_SCORES) {
		[scoresWindow makeKeyAndOrderFront:self];
		[[levels cellAt:rank :0] setIntValue:level];
		[[scores cellAt:rank :0] setIntValue:scoreValue];
		[[names getCellFrame:&nRect at:rank :0] convertRect:&nRect toView:nil];
		NXInsetRect(&nRect, -BEZEL_SIZE, -BEZEL_SIZE);
		nRect.origin.x -= FIELD_X_OFFSET;

		if (!nameField) {
			nameField = [[TextField alloc] initFrame:&nRect];
			[nameField setEditable:YES];
			[[nameField setTarget:self] setAction:@selector(nameFieldEnd:)];
		} else
		  [nameField moveTo:nRect.origin.x :nRect.origin.y];

		[nameField setStringValue:username()];
		[[window contentView] addSubview:nameField];
		[[nameField display] selectText:self];
		while ([NXApp peekAndGetNextEvent:NX_KEYUPMASK | NX_KEYDOWNMASK]) ;
		[NXApp runModalFor:window];
	}
	return self;
}

- nameFieldEnd:sender
{
	id window = [names window];
	
	[window disableFlushWindow];
	[[names cellAt:rank :0] setStringValue:[nameField stringValue]];
	[nameField removeFromSuperview];
	[window display];
	[[window reenableFlushWindow] flushWindow];
	[NXApp stopModal];
	return self;
}

- windowWillClose:sender
{
	if (nameField && [nameField currentEditor]) {
    	[self nameFieldEnd:sender];
		return nil;
	} else
	  return self;
}

- writeHighScores:(NXStream *)stream
{
    int c;
    
    for (c = 0; c < NUM_SCORES; c++)
    	NXPrintf(stream, "%s\7%s\7%s\7",
					[[names cellAt:c :0] stringValue],
					[[levels cellAt:c :0] stringValue],
					[[scores cellAt:c :0] stringValue]);
    NXFlush(stream);
	 return self;
}

- writeScores
{
	NXStream *outStream;

	if ((outStream = [self findScoresFile: NX_WRITEONLY])) {
		[self writeHighScores: outStream];
		NXSaveToFile(outStream, path);
		NXCloseMemory(outStream, NX_FREEBUFFER);
		chmod(path, 0666);
	}
	return self;
}

- free
{
    if (nameField)
    	[nameField free];
    return [super free];
}

@end

