//
// $Id: NewGameController.m,v 1.11 1997/10/31 04:51:57 nygard Exp $
//

//
//  This file is a part of Empire, a game of exploration and conquest.
//  Copyright (C) 1996  Steve Nygard
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  You may contact the author by:
//     e-mail:  nygard@telusplanet.net
//

#import "Empire.h"

RCSID ("$Id: NewGameController.m,v 1.11 1997/10/31 04:51:57 nygard Exp $");

#import "NewGameController.h"
#import "EmpireImageVendor.h"
#import "Human.subproj/Human.h"
#import "Client.h"
#import "Brain.h"
#import "ServerController.h"
#import "DistributedGameManager.h"

//======================================================================
// The New Game Controller provides access to the panel for selecting
// the parameters of a new game.  It's creates the game manager for a
// new game, and instructs it on the type and parameters of players
// to add to the game.
//
// Also, it provides a window for clients to select the parameters of
// their player in distributed games.
//
// The controller observes the server controller so it can update the
// list of available remote hosts.
//
// It will also need to know the type of computer players that are
// available.
//======================================================================

@implementation NewGameController

- (void) awakeFromNib
{
    int l;
    EmpireImageVendor *vendor;
    NSImage *city;
    NSImage **onLand;
    NSImage **onWater;
    NSImage **onCity;
    int loop_to_land[2] = {0, 2};
    int loop_to_water[7] = {1, 3, 4, 5, 6, 8, 9};

    NSString *resourcePath, *mapName;
    NSBundle *bundle;
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *tmp;

    vendor = [EmpireImageVendor instance];

    [vendor player:p_player1:&city:&onLand:&onWater:&onCity:NULL];
    [[player1UnitImageMatrix cellAtRow:0 column:0] setImage:city];
    for (l = 0; l < 2; l++)
        [[player1UnitImageMatrix cellAtRow:0 column:l+1] setImage:onLand[loop_to_land[l]]];
    for (l = 0; l < 7; l++)
        [[player1UnitImageMatrix cellAtRow:0 column:l+3] setImage:onWater[loop_to_water[l]]];

    [vendor player:p_player2:&city:&onLand:&onWater:&onCity:NULL];
    [[player2UnitImageMatrix cellAtRow:0 column:0] setImage:city];
    for (l = 0; l < 2; l++)
        [[player2UnitImageMatrix cellAtRow:0 column:l+1] setImage:onLand[loop_to_land[l]]];
    for (l = 0; l < 7; l++)
        [[player2UnitImageMatrix cellAtRow:0 column:l+3] setImage:onWater[loop_to_water[l]]];

    [vendor player:p_player3:&city:&onLand:&onWater:&onCity:NULL];
    [[player3UnitImageMatrix cellAtRow:0 column:0] setImage:city];
    for (l = 0; l < 2; l++)
        [[player3UnitImageMatrix cellAtRow:0 column:l+1] setImage:onLand[loop_to_land[l]]];
    for (l = 0; l < 7; l++)
        [[player3UnitImageMatrix cellAtRow:0 column:l+3] setImage:onWater[loop_to_water[l]]];
  
    [vendor attach:self];

    [player1ColorWell setColor:[vendor colorForPlayer:p_player1]];
    [player2ColorWell setColor:[vendor colorForPlayer:p_player2]];
    [player3ColorWell setColor:[vendor colorForPlayer:p_player3]];

    bundle = [NSBundle bundleForClass:[self class]];

    mapName = [defaults stringForKey:DK_DefaultMap];

    resourcePath = [bundle pathForResource:mapName ofType:@"map"];
    NSAssert1 (resourcePath != nil, @"Could not find %@.", mapName);

    [mapTextfield setStringValue:resourcePath];

    tmp = [defaults stringForKey:DK_DefaultPlayer1Type];
    [player1TypePopup selectItemWithTitle:tmp];

    tmp = [defaults stringForKey:DK_DefaultPlayer2Type];
    [player2TypePopup selectItemWithTitle:tmp];

    tmp = [defaults stringForKey:DK_DefaultPlayer3Type];
    [player3TypePopup selectItemWithTitle:tmp];

    tmp = [defaults stringForKey:DK_DefaultPlayer1Name];
    [player1NameTextfield setStringValue:tmp];

    tmp = [defaults stringForKey:DK_DefaultPlayer2Name];
    [player2NameTextfield setStringValue:tmp];

    tmp = [defaults stringForKey:DK_DefaultPlayer3Name];
    [player3NameTextfield setStringValue:tmp];
}

//----------------------------------------------------------------------

- initWithBrain:(Brain *)theBrain
{
    NSString *nibFile;
    BOOL loaded;

    [super init];

    clientGameManager = nil;

    nibFile = @"NewGamePanel.nib";
    loaded = [NSBundle loadNibNamed:nibFile owner:self];
    if (loaded == NO)
    {
        NSLog (@"Could not load %@.", nibFile);
        [super dealloc];
        return nil;
    }

    serverController = [theBrain serverController];
    if (serverController != nil)
    {
        [serverController attach:self];
    }

    return self;
}

//----------------------------------------------------------------------

- (void) dealloc
{
    SNRelease (clientGameManager);
    
    [super dealloc];
}

//----------------------------------------------------------------------

- (void) updatePlayer1Color:sender
{
    [[EmpireImageVendor instance] setColor:[player1ColorWell color] forPlayer:p_player1]; 
}

//----------------------------------------------------------------------

- (void) updatePlayer2Color:sender
{
    [[EmpireImageVendor instance] setColor:[player2ColorWell color] forPlayer:p_player2]; 
}

//----------------------------------------------------------------------

- (void) updatePlayer3Color:sender
{
    [[EmpireImageVendor instance] setColor:[player3ColorWell color] forPlayer:p_player3]; 
}

//----------------------------------------------------------------------

- (void) createNewGame:sender
{
    int playerCount;
    DistributedGameManager *gameManager;
    BOOL ps[3];
    Client *remoteClient;
    int remoteClientIndex;
  
    int l, m;
    struct {
        int player;
        NSTextField *nameText;
        NSSlider *productionEffSlider;
        NSSlider *combatEffSlider;
        NSPopUpButton *remoteClientPopup;
    } player_things[] = {
        { p_player1, player1NameTextfield, player1ProductionEffSlider,
          player1CombatEffSlider, player1RemoteClientPopup },
        { p_player2, player2NameTextfield, player2ProductionEffSlider,
          player2CombatEffSlider, player2RemoteClientPopup },
        { p_player3, player3NameTextfield, player3ProductionEffSlider,
          player3CombatEffSlider, player3RemoteClientPopup }
    };
#if 0
    // Check whether there is a game in progress

    if ([gameManager gameInProgress] == YES)
    {
        if (NSRunAlertPanel (@"New Game", @"There is already a game in progress or starting.", @"Cancel", @"Start new game", nil) == NSAlertDefaultReturn)
        {
            return;
        }
        
        [gameManager stopGame];
    }
#endif
    // Count the number of participating players

    ps[0] = [[player1TypePopup selectedItem] tag]; // Why not use indexOfSelectedItem?
    ps[1] = [[player2TypePopup selectedItem] tag];
    ps[2] = [[player3TypePopup selectedItem] tag];

    playerCount = ((ps[0] > 0) ? 1 : 0) + ((ps[1] > 0) ? 1 : 0) + ((ps[2] > 0) ? 1 : 0);
  
    if (playerCount < 1)
    {
        NSRunAlertPanel (@"New Game", @"There must be at least one player.", @"", nil, nil);
        return;
    }

    for (l = 0; l < 3; l++)
    {
        if (ps[l] == 3)
        {
            NSPopUpButton *rc_popup = player_things[l].remoteClientPopup;
            remoteClientIndex = [rc_popup indexOfSelectedItem];

            if (remoteClientIndex < 1)
            {
                NSRunAlertPanel (@"New Game", @"You must select a client for the Remote player %d.", @"", nil, nil, l);
                return;
            }
        }
    }

    for (l = 0; l < 3; l++)
    {
        if (ps[l] == 3)
        {
            remoteClientIndex = [player_things[l].remoteClientPopup indexOfSelectedItem];

            for (m = l + 1; m < 3; m++)
            {
                if (ps[l] == 3 && [player_things[m].remoteClientPopup indexOfSelectedItem] == remoteClientIndex)
                {
                    NSRunAlertPanel (@"New Game", @"Remote players %d and %d must have different clients.",
                                     @"", nil, nil, l + 1, m + 1);
                    return;
                }
            }
        }
    }

    gameManager = [[[DistributedGameManager alloc] init] autorelease];

    // Start a new game with the given map name
    [gameManager startGameWithMapNamed:[mapTextfield stringValue]];
  
    [[sender window] orderOut:self];

    for (l = 0; l < 3; l++)
    {
        int pn = player_things[l].player;
        NSString *name = [player_things[l].nameText stringValue];
        int pe = [player_things[l].productionEffSlider intValue];
        int ce = [player_things[l].combatEffSlider intValue];
        NSPopUpButton *rc_popup = player_things[l].remoteClientPopup;
    
        switch (ps[l])
        {
          case 0:
              break;

          case 1:
              [gameManager addPlayer:pn name:name type:@"Human"
                           withEfficiencies:pe:ce];
              break;

          case 3:
              remoteClientIndex = [rc_popup indexOfSelectedItem];

              NSAssert (remoteClientIndex > 0, @"No remote player chosen!");

              //NSLog (@"remote player[%d]: '%@'\n", remoteClientIndex, [rc_popup titleOfSelectedItem]);
              remoteClient = [[serverController clientAtIndex:remoteClientIndex - 1] client];
              [gameManager addRemotePlayer:pn forClient:remoteClient];
              break;

          default:
              NSLog (@"Unknown player type #%d", ps[l]);
        }
    }

    // Begin game

    [gameManager beginGame];
}

//----------------------------------------------------------------------

- (void) aboutPlayer1:sender
{
    [NSApp runModalForWindow:aboutPanel]; 
}

//----------------------------------------------------------------------

- (void) aboutPlayer2:sender
{
    [NSApp runModalForWindow:aboutPanel]; 
}

//----------------------------------------------------------------------

- (void) aboutPlayer3:sender
{
    [NSApp runModalForWindow:aboutPanel]; 
}

//----------------------------------------------------------------------

- (void) aboutStopAction:sender
{
    [NSApp stopModal];
    [aboutPanel orderOut:self]; 
}
  
//----------------------------------------------------------------------

- (void) setMapPanel:sender
{
    NSArray *types = [NSArray arrayWithObject:@"map"];
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];

    [openPanel setAllowsMultipleSelection:NO];

    if ([openPanel runModalForTypes:types] == NSOKButton)
    {
        [mapTextfield setStringValue:[openPanel filename]];
    } 
}

//----------------------------------------------------------------------

- (void) showPanel
{
    [newGamePanel makeKeyAndOrderFront:self];
}

//----------------------------------------------------------------------

- (void) choosePlayer:(Player)number forGameManager:(DistributedGameManager *)gameManager
{
    int l;
    EmpireImageVendor *vendor;
    NSImage *city;
    NSImage **onLand;
    NSImage **onWater;
    NSImage **onCity;
    int loop_to_land[2] = {0, 2};
    int loop_to_water[7] = {1, 3, 4, 5, 6, 8, 9};
    id nameTexts[] = { player1NameTextfield, player2NameTextfield, player3NameTextfield };
    NSRect frameRect;

    NSAssert (clientGameManager == nil, @"Expected client game manager to be nil.");
    clientGameManager = [gameManager retain];

    ncPlayerNumber = number;

    frameRect = [newClientPanel frame];
    frameRect.origin.x += number * 24;
    frameRect.origin.y -= number * 24;
    [newClientPanel setFrameOrigin:frameRect.origin];

    [ncPlayerBox setTitle:[NSString stringWithFormat:@"Player %d", number]];

    vendor = [EmpireImageVendor instance];

    [vendor player:number:&city:&onLand:&onWater:&onCity:NULL];
    [[ncUnitImageMatrix cellAtRow:0 column:0] setImage:city];
    for (l = 0; l < 2; l++)
        [[ncUnitImageMatrix cellAtRow:0 column:l+1] setImage:onLand[loop_to_land[l]]];
    for (l = 0; l < 7; l++)
        [[ncUnitImageMatrix cellAtRow:0 column:l+3] setImage:onWater[loop_to_water[l]]];

    [ncColorWell setColor:[vendor colorForPlayer:number]];
    [ncNameTextfield takeStringValueFrom:nameTexts[number - p_player1]];

    [newClientPanel makeKeyAndOrderFront:self];
}

//----------------------------------------------------------------------

- (void) createNewClient:sender
{
    int playerType = [[ncTypePopup selectedItem] tag];

    int pn;
    NSString *name;
    int pe;
    int ce;

    NSAssert (clientGameManager != nil, @"Expected a client game manager to exist.");

    [newClientPanel orderOut:self];

    pn = ncPlayerNumber;
    name = [ncNameTextfield stringValue];
    pe = [ncProductionEffSlider intValue];
    ce = [ncCombatEffSlider intValue];
    
    switch (playerType)
    {
      case 0:
          break;

      case 1:
          [clientGameManager addPlayer:pn name:name type:@"Human"
                             withEfficiencies:pe:ce];
          break;

      default:
          NSLog (@"Unknown player type #%d", playerType);
    }

    [clientGameManager notifyMasterForPlayer:pn];
    SNRelease (clientGameManager);
}

//======================================================================
// Empire Image Vendor Notification
//======================================================================

- (void) vendorImagesUpdated:(BOOL)player1:(BOOL)player2:(BOOL)player3:(BOOL)other
{
    if (player1)
        [player1UnitImageMatrix setNeedsDisplay:YES];

    if (player2)
        [player2UnitImageMatrix setNeedsDisplay:YES];

    if (player3)
        [player3UnitImageMatrix setNeedsDisplay:YES];
}

//======================================================================
// Window Delegate
//======================================================================

- (void) windowDidBecomeKey:(NSNotification *)notification
{
    NSWindow *theWindow = [notification object];
  
    if (theWindow == newGamePanel)
    {
        [theWindow makeFirstResponder:okayButton];
    }
}

//======================================================================
// Client Host Notification
//======================================================================

- (void) newClientHost:(NSString *)hostname
{
    [player1RemoteClientPopup addItemWithTitle:hostname];
    [player2RemoteClientPopup addItemWithTitle:hostname];
    [player3RemoteClientPopup addItemWithTitle:hostname];
}

//----------------------------------------------------------------------

- (void) removedClientHostNumber:(int)index
{
    [player1RemoteClientPopup removeItemAtIndex:index + 1];
    [player2RemoteClientPopup removeItemAtIndex:index + 1];
    [player3RemoteClientPopup removeItemAtIndex:index + 1];
}

@end
