//
// $Id: World.m,v 1.11 1997/10/31 04:52:13 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: World.m,v 1.11 1997/10/31 04:52:13 nygard Exp $");

#import "World.h"

#import "City.h"
#import "Map.h"
#import "SNRandom.h"

//======================================================================
// The World keeps track of the world map, the total number of cities in
// the world (for the War Report), and the remaining neutral cities.  It
// creates the initial list of neutral cities by scanning through the map.
//
// Cities may only returned to the neutral city list if a player resigns
// from a game.  Otherwise, they are simply passed among players when
// captured.
//======================================================================

#define World_VERSION 1

@implementation World

+ (void) initialize
{
    if (self == [World class])
    {
        [self setVersion:World_VERSION];
    }
}

//----------------------------------------------------------------------
// This is used in single player games, and by the central game manager
// of distributed games.
//----------------------------------------------------------------------

- initWithMapNamed:(NSString *)mapName
{
    MapToken **mapPtrs;
    EMMapSize mapSize;
    EMMapLocation cityLocation;

    [super init];

    // Load map

    worldMap = [[NSUnarchiver unarchiveObjectWithFile:mapName] retain];
    if (worldMap == nil)
    {
        NSLog (@"Error loading map '%@'\n", mapName);
        [super dealloc];
        return nil;
    }

    mapSize = [worldMap mapSize];
    mapPtrs = [worldMap mapPtrs];

    // Create cities

    neutralCityList = [[NSMutableArray array] retain];

    for (cityLocation.row = 0; cityLocation.row < mapSize.height; cityLocation.row++)
    {
        for (cityLocation.column = 0; cityLocation.column < mapSize.width; cityLocation.column++)
        {
            if (EMTerrainComponent (mapPtrs[cityLocation.row][cityLocation.column]) == t_city)
            {
                City *aCity = [[[City alloc] initAtLocation:cityLocation ofMap:worldMap] autorelease];
                [neutralCityList addObject:aCity];
            }
        }
    }

    worldCityCount = [neutralCityList count];

    return self;
}

//----------------------------------------------------------------------
// This is used by client game managers in a distributed game.  The
// central game manager will manage the list of neutral cities.  The
// clients need the world for reports, and for the map when adding their
// player to the game.
//----------------------------------------------------------------------

- initWithMap:(Map *)aWorldMap
{
    [super init];

    worldMap = [aWorldMap retain];
    neutralCityList = nil;

    worldCityCount = [worldMap countTerrainType:t_city];

    return self;
}

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

- (void) dealloc
{
    SNRelease (worldMap);
    SNRelease (neutralCityList);

    [super dealloc];
}

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

- (Map *) worldMap
{
    return worldMap;
}

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

- (int) worldCityCount
{
    return worldCityCount;
}

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

- (City *) randomNeutralCity
{
    City *city;
    int count;
    int tmp;
    
    NSAssert (neutralCityList != nil, @"Neutral city list is nil.");

    count = [neutralCityList count];
    if (count == 0)
        return nil;

    tmp = [[SNRandom instance] randomNumberModulo:count];
    city = [[neutralCityList objectAtIndex:tmp] retain];
    [neutralCityList removeObjectAtIndex:tmp];
    
    return [city autorelease];
}

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

- (City *) neutralCityAtLocation:(EMMapLocation)target
{
    NSEnumerator *cityEnumerator;
    EMMapLocation cityLocation;
    City *city;

    NSAssert (neutralCityList != nil, @"Neutral city list is nil.");

    cityEnumerator = [neutralCityList objectEnumerator];
    while (city = [cityEnumerator nextObject])
    {
        cityLocation = [city cityLocation];
        if (cityLocation.row == target.row && cityLocation.column == target.column)
            break;
    }

    return city;
}

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

- (void) lostCity:(City *)aCity
{
    NSAssert (neutralCityList != nil, @"Neutral city list is nil.");

    // Hopefully, the city *is* in the list.
    [neutralCityList removeObject:aCity];
}

//----------------------------------------------------------------------
// If a player resigns, return their cities to the neutral city list.
//----------------------------------------------------------------------

- (void) addNeutralCities:(NSArray *)cities
{
    [neutralCityList addObjectsFromArray:cities];
}

@end
