
#import <gamekit/gamekit.h>
#import <daymisckit/daymisckit.h>
#import <sound/sound.h>

#define GK_MIN_SOUND_TIME 50000 // in usec, this prevents flanging

@implementation SoundPlayer

- init
{ // This method should be avoided.
	return [self initSounds:GK_DEFNUMSOUNDS types:GK_DEFNUMTYPES streams:1];
}

- initSounds:(int)ns types:(int)nt streams:(int)nstr
{
	if (!_initialized) [super init];
	else [self freeObjects];
	numTypes = nt; numSounds = ns;
	currentTime = [[DAYTime alloc] initWithCurrentTime];
	startTime = [[DAYTime alloc] initWithCurrentTime];
	streamGroup = [[GKSoundStream alloc] initStreams:nstr];
	soundListList = [[List alloc] initCount:numTypes];
	soundType = 0; _initialized = YES; turnedOn = YES;
	return self;
}

- appDidInit:sender	// forwarded by GameBrain
{
	id gameInfo = [[NXApp delegate] gameInfo];
	[self initSounds:[gameInfo numSounds] types:[gameInfo numSoundTypes]
			streams:[gameInfo numSoundStreams]];
	[self loadSounds];
	gameScreen = [[NXApp delegate] gameScreen];
	preferences = [[NXApp delegate] preferencesBrain];
	return self;
}

- loadSounds
{
	int i, j; id tempSnd, tempList;
	char *soundFile = (char *)malloc(MAXPATHLEN + 1);
	id minTime = [[[DAYTime alloc] init] addMicroseconds:GK_MIN_SOUND_TIME];
    id soundOut;
	if (!(soundOut = [[NXSoundOut alloc] init]))
		return self; // bail if no soundOut
	[soundOut free]; //only needed it for the check.
	// if we had 3.1 we could do more checks, I'd put it in, but then I'd
	// be binary incompatible with 3.0!  :-(  It'll be here in the future*****
	for (i=0; i<numTypes; i++) {
		tempList = [[List alloc] initCount:numSounds];
		for (j=0; j<numSounds; j++) {  // load in the the sounds
			sprintf(soundFile, "%s/Sound%d.%d.snd",
					[NXApp appDirectory], j, i);
			tempSnd = [[GKSound alloc] initFromSoundfile:soundFile];
			if (!tempSnd)
				fprintf(stderr, "Unable to load sound \"%s\".\n", soundFile);
			[tempSnd setPlayStream:streamGroup];
			[tempSnd setTimeToPlay:minTime]; // ***** need a way to change this
			[tempList addObject:tempSnd];
		}
		[soundListList addObject:tempList];
	}
    free(soundFile);
	return self;
}

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

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

- play:sender { return [self playNum:[sender tag]]; }

- playNum:(int)num
{
	// make sure we have the sound
	if ((num < 0) || (num >= [[soundListList objectAt:0] count])) return nil;
	[currentTime initWithCurrentTime];
	// play the sound if the game's state allows it.
	if ([currentTime isAfter:startTime] && turnedOn &&
			([gameScreen demoMode] ? [preferences demoSound] : YES)) {
		// get pointer to appropriate sound data and then enqueue
		// the sound data to be played
		[[[soundListList objectAt:soundType] objectAt:num] play];
	}
	return self;
}

- setSoundType:(int)num
{
	if (num > [soundListList count]) soundType = [soundListList count];
	else if (num < 0) soundType = 0;
	else soundType = num;
	return self;
}

- (int)soundType { return soundType; }

- soundNum:(int)num type:(int)type
{
	return [[soundListList objectAt:type] objectAt:num];
}

- freeObjects
{
	[soundListList makeObjectsPerform:@selector(freeObjects)];
	[soundListList freeObjects];
	[soundListList free];
	[streamGroup free];
	[device free];
	return self;
}

- free
{
	[self freeObjects];
	return nil;
}


@end
