
#import <gamekit/gamekit.h>

#define DEMOMODE [[[NXApp delegate] gameScreen] demoMode]
#define TOPSCORE [highScoreController highestScore]

@interface ScoreKeeper(private)
- (BOOL)_changeOKTo:(int)new;
- _changedFrom:(int)old;
@end

@implementation ScoreKeeper

- init
{
	[super init];
	scoreCanGoNegative = NO;
	score = 0;
    return self;
}

- appDidInit:sender		// forwarded by GameBrain -- just loads score
{
	if (!highScoreController)
		highScoreController = [[NXApp delegate] highScoreController];
	if (!bonusTrackerList) bonusTrackerList = [[List alloc] init];
	if (!delegateList) delegateList = [[List alloc] init];
	[self updateTopScoreText];
	[self updateScoreText];
	return self;
}

- (int)currentScore { return score; }

- resetScore
{
	score = 0;
	[[self updateScoreText] updateTopScoreText];
	return self;
}

- scoreCanGoNegative:(BOOL)flag
{
	scoreCanGoNegative = flag;
	return self;
}

- (int)addToScore:(int)amount
{
	int newScore = score + amount;
	int oldScore = score;
	if (![self _changeOKTo:newScore]) return 0;
	score = newScore;
	[self _changedFrom:oldScore];
	[self updateScoreText];
	if ((score > TOPSCORE) && !DEMOMODE) [self updateTopScoreText];
#ifdef NOISYDEBUG
	fprintf(stderr, "Score inc'ed from %d to %d (+%d).\n",
			oldScore, newScore, amount);
#endif
	return amount;
}

- (int)subtractFromScore:(int)amount
{
	BOOL scoreWasOver = (score > TOPSCORE);
	int newScore = score - amount;
	int oldScore = score;
	if (![self _changeOKTo:newScore]) return 0;
	score = newScore;
	if ((!scoreCanGoNegative) && (score < 0)) score = 0;
	[self updateScoreText];
	if (scoreWasOver && (score < TOPSCORE) && !DEMOMODE)
		[self updateTopScoreText];
	[self _changedFrom:oldScore];
#ifdef NOISYDEBUG
	fprintf(stderr, "Score dec'ed from %d to %d (%d).\n",
			oldScore, newScore, (score - oldScore));
#endif
	return (score - oldScore);
}

- (BOOL)_changeOKTo:(int)new
{
	int i; id temp;
#ifdef NOISYDEBUG
	fprintf(stderr, "_changeOKTo: %u delegate(s)...\n", [delegateList count]);
#endif
	for (i=0; i<[delegateList count]; i++) {
		temp = [delegateList objectAt:i];
		if ([temp respondsTo:@selector(scoreWillChangeFrom:to:)]) {
#ifdef NOISYDEBUG
		fprintf(stderr,
"    Sending -scoreWillChangeFrom:to: message to delegate of \"%s\" class.\n",
				[[temp class] name]);
#endif
			if (![temp scoreWillChangeFrom:score to:new]) return NO;
		}
	}
	return YES;
}

- _changedFrom:(int)old
{
	int i; id temp;
#ifdef NOISYDEBUG
	fprintf(stderr, "_changedFrom: %u delegate(s)...\n", [delegateList count]);
#endif
	for (i=0; i<[delegateList count]; i++) {
		temp = [delegateList objectAt:i];
		if ([temp respondsTo:@selector(scoreChangedFrom:to:)]) {
#ifdef NOISYDEBUG
			fprintf(stderr,
"    Sending -scoreChangedFrom:to: message to delegate of \"%s\" class.\n",
					[[temp class] name]);
#endif
			[temp scoreChangedFrom:old to:score];
		}
	}
	return self;
}

- (GKTrackerId)addBonusTracker:newTracker
{
	[bonusTrackerList addObjectIfAbsent:newTracker];
	return [bonusTrackerList indexOf:newTracker];
}

- bonusTracker:(GKTrackerId)index
{
	if (index < 0) return nil;
	return [bonusTrackerList objectAt:index];
}

- (int)addBonusToScore:(GKTrackerId)index advance:(BOOL)flag
{
	int change;
	if (index < 0) return 0;
	change = [self addToScore:[[bonusTrackerList objectAt:index] bonusValue]];
	if (flag) [[bonusTrackerList objectAt:index] advanceBonus];
	return change;
}

- (int)subtractBonusFromScore:(GKTrackerId)index retreat:(BOOL)flag
{
	int change;
	if (index < 0) return 0;
	change = [self subtractFromScore:
			[[bonusTrackerList objectAt:index] bonusValue]];
	if (flag) [[bonusTrackerList objectAt:index] retreatBonus];
	return change;
}

- resetBonus:(int)index
{
	if (index < 0) [bonusTrackerList makeObjectsPerform:@selector(resetBonus)];
	else [[bonusTrackerList objectAt:index] resetBonus];
	return self;
}

- updateScoreText
{
	[scoreText setIntValue:score];
	return self;
}

- updateTopScoreText
{
	[topScoreText setIntValue:((TOPSCORE > score) ? TOPSCORE : score)];
	return self;
}

- setHighScoreController:controller
{
	highScoreController = controller;
	return self;
}

- setTopScoreText:textField
{
	topScoreText = textField;
	return self;
}

- setScoreText:textField
{
	scoreText = textField;
	return self;
}

- topScoreText
{
	return topScoreText;
}

- scoreText
{
	return scoreText;
}

- highScoreController
{
	return highScoreController;
}

- delegateList
{
	return delegateList;
}

- addDelegate:newDel
{
#ifdef NOISYDEBUG
	fprintf(stderr, "ScoreKeeper adding delegate of class \"%s\"\n.",
			[[newDel class] name]);
#endif
	return [delegateList addObject:newDel];
}

- removeDelegate:oldDel
{
#ifdef NOISYDEBUG
	fprintf(stderr, "ScoreKeeper removing delegate of class \"%s\"\n.",
			[[oldDel class] name]);
#endif
	return [delegateList removeObject:oldDel];
}


@end
