/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.cnr.iasi.giant.thread;

import cytoscape.Cytoscape;
import it.cnr.iasi.giant.action.RunClusteringAction;
import it.cnr.iasi.giant.algorithm.clustering.KMeansOriginal;
import it.cnr.iasi.giant.algorithm.distance.GraphUtil;
import it.cnr.iasi.giant.frame.KMeansInitFrame;
import it.cnr.iasi.giant.io.IOWriter;
import it.cnr.iasi.giant.util.ClusteringUtil;
import it.cnr.iasi.giant.util.Helper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.javaml.clustering.Clusterer;
import net.sf.javaml.core.Dataset;
import net.sf.javaml.core.Instance;
import net.sf.javaml.tools.data.FileHandler;

/**
 *
 * @author Fabio Cumbo
 * @info GIANT
 * @version v1.0
 * @organization IASI-CNR : Istituto di Analisi dei Sistemi ed Informatica 
 *                  "Antonio Ruberti" - Consiglio Nazionale delle Ricerche
 * 
 */
public class KMeansKThread extends Thread {
    
    @Override
    public void run() {
        int k = (Integer)KMeansInitFrame.getK_snipper().getValue();
        int iter = (Integer)KMeansInitFrame.getIterK_snipper().getValue();
        IOWriter writer = new IOWriter();
        
        if (k>0 && iter>0) {
                        
            if (!ClusterLoaderThread.getClustersKRange().isEmpty() && ClusterLoaderThread.getClustersKRange().containsKey(k)) {
                HashMap<Integer, ArrayList<String>> clusters = ClusterLoaderThread.getClustersKRange().get(k);
                String filePath = writer.writeTmpClusterFile(clusters);

                if (!clusters.isEmpty() && !filePath.equals("NULL")) {
                    ClusterLoaderThread.setClusterFileName("KMEANS-POWERED");
                    ClusterLoaderThread.setClusterFilePath(filePath);
                    ClusterLoaderThread.setClusters(clusters);

                    KMeansInitFrame.appendInConsole("KMEANS: starting KMeans algorithm at " + Helper.getCurrentTime());
                    KMeansInitFrame.appendInConsole("KMEANS: k = " + k + " - iterations = " + iter);
                    KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                    KMeansInitFrame.appendInConsole("KMEANS: computing...");
                    KMeansInitFrame.appendInConsole("KMEANS: completed at " + Helper.getCurrentTime());
                    KMeansInitFrame.appendInConsole("CLUSTERS: " + clusters.size());
                    for (int t=0; t<clusters.size(); t++)
                        KMeansInitFrame.appendInConsole("cluster " + (t+1) + "  -  size: " + clusters.get(t).size());
                    KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                
                }
                else {
                    KMeansInitFrame.appendInConsole("INTERNAL ERROR: please retry...");
                    KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                }
                                
            }
            else {
                
                KMeansInitFrame.appendInConsole("COMPUTING DISTANCE MATRIX: please wait....");
                
                if (ClusteringUtil.getLastMetric().equals("NULL")) {
                    if (KMeansInitFrame.getSp_matrix_radio().isSelected()) {
                            try {
                                GraphUtil graph = new GraphUtil(NetworkLoaderThread.getDegreeMap().keySet().size(), NetworkLoaderThread.getAdjMatrix());
                                ClusteringUtil.setTmpDistanceFile(writer.writeTmpDistanceMatrixFile(ClusteringUtil.getDistanceMatrix("SP", graph, null)));
                                ClusteringUtil.setMatrix(true);
                                ClusteringUtil.setLastMetric("SP");
                            } catch (IOException ex) {
                                Logger.getLogger(KMeansKThread.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                        else if (KMeansInitFrame.getHamming_matrix_radio().isSelected()) {
                            try {
                                ClusteringUtil.setTmpDistanceFile(writer.writeTmpDistanceMatrixFile(ClusteringUtil.getDistanceMatrix("HAMMING", null, NetworkLoaderThread.getAdjMatrix())));
                                ClusteringUtil.setMatrix(true);
                                ClusteringUtil.setLastMetric("HAMMING");
                            } catch (IOException ex) {
                                Logger.getLogger(KMeansKThread.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                }
                else if (ClusteringUtil.getLastMetric().equals("SP")) {
                    if (KMeansInitFrame.getHamming_matrix_radio().isSelected()) {
                            try {
                                ClusteringUtil.setTmpDistanceFile(writer.writeTmpDistanceMatrixFile(ClusteringUtil.getDistanceMatrix("HAMMING", null, NetworkLoaderThread.getAdjMatrix())));
                                ClusteringUtil.setMatrix(true);
                                ClusteringUtil.setLastMetric("HAMMING");
                            } catch (IOException ex) {
                                Logger.getLogger(KMeansKThread.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                }
                else if (ClusteringUtil.getLastMetric().equals("HAMMING")) {
                    if (KMeansInitFrame.getSp_matrix_radio().isSelected()) {
                            try {
                                GraphUtil graph = new GraphUtil(NetworkLoaderThread.getDegreeMap().keySet().size(), NetworkLoaderThread.getAdjMatrix());
                                ClusteringUtil.setTmpDistanceFile(writer.writeTmpDistanceMatrixFile(ClusteringUtil.getDistanceMatrix("SP", graph, null)));
                                ClusteringUtil.setMatrix(true);
                                ClusteringUtil.setLastMetric("SP");
                            } catch (IOException ex) {
                                Logger.getLogger(KMeansKThread.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                }
                
                if (!ClusteringUtil.getTmpDistanceFile().equals("NULL")) {
                    
                    KMeansInitFrame.appendInConsole("COMPUTING DISTANCE MATRIX: completed!");
                    KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                    
                    try {
                        Dataset data = FileHandler.loadDataset(new File(ClusteringUtil.getTmpDistanceFile()), Cytoscape.getCurrentNetwork().nodesList().size()-1, " ");
                        Clusterer km = new KMeansOriginal(k, iter);
                        
                        KMeansInitFrame.appendInConsole("KMEANS: starting KMeans algorithm at " + Helper.getCurrentTime());
                        KMeansInitFrame.appendInConsole("KMEANS: k = " + k + " - iterations = " + iter);
                        KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                        KMeansInitFrame.appendInConsole("KMEANS: computing...");
                        
                        /*
                        * Cluster the data, it will be returned as an array of data sets, with
                        * each dataset representing a cluster
                        */

                        Dataset[] result = km.cluster(data);
                        System.out.println("Cluster count: " + result.length);

                        //EXTRACT CLUSTERS FROM DATASET[]
                        //SET CLUSTERS

                        HashMap<Integer, ArrayList<String>> clusters = new HashMap<Integer, ArrayList<String>>();
                        ArrayList<String> list = new ArrayList<String>(NetworkLoaderThread.getDegreeMap().keySet());
                        
                        int lb = Integer.MAX_VALUE;
                        for (int i=0; i<result.length; i++) {
                            Dataset ds = result[i];
                            Instance inst = ds.get(0);
                            if (lb > inst.getID())
                                lb = inst.getID();
                        }
                        int ub = lb + NetworkLoaderThread.getDegreeMap().keySet().size() -1;
                        
                        HashMap<Integer, Integer> newMap = RunClusteringAction.getNewMap(ub, lb);

                        for (int i=0; i<result.length; i++) {
                            Dataset ds = result[i];
                            ArrayList<String> tmp = new ArrayList<String>();
                            for (int j=0; j<ds.size(); j++) {
                                Instance inst = ds.get(j);
                                System.err.print(inst.getID() + " ");          
                                tmp.add(list.get(newMap.get(inst.getID())));
                            }
                            clusters.put(i, tmp);
                            System.err.println();
                        }
                        
                        String filePath = writer.writeTmpClusterFile(clusters);

                        if (!clusters.isEmpty() && !filePath.equals("NULL")) {
                            ClusterLoaderThread.setClusterFileName("KMEANS-POWERED");
                            ClusterLoaderThread.setClusterFilePath(filePath);
                            ClusterLoaderThread.setClusters(clusters);
                            
                            KMeansInitFrame.appendInConsole("KMEANS: completed at " + Helper.getCurrentTime());
                            KMeansInitFrame.appendInConsole("CLUSTERS: " + clusters.size());
                            for (int t=0; t<clusters.size(); t++)
                                KMeansInitFrame.appendInConsole("cluster " + (t+1) + "  -  size: " + clusters.get(t).size());
                            KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                            
                        }
                        else {
                            KMeansInitFrame.appendInConsole("INTERNAL ERROR: please retry...");
                            KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                        }
                        
                        
                    } catch (IOException ex) {
                        KMeansInitFrame.appendInConsole("INTERNAL ERROR: please retry...");
                        KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                    }

                }
                else {
                    KMeansInitFrame.appendInConsole("COMPUTING DISTANCE MATRIX: error!");
                    KMeansInitFrame.appendInConsole("---------------------------------------------------------");
                }
            }
        }
        
        else {
            KMeansInitFrame.appendInConsole("INTERNAL ERROR: invalid k or iterations");
            KMeansInitFrame.appendInConsole("---------------------------------------------------------");
        }
                
    }
    
}
