
#import "Spewer.h"
#import "FlyingWindow.h"
#import "Animator.h"

@implementation EnhanceSpewer:Object

- init
{
	[super init];
	srandom(time(0));
	initiator = nil;
	animator = [[EnhanceAnimator allocFromZone:[self zone]] initChronon:0.05
			adaptation:0.0 target:self action:@selector(move:)
			autoStart:NO eventMask:0];
	_extraList = [[List allocFromZone:[self zone]] init];
	 idleWindows = [[List allocFromZone:[self zone]] init];
	 windowList = [[List allocFromZone:[self zone]] init];
	createOK = NO;
	return self;
}

- start:sender
{
	createOK = YES;
	initiator = sender;
	[self addWindow];
	[animator startEntry];
    return self;
}

- stop:sender
{
	createOK = NO;
	initiator = nil;
	// we stop creating windows, but keep the animator running
	// until all the windows are gone
    return self;
}

- windowWillClose:sender
{
	[self stop:self];
    return self;
}

- free
{ // clean out any windows, remove the timed antry and free everything
	int i;
	animator = [[animator stopEntry] free];
	for (i=0; i<[windowList count]; i++)
		[[windowList objectAt:i] orderOut:self];
	[windowList freeObjects];
	windowList = [windowList free];
	return [super free];
}

- addWindow
{
	NXPoint theCenterPoint;
	NXRect senderFrame; id newWindow;

	if (!createOK) return nil;
	[initiator getFrame:&senderFrame];
	//[initiator convertRect:&senderFrame toView:nil];
	theCenterPoint.x = NX_X(&senderFrame) + NX_WIDTH(&senderFrame) / 2;
	theCenterPoint.y = NX_Y(&senderFrame) + NX_HEIGHT(&senderFrame) / 2;
	[[initiator window] convertBaseToScreen:&theCenterPoint];
	// recycle if we can; otherwise make a new one
	newWindow = [idleWindows removeLastObject];
	if (!newWindow) newWindow = [[EnhanceFlyingWindow allocFromZone:[self zone]]
			initAt:&theCenterPoint];
	else [newWindow reInitAt:&theCenterPoint];
	[windowList addObject:newWindow];
	return self;
}

- move:sender
{
	int i; id newList = _extraList;

	// add any new windows spewing about if necessary...
	if (([windowList count] < MAX_SPEWS) && !(random() % FREQUENCY)) {
		[self addWindow];
	}

	// move the windows
	for (i=0; i<[windowList count]; i++) [[windowList objectAt:i] move];

	// remove any windows that left the screen
	for (i=0; i<[windowList count]; i++) {
		id theWindow = [windowList objectAt:i];
		if ([theWindow onScreen]) [newList addObject:theWindow];
		else {
			[theWindow orderOut:self];
			[idleWindows addObject:theWindow]; // put in recycler
		}
	}
	[windowList empty];
	_extraList = windowList;
	windowList = newList;
	if (([windowList count] < 1) && !(createOK))
		// stop TE after all windows gone
		[animator stopEntry];
	return self;
}

@end
