//  MapView.m
// Part of Risk by Mike Ferris

#import "MapView.h"

#import "mapWraps.h"
#import "Country.h"
#import "GameSetup.h"
#import "Mover.h"
#import "LanguageApp.h"
#import "DefaultManager.h"
#import <dpsclient/psops.h>
#import <appkit/Panel.h>
#import <appkit/TextField.h>
#import <appkit/NXImage.h>
#import <appkit/graphics.h>
#import <objc/List.h>
#import <dpsclient/psops.h>

#define BOARDBACKING "BoardBacking"
#define COUNTRYFILE "Country.data"
@implementation MapView

+ initialize
// set our version
{
	if (self == [MapView class])  {
		[self setVersion:1];
	}
	return self;
}

- initFrame:(NXRect *)frm
// designated initializer
{
	self = [super initFrame:frm];
	// get the backdrop
	boardBackingImage = [NXImage findImageNamed:BOARDBACKING];
	// get the countries
	[self populateGlobe];
	selectedCountry = nil;
	return self;
}

- free
// free all our lists
{
	[northAmerica free];
	[southAmerica free];
	[europe free];
	[asia free];
	[africa free];
	[australia free];
	[countryList freeObjects];
	[countryList free];
	return [super free];
}

- appDidInit:sender
// post init initialization stuff
{
	[countryNameTextField removeFromSuperview];
	[self addSubview:countryNameTextField];
	return self;
}

- displayCountry:country
// have a single country display itself (actually draw everything that
// intersects the countries bounds.)
{
	NXRect r[3];
	
	[country getBounds:&r[0]];
	[self display:r :1 :YES];
	return self;
}

- drawSelf:(NXRect *)rects :(int)rectCount
// the meet of the display methods
{
	NXPoint o = {0.0, 0.0};
	int i, p;
	NXColor color;
	BOOL sel;
	id temp;
	NXRect b;
	
	// draw backing
	if (rectCount == 1)  {
		[boardBackingImage composite:NX_COPY fromRect:&rects[0] 
							toPoint:&rects[0].origin];
	}  else if (rectCount == 3)  {
		[boardBackingImage composite:NX_COPY fromRect:&rects[1] 
							toPoint:&rects[1].origin];
		[boardBackingImage composite:NX_COPY fromRect:&rects[2] 
							toPoint:&rects[2].origin];
	}  else  {
		[boardBackingImage composite:NX_COPY toPoint:&o];
	}
	
	// draw countries only if they intersect the update rects
	sel = NO;
	for (i=0; i<[countryList count]; i++)  {
		temp = [countryList objectAt:i];
		[temp getBounds:&b];
		if (rectCount == 1)  {
			if (NXIntersectsRect(&b, &rects[0]))  {
				p=[temp player];
				if (p==-1)  {
					color = NX_COLORWHITE;
				}  else  {
					color = [theGameSetup colorOfPlayer:p];
				}
				[temp drawSelfInView:self withColor:color isSelected:sel];
			}
		}  else  {
			if ((NXIntersectsRect(&b, &rects[1])) || 
						(NXIntersectsRect(&b, &rects[2])))  {
				p=[temp player];
				if (p==-1)  {
					color = NX_COLORWHITE;
				}  else  {
					color = [theGameSetup colorOfPlayer:p];
				}
				[temp drawSelfInView:self withColor:color isSelected:sel];
			}
		}
	}
	// redraw the selected country
	if (selectedCountry != nil)  {
		sel = YES;
		p = [selectedCountry player];
		if (p==-1)  {
			color = NX_COLORWHITE;
		}  else  {
			color = [theGameSetup colorOfPlayer:p];
		}
		[selectedCountry drawSelfInView:self withColor:color isSelected:sel];
	}
	return self;
}

- mouseDown:(NXEvent *)e
// figure out which country got hit and inform Mover
{
	int i;
	BOOL found=NO;
	int c = [countryList count];
	
	for (i=0; (i<c && found==NO); i++)  {
		found = [[countryList objectAt:i] ptInCountry:&e->location];
		if (found)  {
			[countryNameTextField setStringValue:
						[[countryList objectAt:i] name]];
			[self setSelectedCountry:[countryList objectAt:i]];
			[theMover countryClick:[countryList objectAt:i] num:i event:e];
		}
	}
	
	return self;
}

- setSelectedCountry:country
// change the selected country and redraw if necessary
{
	NXRect r[3];
	BOOL r1=NO, r2=NO;
	
	if (country != selectedCountry)  {
		if (selectedCountry != nil)  {
			[selectedCountry getBounds:&r[1]];
			r1 = YES;
		}
		if (country != nil)  {
			[country getBounds:&r[2]];
			r2 = YES;
		}
		selectedCountry = country;
		if ((r1) && (r2))  {
			NXSetRect(&r[0], r[1].origin.x, r[1].origin.y, r[1].size.width, 
						r[1].size.height);
			NXUnionRect(&r[2], &r[0]);
			[self display:r :3 :YES];
			
		}  else if (r1)  {
			NXSetRect(&r[0], r[1].origin.x, r[1].origin.y, r[1].size.width, 
						r[1].size.height);
			[self display:r :1 :YES];
		}  else if (r2)  {
			NXSetRect(&r[0], r[2].origin.x, r[2].origin.y, r[2].size.width, 
						r[2].size.height);
			[self display:r :1 :YES];
		}
	}
	return self;
}

- (BOOL)doesPlayerWin:(int)pNum
// returns YES if pNum is the only player left with countries
{
	int i, c = [countryList count];
	for (i=0; i<c; i++)  {
		if ([[countryList objectAt:i] player] != pNum)  {
			return NO;
		}
	}
	return YES;
}

- (BOOL)playerOccupiesCountries:(int)pNum
// return YES if pNum owns any countries at all
{
	int i, c = [countryList count];
	for (i=0; i<c; i++)  {
		if ([[countryList objectAt:i] player] == pNum)  {
			return YES;
		}
	}
	return NO;
}

- (BOOL)countriesAreUnoccupied
// returns YES if any countries don't have players
{
	int i, c = [countryList count];
	for (i=0; i<c; i++)  {
		if ([[countryList objectAt:i] player] == -1)  {
			return YES;
		}
	}
	return NO;
}

- makeAllCountriesUnoccupied
// clear the map in preparation for a new game.
{
	int i, c = [countryList count];
	for (i=0; i<c; i++)  {
		[[countryList objectAt:i] setPlayer:-1 andArmies:0];
	}
	[self update];
	return self;
}

- (int)numCountriesForPlayer:(int)p
// return the number of countries player p owns
{
	int num = 0;
	int i,c = [countryList count];
	
	for (i=0;i<c;i++)  {
		if ([[countryList objectAt:i] player] == p)  {
			num++;
		}
	}
	return num;
}

- (int)armiesForPlayer:(int)p
// returns the number of armies player p should get based on how many
// countries and continents he occupies
{
	int numCountries=0;
	int i, c = [countryList count];
	int list[42];
	int continentals;
	BOOL sa=YES, na=YES, eu=YES, af=YES, as=YES, au=YES;
	int numArmies;
	
	for (i=0;i<c;i++)  {
		if ([[countryList objectAt:i] player] == p)  {
			list[i]=YES;
			numCountries++;
		}  else  {
			list[i]=NO;
		}
	}
	// check continents
	for (i=0;i<=3;i++)  {
		if (list[i]==NO)  {
			sa=NO;
		}
	}
	for (i=4;i<=12;i++)  {
		if (list[i]==NO)  {
			na=NO;
		}
	}
	for (i=13;i<=19;i++)  {
		if (list[i]==NO)  {
			eu=NO;
		}
	}
	for (i=20;i<=25;i++)  {
		if (list[i]==NO)  {
			af=NO;
		}
	}
	for (i=26;i<=37;i++)  {
		if (list[i]==NO)  {
			as=NO;
		}
	}
	for (i=38;i<=41;i++)  {
		if (list[i]==NO)  {
			au=NO;
		}
	}
	continentals = (sa?2:0)+(na?5:0)+(eu?5:0)+(af?3:0)+(as?7:0)+(au?2:0);
	numArmies = (numCountries/3);
	if (numArmies<3) numArmies=3;
	numArmies += continentals;
	return numArmies;
}

- makeContinentLists
// init the continent lists
{
	int i;
	
	northAmerica = [[List allocFromZone:[self zone]] init];
	southAmerica = [[List allocFromZone:[self zone]] init];
	europe = [[List allocFromZone:[self zone]] init];
	africa = [[List allocFromZone:[self zone]] init];
	asia = [[List allocFromZone:[self zone]] init];
	australia = [[List allocFromZone:[self zone]] init];
	for (i=0;i<=3;i++)  {
		[southAmerica addObject:[countryList objectAt:i]];
	}
	for (i=4;i<=12;i++)  {
		[northAmerica addObject:[countryList objectAt:i]];
	}
	for (i=13;i<=19;i++)  {
		[europe addObject:[countryList objectAt:i]];
	}
	for (i=20;i<=25;i++)  {
		[africa addObject:[countryList objectAt:i]];
	}
	for (i=26;i<=37;i++)  {
		[asia addObject:[countryList objectAt:i]];
	}
	for (i=38;i<=41;i++)  {
		[australia addObject:[countryList objectAt:i]];
	}
	return self;
}

- populateGlobe
// init the country list by reading it from the typed stream file.
{
	NXTypedStream *ts;
		
	ts = NXOpenTypedStreamForFile([NXApp applicationFile:COUNTRYFILE], 
									NX_READONLY);
	countryList = NXReadObject(ts);
	NXCloseTypedStream(ts);
	WSInitArray([countryList count]);
	[countryList makeObjectsPerform:@selector(windowServerInit)];
	[self update];
	[self makeContinentLists];
	
	return self;
}

- countryList
{
	return countryList;
}

- northAmerica
{
	return northAmerica;
}

- southAmerica
{
	return southAmerica;
}

- europe
{
	return europe;
}

- africa
{
	return africa;
}

- asia
{
	return asia;
}

- australia
{
	return australia;
}

- theDefaultManager 
// for use by the countries who sometimes need to know defaults
{ 
	return theDefaultManager;
}

@end
