/* CVS: $Id: World.java,v 1.50 2001/03/18 23:52:16 gvijf Exp $ */

package evolution;

import java.util.*;
import java.io.*;

import evolution.events.*;
import evolution.actions.Action;
import evolution.actions.IllegalLandTypeException;
import evolution.resources.NotEnoughResourcesException;
import evolution.resources.NoSuchResourceException;
import evolution.lands.NotEnoughLandResourcesException;
import evolution.lands.SquareOfLand;
import evolution.lands.IllegalPlacementException;
import evolution.HumanSelection;
import evolution.actions.ActionKnowledgeCatalog;
import evolution.resources.ResourceKnowledgeCatalog;
import evolution.resources.Resource;
import evolution.constructions.ConstructionKnowledgeCatalog;
import evolution.constructions.Construction;

/**
 * Represents the game world.
 * This is the main class.
 * @stereotype singleton
 */
public class World {

    /**
     * Create a new world.
     * The world will be created in the pause mode, so one needs
     * to call world.startGame() to start playing.
     * @param width The width of the game board
     * @param height The height of the game board
     * @param fileName The main configuration file on which this world
     * should be based. From this configuration file the path is stripped
     * and used as the resource path to load other config files and images.
     */
    public World(WorldController c, String fileName, int width, int height) throws FileNotFoundException, IOException {
        if(instance != null)
            throw new RuntimeException("There can only be one world");
        instance = this;
        setWorldController(c);
        Evolution.initialize();
        EvolutionKnowledgeCatalog.initialize(fileName);
        gameBoard = GameBoard.create(width, height);
        resources = ResourceKnowledgeCatalog.getInst().getResourceInstances();
        creationPower = new CreationPower();
        //EventManager.getInst().subscribe(this, "HumanDiedEvt");
    }

    /**
     * Return the instance of this world.
     */
    public static World getInst() {
        return instance;
    }

    /**
     * The width of the game board.
     */
    public int getWidth() {
        return gameBoard.getWidth();
    }

    public void refresh() {
        for(int i = 0; i < getWidth(); i++) {
            for(int j = 0; j < getHeight(); j++)
                EventManager.getInst().signalEvent(
                	new SquareChangedEvt(getGameBoard().getSquare(i, j)));
        }
    }

    /**
     * The height of the game board.
     */
    public int getHeight() {
        return gameBoard.getHeight();
    }

    /**
     * Check whether the given human is selected or not.
     */
    public boolean isSelected(Human human) {
        return getWorldController().isSelected(human);
    }

    /**
     * Check whether the given human is the last selected human or not.
     */
    public boolean isActiveSelected(Human human) {
        return getWorldController().isActiveSelected(human);
    }

    /**
     * Create a human on a sqyare of land.
     */
    public void createHuman(SquareOfLand sq) throws CreationPowerInsufficientException, IllegalPlacementException {
	    creationPower.decreasePowerHuman();
    	Human human = new Human(sq);
    }

    /**
     * Return the game board.
     */
    public GameBoard getGameBoard() {
        return gameBoard;
    }

    /**
     * Information about the world resources.
     */
    public InfoList getResourcesInfo() {
        InfoList resourcesInfo = ResourceKnowledgeCatalog.getInst().getResourcesInfo();
        resourcesInfo.add("Creation power", InfoList.VALUE, creationPower.getAmount());
        double levelOfTheGoal = EvolutionKnowledgeCatalog.getInst().calcGoal(getResources());
        resourcesInfo.add("Level of the goal", InfoList.VALUE, levelOfTheGoal);
        return resourcesInfo;
    }

    /**
     * Returns a list of world resources.
     */
    public Map getResources() {
        return resources;
    }

    /**
     * Returns the given world resource.
     */
    public Resource getResource(String r) throws NoSuchResourceException {
        /*for(int i = 0; i < resources.length; i++)
            if(resources[i].getName().equals(r))
            	return resources[i];*/
        Resource res = ResourceKnowledgeCatalog.getInst().getResource(r);
        if(res == null)
            throw new NoSuchResourceException("World does not have a resource named '" + r + "'");
        return res;
    }

    /**
     * Return a list with the names of the resources which can be transformed into
     * a given resource and their value.
     */
    /*public List getProducers(String resource) {
         return ConstructionKnowledgeCatalog.getInst().areTransformedInto(resource);
    } */

    /**
     * Return a list with the names of the resources which can be transformed into
     * a given resource
     */
    /*public List getProducersNames(String resource) {
        List list = new ArrayList();
        Iterator it = getProducers(resource).iterator();
        while (it.hasNext()) {
            Object[] obj = (Object[]) it.next();
            list.add(obj[0]);
        }
        return list;
    } */

    /**
     * Set the worldcontroller.
     */
    protected void setWorldController(WorldController c) {
        worldController = c;
    }

    /**
     * Return the worldcontroller.
     */
    protected WorldController getWorldController() {
        return worldController;
    }

    /**
     * The GameBoard attached to this World.
     */
    private GameBoard gameBoard;

    /**
     * The world resources.
     */
    private Map resources;

    /**
     * The instance of this world.
     */
    private static World instance = null;

    /** 
     * The creation power of this world.
     */
    private CreationPower creationPower;

    /** 
     * The worldcontroller of this world.
     */
    private WorldController worldController;
}