package dkohl.bayes.probability.distribution;

import java.util.HashMap;
import java.util.LinkedList;

import dkohl.bayes.probability.Assignment;
import dkohl.bayes.probability.Probability;

public class ContinousDistribution implements ProbabilityDistribution {

	/**
	 * The involved variables mapping to row
	 */
	private HashMap<String, Integer> variable2row;

	private HashMap<String, Gaussian> distribution;

	private String name;

	public ContinousDistribution(String names[], int self) {
		distribution = new HashMap<String, Gaussian>();
		this.variable2row = new HashMap<String, Integer>();
		int count = 0;
		for (int i = 0; i < names.length; i++) {
			if (i != self) {
				variable2row.put(names[i], count);
				count++;
			} else {
				name = names[i];
			}
		}
	}

	/**
	 * Generates a table entry key for an assignment
	 * 
	 * @param assignment
	 *            the assignment
	 * 
	 * @return the key
	 */
	public String generateKey(LinkedList<Assignment> assignment) {
		String[] values = new String[variable2row.size()];
		for (Assignment col : assignment) {
			if (variable2row.containsKey(col.getVariable().getName())) {
				int row = variable2row.get(col.getVariable().getName());
				values[row] = col.getValue();
			}
		}
		String key = "";
		for (String entry : values) {
			key += entry + ";";
		}
		return key;
	}

	public Assignment value(LinkedList<Assignment> assignment) {
		for (Assignment a : assignment) {
			if (a.getVariable().getName().equals(name)) {
				return a;
			}
		}
		return null;
	}

	@Override
	public Probability eval(LinkedList<Assignment> assignment) {
		String assignment_key = generateKey(assignment);
		if (distribution.get(assignment_key) == null) {
			return new Probability(0);
		}
		return new Probability(distribution.get(assignment_key).eval(
				value(assignment)));
	}

	public void pushAssignment(LinkedList<Assignment> assignment) {
		String key = generateKey(assignment);
		Gaussian gaussian = new Gaussian();
		if (distribution.containsKey(key)) {
			gaussian = distribution.get(key);
		}
		gaussian.push(value(assignment));
		distribution.put(key, gaussian);
	}

	public void estimate() {
		for (String key : distribution.keySet()) {
			distribution.get(key).estimate();
		}
	}

	public String[] getNames() {
		String[] names = new String[variable2row.size()];
		for (String name : variable2row.keySet()) {
			names[variable2row.get(name)] = name;
		}
		return names;
	}

	public HashMap<String, Gaussian> getAssignments() {
		return distribution;
	}

}
