
#import "BongAppController.h"
#import "dpsclient/dpsNeXT.h"
#import <sys/time.h>	
#import <misckit/misckit.h>	// Get stuff for string class...

@implementation BongAppController

- setBongSound:sender
{
	const char	*types[] = { "snd", NULL };
	OpenPanel	*openPanel = [OpenPanel new];  // Convenience reference.  Reduce code, and maybe calls.
	MiscString	*pathString = [MiscString newWithString:""];  // Grab an empty instance of MiscString... ;')

	if ( pathString ) {
		if ( [[openPanel allowMultipleFiles:NO] runModalForTypes:types] ) {
			[pathString catStrings:[openPanel directory], "/", *[openPanel filenames], NULL];  // Construct full path.
			[pathString replaceHomeWithTilde];  // Attempt to substitute a tilde for home path.
			[soundTextField setStringValue:[pathString stringValueAndFree]];  // Get the value, and free object.
			[self textWillEnd:soundTextField];  // Get the sound to be updated.
			NXWriteDefault("BongApp", [defaultsStringTable valueForStringKey:"bongFileSoundPath"], [soundTextField stringValue]);
		}
	} else NXLogError("%s Error -- setBongSound: could not aquire a new MiscString instance.\n",
				[[self class] name]);
	
	return ( self );
}

- setWhenToPlay:sender
{
	MiscString		*whenToPlay = [MiscString newWithString:""];
	MiscString		*indexString = [[MiscString alloc] init];
	int				index;

	for ( index = 1; index <= 4; index++ ) {
		if ( [[sender findCellWithTag:index] intValue] ) {
			[indexString sprintf:"%d", index];
			[whenToPlay cat:[defaultsStringTable valueForStringKey:[indexString stringValue]]];
			[whenToPlay cat:" "];
		}
	}
	[whenToPlay squashSpaces];
	NXWriteDefault("BongApp", [defaultsStringTable valueForStringKey:"whenToPlay"] ,[whenToPlay stringValueAndFree]);

	return ( self );
}

// Timed Entry functions.
void updateTimeAndCheck(DPSTimedEntry teNum, double now, id self)
{
	[self updateTimeAndCheck];
}


// Application Delegate Methods

// Set up the timed entry to check for the time (hour or half hour).
- appDidInit:sender
{
	int			defaultIndex;
	MiscString	*index = [[MiscString alloc] init];
	MiscString	*whenToPlayDefaults = [[MiscString alloc] init];
	MiscString	*currPlayDefault = [[MiscString alloc] init];

	[soundTextField setStringValue:NXReadDefault("BongApp", [defaultsStringTable valueForStringKey:"bongFileSoundPath"])];
	[self textWillEnd:soundTextField];  // "force" retrieval of the sound
	if (!(DPSAddTimedEntry(1.0, (DPSTimedEntryProc)&updateTimeAndCheck, self, NX_BASETHRESHOLD))) {
		NXLogError("%s Error -- appDidInit: could not aquire"
			" timed entry for time check.\n",
			[[self class] name]);
		[NXApp terminate:self];
	}

	// Get whenToPlay default, and set the appropriate switches to reflect the settings.
	// Assuming that the switch defaults are labeled 1 - 4 (or even higher if there are more switches
	//  that you add.  I kept it simple since most people don't want "bong'in" going on more than
	//  at the quarter hour marks.
	[whenToPlayDefaults setString:NXReadDefault("BongApp", [defaultsStringTable valueForStringKey:"whenToPlay"])];
	for ( defaultIndex = 4; defaultIndex; defaultIndex-- ) {
		[index sprintf:"%d", defaultIndex];
		[currPlayDefault setString:[defaultsStringTable valueForStringKey:[index stringValue]]];
		[[whenToPlayMatrix findCellWithTag:defaultIndex] setIntValue:
			([whenToPlayDefaults spotOfRegex:[currPlayDefault stringValue]] != -1 ) ? YES : NO];
	}

	return ( self );
}

- showInfoPanel:sender;
{
	MiscString	*revisionString = [[MiscString alloc] init];
	MiscString	*infoNibPath = [[MiscString alloc] init];
	char		buffer[MAXPATHLEN + 1];

	if ( !infoPanel ) {
		[[NXBundle mainBundle] getPath:buffer forResource:"Info" ofType:"nib"];
		[infoNibPath setString:buffer];
		if ( ![NXApp loadNibFile:[infoNibPath stringValue] owner:self withNames:NO fromZone:[self zone]] ) {
			NXLogError("%s Error -- showInfoPanel: could not load the info panel.\n",
					[[self class] name]);
			return ( self );
		} else {
			[revisionString sprintf:"Ver %.2f Rel %.2f", B_VERSION, B_RELEASE];
			[revisionTextField setStringValue:[revisionString stringValue]];
		}
	}
	[infoPanel makeKeyAndOrderFront:self];

	return ( self );
}

- updateTimeAndCheck
{
	struct tm		*localTime;
	struct timeval	currentTime;
	Sound			*totalBongSound;
	
	// Get the time in seconds, and microseconds from 1970 ...
	gettimeofday (&currentTime, NULL);
	// ... and then break it down into something useful.  The time that is.
	localTime = localtime (&(currentTime.tv_sec));

	// Update the fields
	[[timeForm findCellWithTag:HOURS] setIntValue:localTime->tm_hour];
	[[timeForm findCellWithTag:MINUTES] setIntValue:localTime->tm_min];
	[[timeForm findCellWithTag:SECONDS] setIntValue:localTime->tm_sec];

	// Now based on the values, do a bong for hour, or half hour...
	if ( localTime->tm_sec == 0 ) {

		// If we are on a 15 minute interval, then check if we are allowed to play...
		if ((localTime->tm_min == 0) && ([self _allowedToPlayAt:B_ON_THE_HOUR])) {
			bongCount = localTime->tm_hour;
			if ( bongCount == 0 ) bongCount = 12; 
			else if ( bongCount > 12 ) bongCount -= 12;
		} else if ((localTime->tm_min == 15) && ([self _allowedToPlayAt:B_QUARTER_AFTER])) {
			bongCount = 1;
		} else if ((localTime->tm_min == 30) && ([self _allowedToPlayAt:B_HALF_AFTER])) {
			bongCount = 1;
		} else if ((localTime->tm_min == 45) && ([self _allowedToPlayAt:B_QUARTER_TILL])) {
			bongCount = 1;
		} else return ( self );  // ... else return.

		// Get a new sound, then construct many bongs and play the sound
		totalBongSound = [[Sound alloc] init];
		while ( bongCount-- ) {
			[totalBongSound insertSamples:[Sound findSoundFor:"bongSound"] at:[totalBongSound dataSize]];
			if ( [totalBongSound needsCompacting] ) [totalBongSound compactSamples];  // Compact if sound has fragmentation.
		}

		[totalBongSound play];  // Spawn a sound playing thread, and play the sound.
	}
	
	return ( self );
}

// Another support method
- (BOOL)_allowedToPlayAt:(int)timeRequested
{
	MiscString		*defaultTimes = [[MiscString alloc] init];
	MiscString		*indexString = [[MiscString alloc] init];

	// Check and see if we are within our known limits of play, and then get the defaults if so.
	if ((timeRequested < B_ON_THE_HOUR) || (timeRequested > B_QUARTER_TILL)) return ( NO );
	[defaultTimes setString:NXReadDefault("BongApp", [defaultsStringTable valueForStringKey:"whenToPlay"])];

	// Now use the MiscString instance methods to find any instance of a known string in the defaults.
	[indexString sprintf:"%d", timeRequested];
	if ( [defaultTimes rspotOfRegex:[defaultsStringTable valueForStringKey:[indexString stringValue]]] < 0 ) return ( NO );

	return ( YES );
}

// Text field delegate overrides...
- (BOOL)textWillEnd:sender
{
	Sound 		*newSound;
	Sound		*oldSound;
	MiscString	*pathString = [MiscString newWithString:[soundTextField stringValue]];

	oldSound = [Sound removeSoundForName:"bongSound"];
	[pathString replaceTildeWithHome];
	if (!(newSound = [Sound addName:"bongSound" fromSoundfile:[pathString stringValue]])) {
		NXLogError("%s Error -- textWillEnd: could not aquire the new sound (%s).\n",
				[[self class] name], [pathString stringValue]);
		if ( oldSound ) [Sound addName:"bongSound" sound:oldSound];
		return ( NO );
	}
	NXWriteDefault("BongApp", [defaultsStringTable valueForStringKey:"bongFileSoundPath"], [soundTextField stringValue]);

	return ( YES );	// Allow the changes.
}

// Going to add some simple/smashing animation to the information panel.
- smashClock:sender
{


	return ( self );
}

@end
