
#import "NXIAlien.h"
#import "NXIAlienOverseer.h"

static id overseer = nil;

@implementation NXIAlienOverseer

+ new
{	// this is hokey -- don't try to subclass it!
	if (!overseer) overseer = [[self alloc] init];
	return overseer;
}

- init
{	// we keep the dead state; this actor is never rendered.  It's a "behind
	// the scenes" player...
	id ret = [super init];
	invaderList = [[List alloc] init];
	GK_CLEAR_VECTOR(&lastMovementDirection);
	GK_CLEAR_VECTOR(&movementDirection);
	GK_CLEAR_VECTOR(&movement);
	leftMost = nil; rightMost = nil;
	return ret;
}

- setUpAliensForLevel:(int)aLevel
{
	id manager = [stage stageManager];
	int i, j, offset; NXRect bounds;
	[[stage bufferType:GK_SCREEN_BUFFER] getBounds:&bounds];
	offset = (NX_WIDTH(&bounds) / ALIEN_VERTICAL_STEP_SIZE) - aLevel;
	if (offset < 5) offset = 5;
	GK_SET_VECTOR(&movementDirection, ALIEN_RIGHT, 0.0);
	GK_SET_VECTOR(&lastMovementDirection, ALIEN_RIGHT, 0.0);
	// build up all the aliens and add them to the stage
	moveCycles = ALIEN_STEPCYCLES - aLevel;
	if (moveCycles < 1) moveCycles = 1;
	for (j = 0; j < ALIEN_NUMROWS; j++) { // work from top to bottom row
	// this code to get the color will allow me to change ALIEN_NUMROWS...
		float m = (j * 5.0 / ALIEN_NUMROWS);
		int color = BLUE_ALIEN;
		if (m > 0.99) color = GREEN_ALIEN;
		if (m > 2.99) color = RED_ALIEN;
		for (i = 0; i < ALIEN_NUMVADERS; i++) {
			id newVader = [manager getActorOfClass:[NXIAlien class]];
			NXPoint newPosition = { ALIEN_WIDTH * i,
					ALIEN_VERTICAL_STEP_SIZE * (offset - j) };
			
			[newVader initAlienColor:color at:&newPosition];
			[stage addActor:newVader ofType:GK_DYNAMIC_ACTOR];
			[invaderList addObject:newVader];
			// need to set up the collision group (player's bullets)
			// *****
	}	}
	[self findRightMost];
	[self findLeftMost];
	return self;
}

- findRightMost
{	// find the rightmost alien invader
	int i; float x = 0.0;
	for (i=0; i<[invaderList count]; i++) {
		NXPoint aPoint; id vader = [invaderList objectAt:i];
		[vader at:(&aPoint)];
		if (aPoint.x > x) {
			x = aPoint.x;
			rightMost = vader;
		}
	}
	return self;
}

- findLeftMost
{	// find the leftmost alien invader
	int i; float x = 20000.0; // any really big number will do
	for (i=0; i<[invaderList count]; i++) {
		NXPoint aPoint; id vader = [invaderList objectAt:i];
		[vader at:(&aPoint)];
		if (aPoint.x < x) {
			x = aPoint.x;
			leftMost = vader;
		}
	}
	return self;
}

- alienLeavingTheStage:anAlien
{
	if (anAlien == rightMost) [self findRightMost];
	if (anAlien == leftMost) [self findLeftMost];
	[invaderList removeObject:anAlien];
	switch ([invaderList count]) { // these are when we speed up
		case 32:	case 16:	case 8:
		case 4:		case 2:		case 1:
			moveCycles /= 2; break;
	}
	if (moveCycles < 1) moveCycles = 1;	// fastest we can go!
	if (![invaderList count]) {
		// no more left:  time to move to the next level!
		[[NXApp delegate] nextLevel];
	}
	return self;
}

- move:sender
{
	// check to see if any invaders are past the "threshold"; if they are,
	// then we change the movement direction and move them all down.
	cycles++;	// never gets inc'ed by GKActor machinery since we're "dead"
	if (cycles >= moveCycles) {
		cycles = 0;
		// see if we need to change directions or not:
		// if we moved down, it's time to reverse direction.
		if (GK_VECTOR_Y(&movementDirection) != 0.0) {
			GK_COPY_VECTORS(&movementDirection, &lastMovementDirection);
			GK_VECTOR_X(&movementDirection) *= -1;
		} else // if we're past the "edge" it's time to move down
			if (((movementDirection.x > 0) && [leftMost hitEdge:LEFT_EDGE]) ||
			((movementDirection.x < 0) && [rightMost hitEdge:RIGHT_EDGE])) {
			GK_SET_VECTOR(&movementDirection, 0.0, -ALIEN_VERTICAL_STEP_SIZE);
		}
		GK_COPY_VECTORS(&movement, &movementDirection);
		// ***** play the marching sound here
	} else {	// don't move; we're between steps
		GK_CLEAR_VECTOR(&movement);
	}
	return self;
}

- movementVector:(NXPoint *)aVector
{
	GK_VECTOR_X(aVector) = GK_VECTOR_X(&movement);
	GK_VECTOR_Y(aVector) = GK_VECTOR_Y(&movement);
	return self;
}

@end
