
/* Generated by Interface Builder */

#import "GameCoordinator.h"
#import	"AccidentView.h"
#import	"DrivingAceView.h"
#import	"EndOfLimitView.h"
#import	"ExtraTankView.h"
#import	"FlatTireView.h"
#import	"GasolineView.h"
#import	"Mile_25_View.h"
#import	"Mile_50_View.h"
#import	"Mile_75_View.h"
#import	"Mile_100_View.h"
#import	"Mile_200_View.h"
#import	"OutOfGasView.h"
#import	"PunctureProofView.h"
#import	"RepairsView.h"
#import	"RightOfWayView.h"
#import	"RollView.h"
#import	"SpareTireView.h"
#import	"SpeedLimitView.h"
#import	"StopView.h"
#import	"mille.h"
#import	"prototypes.h"
#import	<appkit/appkit.h>
#import	<assert.h>
#import	<objc/objc-runtime.h>
#import	<objc/List.h>


												// This data structure is used to allocate cards and load the
												//	card deck.
	cardDeckCell	cardDeck[] = {	{ "AccidentView",		N_ACCIDENT,			C_ACCIDENT_HAZARD		},
									{ "DrivingAceView",		N_DRIVING_ACE,		C_DRIVING_ACE_SAFETY	},
									{ "EndOfLimitView",		N_END_OF_LIMIT,		C_END_OF_LIMIT_REMEDY	},
									{ "ExtraTankView",		N_EXTRA_TANK,		C_EXTRA_TANK_SAFETY		},
									{ "FlatTireView",		N_FLAT_TIRE,		C_FLAT_TIRE_HAZARD		},
									{ "GasolineView",		N_GASOLINE,			C_GASOLINE_REMEDY		},
									{ "OutOfGasView",		N_OUT_OF_GAS,		C_OUT_OF_GAS_HAZARD		},
									{ "PunctureProofView",	N_PUNCTURE_PROOF,	C_PUNCTURE_PROOF_SAFETY	},
									{ "RepairsView",		N_REPAIRS,			C_REPAIRS_REMEDY		},
									{ "RightOfWayView",		N_RIGHT_OF_WAY,		C_RIGHT_OF_WAY_SAFETY	},
									{ "RollView",			N_ROLL,				C_ROLL_REMEDY			},
									{ "SpareTireView",		N_SPARE_TIRE,		C_SPARE_TIRE_REMEDY		},
									{ "SpeedLimitView",		N_SPEED_LIMIT,		C_SPEED_LIMIT_HAZARD	},
									{ "StopView",			N_STOP,				C_STOP_HAZARD			},
									{ "Mile_25_View",		N_25,				C_25					},
									{ "Mile_50_View",		N_50,				C_50					},
									{ "Mile_75_View",		N_75,				C_75					},
									{ "Mile_100_View",		N_100,				C_100					},
									{ "Mile_200_View",		N_200,				C_200					},
									0
	};
	
	
	
@implementation GameCoordinator

- setMessagesText:( Text * ) anObject
{

	float	ourGray = [[ anObject opaqueAncestor ] backgroundGray ];
	
	
    messagesText = anObject;
	if( ourGray < 0.0 )
		ourGray = [[ messagesText window ] backgroundGray ];
    [[[ messagesText setEditable:NO ] setSelectable:NO ] setBackgroundGray:ourGray ];
    
    return self;
}

- setDrawPile:anObject
{

    drawPile = anObject;
   [[[[ drawPile setTag:P_DRAW ] setTitle:"Draw Pile" ] setFrameMode:YES ] setCardsEnabled:YES ];
    
    return self;
}

- setDiscardPile:anObject
{

    discardPile = anObject;
    [[[[ discardPile setTag:P_DISCARD ] setTitle:"Discard Pile" ] setFrameMode:YES ] setTrackingEnabled:YES ];
    
    return self;
}

- ( Window * )gameWindow
{


	return gameWindow;
}


- ( Window * )scoreWindow
{


	return scoreWindow;
}


- ( Window * )cardsPlayedWindow
{


	return cardsPlayedWindow;
}


- appDidInit:sender
{

	int				i;
	NXRect			handFrame = {	-25, -25, 10, 10 };
	HandTileView	*computerHand;
	

												// Create all of the cards and add them to the
												//	deck.
	for( i = 0; i < ( sizeof( cardDeck ) / sizeof( cardDeckCell )); ++ i )
		if( cardDeck[ i ].cardClassName ) {
			int		j;
			id		aCardClass = objc_getClass( cardDeck[ i ].cardClassName );
		
			for( j = 0; j < cardDeck[ i ].numCards; ++j )
				[ drawPile addCard:( CardView * )[[[[ aCardClass allocFromZone:[ NXApp zone ]] init  ] setDragCoordinator:dragCoordinator ] setTag:cardDeck[ i ].cardType ] :self ];
		}
	
												// The computer hand tile view isn't on the board.
												//	we have to create it and locate it somewhere not in the window's
												//	frame.
	computerHand = [ HandTileView newFrame:&handFrame ];
	[[ gameWindow contentView ] addSubview:computerHand ];
	[ computerPlayer setHand:computerHand ];
	
												// Set the attributes of the views for the players.
	[[ computerPlayer speedPile ] setTrackingEnabled:YES ];
	[[ computerPlayer battlePile ] setTrackingEnabled:YES ];
	[[ player speedPile ] setTrackingEnabled:YES ];
	[[ player battlePile ] setTrackingEnabled:YES ];
	[[ player safetyPile ] setTrackingEnabled:YES ];
	[[[ player handPile ] setTrackingEnabled:YES ] setCardsEnabled:YES ];
	[[ player distancePile ] setTrackingEnabled:YES ];
	
	[ discardPile setTrackingEnabled:YES ];

												// Initialize scores not maintained by
												//	the players.
	[ OTHER_HAND_TOTAL_SCORE(computerPlayer)		setIntValue:0 ];								
	[ OTHER_OVERALL_TOTAL_SCORE(computerPlayer)		setIntValue:0 ];
	[ OTHER_GAMES_SCORE(computerPlayer)				setIntValue:0 ];
	[ MAIN_HAND_TOTAL_SCORE(computerPlayer)			setIntValue:0 ];
	[ MAIN_OVERALL_TOTAL_SCORE(computerPlayer)		setIntValue:0 ];
	[ MAIN_GAMES_SCORE( computerPlayer )			setIntValue:0 ];
	[ OTHER_HAND_TOTAL_SCORE(player)			setIntValue:0 ];								
	[ OTHER_OVERALL_TOTAL_SCORE(player)			setIntValue:0 ];
	[ OTHER_GAMES_SCORE(player)					setIntValue:0 ];
	[ MAIN_HAND_TOTAL_SCORE(player)				setIntValue:0 ];
	[ MAIN_OVERALL_TOTAL_SCORE(player)			setIntValue:0 ];
	[ MAIN_GAMES_SCORE( player )				setIntValue:0 ];

	[ gameWindow display ];

												// Player goes first.
	lastShuffler = computerPlayer ;
	
	return [ self newGame ];
}


// Enough, Enough, Enough of this foolishness.
//	Lets get to the game.
// The methods below IS THE GAME...

- newGame
{

	
	[ player newGame ];
	[ computerPlayer newGame ];	

	[ self newHand ];
	
	return self;
}


- newHand
{

	int		i;

	
												// Set the hand distance limit.
	[ self setHandLimit:HAND_DISTANCE_LIMIT ];
	
												// Clear and messages.
	[[ messagesText selectAll:self ] replaceSel:"" ];
	
												// Move all of the cards back to the draw pile
												//	and reinitialize the player for a new hand.
												//	Also erases scores for the player's hand.
	[ discardPile sendAllCardsTo:drawPile ];
	[ computerPlayer newHand ];
 	[ player newHand ];
											
												// Make sure all of the cards are face down
												//	in the draw pile.
	for( i = 0; i < NUMBER_OF_CARDS_IN_DECK; ++i )
		[( CardView * )[[ drawPile subviews ] objectAt:i ] setShowTopFace:YES ];

	[ self shuffleDeck ];
	
												// Instruct all players to draw cards.
	for( i = 0; i < ( HAND_SIZE - 1 ); ++i ) {
		[ computerPlayer drawCard ];
		[ player drawCard ];
	}
	
												// Clear the display tracking of what cards 
												//	were played.
	[ cardsTracker newHand ];
	
	[ gameWindow display ];
	
												// If the computer goes first then
												//	do it.
	if( lastShuffler == computerPlayer )
		[ computerPlayer playMove ];
	
	return self;
}


- shuffleDeck
{

	int		i, j;
	

												// The addCard: and removeCard: methods of card holder objects
												//	are too restrictive for shuffling.  Therefore we're going
												//	do deal with the view hierarchy directly.
	for( j = 0; j < 5; ++j ) {
		extern void	srandom( int );
		
		srandom( time( NULL ));
		for ( i = 0; i < NUMBER_OF_CARDS_IN_DECK; i++ ) {
			int	 		r = roll( 1, NUMBER_OF_CARDS_IN_DECK ) - 1;
			CardHolder	*firstCard = [[ drawPile subviews ] objectAt:i ],
						*secondCard = [[ drawPile subviews ] objectAt:r ];
		
			assert( r >= 0 && r < NUMBER_OF_CARDS_IN_DECK );
			[ drawPile replaceSubview:firstCard with:[ secondCard removeFromSuperview ]];
			if( r > ([[ drawPile subviews ] count ] - 1 ))
				r -= 1;
			[ drawPile addSubview:firstCard :NX_BELOW relativeTo:[[ drawPile subviews ] objectAt:r ]];
		}
	}
	[ gameWindow display ];
	
	return self;
}


- ( int )handLimit
{


	return handLimit;
}


- setHandLimit:( int )aLimit
{


	handLimit = aLimit;
	
	return self;
}



- ( BOOL )willPlayerExtend
{

	BOOL	retVal = NO;
	
	
	if( handLimit == HAND_DISTANCE_LIMIT )
		if( NXRunAlertPanel( "", "Extension?", "Yes", "No", NULL ) == NX_ALERTDEFAULT )  {
			[ self setHandLimit:HAND_DISTANCE_EXTENSION_LIMIT ];
			[[ messagesText selectAll:self ] replaceSel:"Player chooses to hand." ];
			retVal = YES;
		}

	return retVal;
}


- handOver
{


												// Sum the hand and overall totals
												//	for both players.
	[[ computerPlayer sumHand ] sumOverall ];
	[[ player sumHand ] sumOverall ];
	
												// Choose a new shuffler.
	if( lastShuffler == player )
		lastShuffler = computerPlayer;
	else
		lastShuffler = player;
		
												// Is the game over?
	if(([ OTHER_OVERALL_TOTAL_SCORE( player ) intValue ] >= GAME_DISTANCE_LIMIT ) || ([ OTHER_OVERALL_TOTAL_SCORE( computerPlayer ) intValue ] >= GAME_DISTANCE_LIMIT )) {

												// Game over.
												// Choose a winner and bump his score.
		if([ OTHER_OVERALL_TOTAL_SCORE( player ) intValue ] != [ OTHER_OVERALL_TOTAL_SCORE( computerPlayer ) intValue ]) {
			if([ OTHER_OVERALL_TOTAL_SCORE( player ) intValue ] >= [ OTHER_OVERALL_TOTAL_SCORE( computerPlayer ) intValue ])
				[ OTHER_GAMES_SCORE( player ) setIntValue:[ OTHER_GAMES_SCORE( player ) intValue ] + 1 ];
			else
				[ OTHER_GAMES_SCORE( computerPlayer ) setIntValue:[ OTHER_GAMES_SCORE( computerPlayer ) intValue ] + 1 ];

			[ MAIN_GAMES_SCORE( player )			setIntValue:[ OTHER_GAMES_SCORE( player ) intValue ]];
			[ MAIN_GAMES_SCORE( computerPlayer )	setIntValue:[ OTHER_GAMES_SCORE( computerPlayer ) intValue ]];
		}
	 											// Start a new game.
	 	[ self newGame ];
	} else {
	 
	 											// Hand over.
												// Start a new hand.
		[ self newHand ];
	}

	return self;
}


- computerVsComputer:sender
{

	id				anAlert =  NXGetAlertPanel( NULL, "Computer vs Computer", "Quit", NULL, NULL );
	NXModalSession	*session =  [ NXApp beginModalSession:NULL for:anAlert ];
	int				modal;
	id				oldShuffler = lastShuffler,
					lastPlayer = player;
	

	do {
	
		[ lastPlayer playMove ];

										// Kludge.
										//	Has the shuffler changed?
										//	(indicates a new hand.)
		if( oldShuffler == lastShuffler ) {
		
										// New hand.
										//	Who went first?
										// If the computer went first then
										//	have the player move.  If the player is
										//	to go first then move now.
			[ player playMove ];
				
										// Computer goes next.
			lastPlayer = computerPlayer;
			oldShuffler = lastShuffler;
		} else {
										// Same hand.
										//	Choose next player to move.
			if( lastPlayer == player )
				lastPlayer = computerPlayer;
			else
				lastPlayer = player;
		}
		modal = [ NXApp runModalSession:session ];
	} while( modal == NX_RUNCONTINUES );
	
	[ NXApp endModalSession:session ];
	NXFreeAlertPanel( anAlert );
	
	return self;
}



@end
