package multinomad.tools.kmeans;

import java.util.Iterator;

import multinomad.config.Configuration;
import multinomad.individuals.DoubleIndividual;
import multinomad.individuals.Population;
import multinomad.tools.CommonState;
import multinomad.tools.kmeansML.Centroids;

public class Kmeans implements Iterable<DoubleIndividual>{
	
	private Population centroids;
	private Population rawdata;
	private int k;
	
	public Kmeans(Population poprawdata, int numClusters) {
		centroids = new Population(false);
		k = numClusters;
		rawdata = poprawdata;
		initialize();
	}
	
	private void initialize() {
		if(Configuration.kmeansinit.equals(Configuration.KMEANSRANDOM)) {
			randomInit();
		}else if (Configuration.kmeansinit.equals(Configuration.KMEANSPLUS)) {
			kmeansPlusInit();
		}
	}
	
	private void randomInit() {
		for (int i=0;i<k;i++) {
			
			boolean inserted = false;
			while(!inserted) {
				DoubleIndividual ind = rawdata.getP().get(CommonState.r.nextInt(rawdata.size()));
				if(!centroids.contains(ind)) {
					inserted = true;
					Centroid centroid = new Centroid(ind);
					centroids.add(centroid);
				}
			}
		}
	}
	
	//TODO
	private void kmeansPlusInit() {
		
	}
	
	/**
	 * 
	 * @return A populatin of centroids after convergence of kmeans
	 */
	public Population cluster() {
		
		boolean changed = true; // change in at least one cluster assignement
		boolean success = true; // all means computed? (no zero-count cluster)
		int maxCount = rawdata.size()*10; // sanity check
		int ct = 0;
		
		while(changed == true && success == true && ct < maxCount) { // tecnically this is Lloyd's algorithm
			changed = updateClustering(); // (re)assign tuples to clusters
			success = updateMeans(); // Compute new cluster means if possible
			ct++; // k-means typically converges very quickly
		}
		
		return centroids;
	}
	
	// TODO
	private boolean updateClustering() {
		
		return false;
	}
	
	private boolean updateMeans() {
		if(Configuration.kmeansconvergence.equals(Configuration.KMEANSLLOYD)) {
			return updateMeansLloyd();
		}else if (Configuration.kmeansinit.equals(Configuration.KMEANSBIASED)) {
			return updateMeansBiased();
		}else
			return false;
	}
	
	//TODO
	private boolean updateMeansLloyd() {
		
		return false;
	}
	
	//TODO
	private boolean updateMeansBiased() {
			
		return false;
	}
	
	public Iterator<DoubleIndividual> iterator() {
		return centroids.iterator();
	}

}
