package de.unikassel.cs.kde.kdd;

import java.util.List;
import java.util.Random;

import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.Tools;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.learner.clustering.ClusterModel;
import com.rapidminer.operator.learner.clustering.FlatCrispClusterModel;
import com.rapidminer.operator.learner.clustering.clusterer.AbstractFlatClusterer;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeDouble;
import com.rapidminer.parameter.ParameterTypeInt;

/**
 * 
 * @author:  rja
 * @version: $Id: KDDKMeans.java,v 1.7 2008-11-03 12:21:34 rja Exp $
 * $Author: rja $
 * 
 */
public class KDDKMeans extends AbstractFlatClusterer {

	public static final String PARAMETER_K = "k";
	public static final String PARAMETER_MAX_RUNS = "max_runs";
	public static final String PARAMETER_MAX_ERROR_CHANGE = "max_error_change";
	public static final String PARAMETER_LOCAL_RANDOM_SEED = "local_random_seed";

	/*
	 * number of clusters
	 */
	private int k;
	/*
	 * maximal number of iterations
	 */
	private int maxIter;
	/*
	 * maximal change in error
	 */
	private double maxErrorChange;

	private Random rand;


	public KDDKMeans(OperatorDescription description) {
		super(description);
	} 

	@Override
	public ClusterModel createClusterModel(final ExampleSet exampleSet) throws OperatorException {
		/*
		 * should be called, don't ask why. :-(
		 */
		exampleSet.remapIds();
		/*
		 * get the parameters (the number of clusters, max iteration, max error change)
		 */
		k = getParameterAsInt(PARAMETER_K);
		maxIter = getParameterAsInt(PARAMETER_MAX_RUNS);
		maxErrorChange = getParameterAsDouble(PARAMETER_MAX_ERROR_CHANGE);
		rand = new Random(getParameterAsInt(PARAMETER_LOCAL_RANDOM_SEED));
		/* 
		 * additional checks
		 */
		Tools.onlyNumericalAttributes(exampleSet, "KDDKMeans");
		Tools.onlyNonMissingValues(exampleSet, "KDDKMeans");
		if (exampleSet.size() < k) {
			logWarning("number of clusters (k) = " + k + " > number of objects =" + exampleSet.size());
			k = exampleSet.size();
		}

		FlatCrispClusterModel clustering = null;
		/* ***********************************************************
		 * TODO: insert your code here
		 * ***********************************************************/
		
		

		return clustering;
	}


	/** Manhattan distance
	 * 
	 * @param example
	 * @param centroid
	 * @return
	 */
	private double getDistance (Example example, double[] centroid) {
		/* ***********************************************************
		 * TODO: insert your code here
		 * ***********************************************************/
		return Double.MAX_VALUE;
	}



	/** Method to get parameters from RapidMiner.
	 * If you need more parameters, change this method.
	 * 
	 * @see com.rapidminer.operator.learner.clustering.clusterer.AbstractClustering#getParameterTypes()
	 */
	public List<ParameterType> getParameterTypes() {

		final List<ParameterType> types = super.getParameterTypes();
		final ParameterType type = new ParameterTypeInt(PARAMETER_K, "The number of clusters which should be detected.", 2, Integer.MAX_VALUE, 2);
		type.setExpert(false);
		types.add(type);
		types.add(new ParameterTypeInt(PARAMETER_MAX_RUNS, "The maximal number of runs of k-Means with random initialization that are performed.", 1, Integer.MAX_VALUE, 10));
		types.add(new ParameterTypeDouble(PARAMETER_MAX_ERROR_CHANGE, "The maximal error change that is allowed before stopping k-Means.", 0, Double.MAX_VALUE, 10e-6));
		types.add(new ParameterTypeInt(PARAMETER_LOCAL_RANDOM_SEED, "Use the given random seed instead of global random numbers (-1: use global)", -1, Integer.MAX_VALUE, -1));

		return types;
	}

}

