
#import "NVDealer.h"
 
// This should return a float between 0 and 1
float frandom()
{
	float val = (random() & 0x7fffffff);
	val /= 0x7fffffff;
	return val;
}
 
float randBetween(float a, float b)
{
	float val, scale, t;

	if (a > b)
	{	t = a; a = b; b = t;
	}
	
	scale = (b-a);
	val = scale * frandom();
	return (a + val);
}

@implementation NVDealer

/***************************************************************************************
 *                            Inspector And Rules Methods                              *
 ***************************************************************************************/
- (BOOL)hasRules
/*
	NO if the module does not have a Rules Window, YES if it does.  The default
	method returns NO.
*/
{
	return NO;
}

- inspector:sender
/*
	Should return the inspector for the game module.  The default method returns nil,
	indicating that there is no inspector available.
*/
{
	if(inspector)
		return [inspector contentView];
	else
		return nil;
}

- inspectorWillBeRemoved:sender
/*
	Sent when this module's inspector is about to be replace with another one.
*/
{
	return self;
}

- inspectorWasInstalled:sender
/*
	Sent just after this module's inspector has been installed.
*/
{
	return self;
}

- rulesWindow
/*
	Should return the window that houses the module's rules, if present.  The
	default method returns nil.  
*/
{
	char path[MAXPATHLEN+1];
	
	if(!rulesWindow)
	{
		if ([bundle getPath:path forResource:"rules" ofType:"nib"]) 
		{
			[NXApp loadNibFile:path 
						 owner:self 
					 withNames:NO 
					  fromZone:[self zone]];
		}
		else
		{
			fprintf(stderr, "Couldn't load rules nib file!\n");
			return nil;
		}
	}

	return rulesWindow;
}

- setPreferences:sender
{
	return nil;
}

- revertPreferences:sender
{
	return nil;
}

- preferencesChanged:sender
{
	[Prefs() prefsChanged:sender];
	return self;
}

/***************************************************************************************
 *                                  Player Methods                                     *
 ***************************************************************************************/
- (int)collectAllBetsForPlayer:(int)playerNum
{
	return 0;
}

- currentPlayer
{
	return [pitBoss currentPlayer];
}

- (int)numPlayers
{
	return [pitBoss numPlayers];
}

- playerDidBet:aPlayer
{
	return self;
}

- playerDidClose:aPlayer
/*
 *  Sent after a player has closed and is no longer part of the game.  No messages
 *  should be sent to aPlayer.  This method should just do some internal cleanup
 *  if necessary.
 */
{
	return self;
}

- playerDidJoin:player
{
	return self;
}

/*
- (BOOL)player:aPlayer willBet:(int)betType onView:sender
{
	return YES;
}
*/

- (BOOL)playerWillClose:aPlayer
/*
 *  Should return YES if it is okay to close this player, NO if it is not.  The
 *  default implementation returns YES.
 */
{
    return YES;
}

- (BOOL)playerWillJoin:sender
{
	return YES;
}

/***************************************************************************************
 *                                  Table Methods                                      *
 ***************************************************************************************/
- gameView
{	
	return [gameView contentView];
}

- setTableMax:(int)aNumber
{
    tableMax = aNumber;
    
    return self;
}
 
- setTableMin:(int)aNumber
{    
    tableMin = aNumber;
    
    return self;
}

- (int) tableMax
{
    return tableMax;
}

- (int) tableMin
{
    return tableMin;
}


- table
{
	return table;
}

- view:aView wasLoadedOnTable:tableObject
{
	table = tableObject;

	return self;
}

/***************************************************************************************
 *                               Other Misc. Methods                                   *
 ***************************************************************************************/
- initFromBundle:aBundle withName:(const char *)name
/*
	Called by the Casino object when loading a game module.  This method
	initializes the NVDealer class and loads its table nib file.  Objects that override
	this method must precede new code with a call to super.
*/
{
    char path[MAXPATHLEN+1];
	int seed;

    [super init];
		
	pitBoss = PBoss();
	dealerText = [pitBoss dealerText];
	
    bundle = aBundle;
    
	gameName = NXCopyStringBufferFromZone(name, [self zone]);

    // seed the random number generator...
    seed = time(0);
	srandom(seed);

    if ([bundle getPath:path forResource:"table.nib" ofType:NULL])
    {
		[NXApp loadNibFile:path 
				     owner:self
			     withNames:NO 
				  fromZone:[self zone]];
    }
	
    return self;
}

- finishSessionAndClose
/*
	This message is sent when a new game is being loaded.  If there is any clean up
	to do, this is where to do it.
*/
{
	return self;
}

- pitBoss
{
	return pitBoss;
}

- (int)randomIntBetween:(int)lowNum :(int)highNum
{
	return (int) randBetween((float)lowNum, (float)highNum+1);
}

- (float)randomFloatBetween:(float)lowNum :(float)highNum
{
	return randBetween(lowNum, highNum+1);
}

- say:(char *)text
{
	[dealerText setStringValue:text];
	NXPing();
	
	return self;
}

- selectCellWithTag:(int)tag forPopUpButton:button
/*
	I've added this because its not at all intuitive to select a cell in a pop up
	list, especially when you only have a handle on the popUpButton.
*/
{
	[[[button target] itemList] selectCellWithTag:tag];
	[button setTitle:[[[[button target] itemList] selectedCell] title]];
	
	return self;
}

- (int)tagOfSelectedCellInPopUpButton:popUpButton
{
	return [[[[popUpButton target] itemList] selectedCell] tag];
}

- runDebug
/*
	Sent by a NVWindow when the user holds down the Alternate, Control, and Shift
	keys while depressing the 'd' key.
	
	Overide this method to bring up debugging panels or whatever.
*/
{
	return self;
}

/***************************************************************************************
 *                        Card/CardPile/CardPileView Methods                           *
 ***************************************************************************************/
- addDecks:(int)n toView:view emptyFirst:(BOOL)willEmpty andShuffle:(BOOL)willShuffle
{
	id pile = [view cardPile];
	
	
	if(willEmpty)
	{
		[pile empty];
		[view display];
		NXPing();
	}
	
	[pile addDecks:n];
	
	if(willShuffle)
	{
		[self say:"Shuffling Deck..."];
		NXPing();
		
		[pile shuffle];
		
		[PBoss() playSound:NV_SHUFFLESOUND];
		
		sleep(5);
		[self say:""];
	}
	
	[view display]; 
	NXPing();
	
	return self;
}

- newDeck:(int)numDecks forView:view
{
	return [self addDecks:numDecks toView:view emptyFirst:YES andShuffle:YES];
}


- setUserValueForPile:cardPile aceHigh:(BOOL)flag
{
	int i, value, numCards = [cardPile cardCount];
	id card;
	
	for(i=0; i<numCards; i++)
	{
		card = [cardPile cardAt:i];
		value = [card value];
		
		if(value == CS_ACE && flag)
			[card setUserValue:CS_KING+1];
		else
			[card setUserValue:value];
	}
	
	return self;
}

@end

@implementation NVDealer(BetViewDelegate)

- mouseEnteredView:sender
/*
	When a mouse enters a tableView, it sends this message to us.  We use it to
	update the tableAdvice text field.
*/
{
    return self;
}

- mouseExitedView:sender
{
	return self;
}

- player:aPlayer willBet:(int)betType onView:aBetView
{
	return self;
}

- (BOOL)playerWillDragChipAtRow:(int)row andCol:(int)col fromView:sender
/*
	Sent by a BetView when a player wishes to drag a chip pile.  Overwrite this
	method to return YES if your module will allow drag and drop.
*/
{
	return NO;
}

- playerDraggedChipAtRow:(int)row andCol:(int)col fromView:sender
/*
	Sent by a BetView after a player drags a chip pile.  
*/
{
	return self;
}

- (BOOL)playerWillDropChipAtRow:(int *)row andCol:(int *)col InView:sender
/*
	Sent by a BetView when a player wants to drop a chip pile on it.  Over write this
	method to return YES if your module allows drag and drop.
*/
{
	return NO;
}

- playerDroppedChipAtRow:(int)row andCol:(int)col inView:sender
/*
	Sent by a BetView when a player drops a chip on it.  Overwrite this method to add
	the pile to the betview.  Check out the blackjack module to see how this is done.
*/
{
	return self;
}

@end

