/* CVS: $Id: EvolutionKnowledgeCatalog.java,v 1.15 2001/03/18 19:16:33 gvijf Exp $ */

package evolution;

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

import evolution.lands.LandKnowledgeCatalog;
import evolution.actions.ActionKnowledgeCatalog;
import evolution.resources.Resource;
import evolution.resources.ResourceKnowledgeCatalog;
import evolution.resources.NoSuchResourceException;
import evolution.constructions.ConstructionKnowledgeCatalog;

/**
 * The general Evolution KnowledgeCatalog.
 * @stereotype singleton */
public class EvolutionKnowledgeCatalog extends KnowledgeCatalog {

    /**
     * Create a new KnowledgeCatalog from the given file.
     */
    protected EvolutionKnowledgeCatalog(String fileName) throws IOException, FileNotFoundException {
        super(fileName);
        try {
        	ResourceKnowledgeCatalog.initialize(getProperty("ResourcesFile", "resources.prop"));
        	LandKnowledgeCatalog.initialize(getProperty("LandsFile", "lands.prop"));
        	ActionKnowledgeCatalog.initialize(getProperty("ActionsFile", "actions.prop"));
        	ConstructionKnowledgeCatalog.initialize(getProperty("ConstructionsFile", "constructions.prop"));
        } catch(FileNotFoundException e) {
            throw e;
        } catch(IOException e) {
            throw e;
        }
    }

    /**
     * Return the instance of this singleton.
     */
    public static EvolutionKnowledgeCatalog getInst() {
        if(instance == null)
            throw new RuntimeException("EvolutionKnowledgeCatalog was not initialized");
        return instance;
    }

    /**
     * Initialize this singleton from the given file.
     */
    public static void initialize(String fileName) throws FileNotFoundException, IOException {
        instance = new EvolutionKnowledgeCatalog(fileName);
    }

    /**
     * Return the default vision range.
     */     
    public int getDefaultVisionRange() {
         return Integer.parseInt(getProperty("Human.visionRange", "2"));
    }

    /**
     * Return the amount by which the player's creationpower decreases whenever he 
     * creates a human.
     */
    public double getHumanCreationDecrease() {
        return Double.parseDouble(getProperty("CreationPower.human", "20"));
    }

    /**
     * Return the amount by which the player's creationpower increases 
     * on every clocktick.
     */
    public double getCreationIncrease() {
        return Double.parseDouble(getProperty("CreationPower.inc", "1"));
    }
    
    /**
     * Return the initial creationpower of a player.
     */
    public double getInitCreationPower() {
        return Double.parseDouble(getProperty("CreationPower.init", "100"));
    }

    /**
     * Return the maximum amount of creationpower.
     */
    public double getMaxCreationPower() {
        return Double.parseDouble(getProperty("CreationPower.max", "500"));
    }

    /**
     * Calculate the current goal from a list of given resources.
     * @precondition The list must contain all resources for which weight
     * values are read from the config file.
     */
    public double calcGoal(Map resources) {
		if(weights == null) {
		    parseWeights(getProperty("Goal"));
        }
        double goal = 0;
		Set keys = weights.keySet();
		Iterator it = keys.iterator();
		while (it.hasNext()) {
			String resName = (String) it.next();
            Resource r = (Resource) resources.get(resName);
            if(r == null)
                throw new RuntimeException("No value specified for resource" + resName + "to calculate level of the goal");
            double w = ((Double) weights.get(resName)).doubleValue();
            goal += w * r.getValue();
	    }
		return goal;
    }

    /**
     * Parse the weightsline for the goal from the config file.
     * This line looks like this:
     *	Goal = Happiness(5) Energy(4) Coals(6.5)
     * The weights will be normalized so they sum to 1.
     */
    protected void parseWeights(String weightsString) {
        weights = new HashMap();
        List parts = split(" ", weightsString);
        double sum = 0;
        for(int i = 0; i < parts.size(); i++) {
            Double w = extractValue((String) parts.get(i));
            String resource = extractName((String) parts.get(i));
            weights.put(resource, w);
            sum += w.doubleValue();
        }
        Set keys = weights.keySet();
        Iterator it = keys.iterator();
        while(it.hasNext()) {
            Object key = it.next();
            weights.put(key,
                new Double(((Double) weights.get(key)).doubleValue() / sum));
        }
    }

    /**
     * Hash of Class objects for resources and their normalized weight.
     */
    private Map weights;

    /**
     * Instance of the singleton.
     */
    protected static EvolutionKnowledgeCatalog instance = null;
}