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

import cytoscape.CyNode;
import cytoscape.Cytoscape;
import it.cnr.iasi.giant.thread.NetworkLoaderThread;
import java.util.ArrayList;
import java.util.HashSet;
import org.apache.commons.math3.stat.descriptive.moment.Mean;
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;

/**
 *
 * @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 ComputeZScore {
    
    public static HashSet<String> excluded = new HashSet<String>();
    private static double inClusterDegree = 0;
    
    public ComputeZScore() {}
    
    public static double compute(String node, ArrayList<String> cluster) {
        
        /*
         * 
         *  Zi = (Ki - K'si) / Oksi
         * 
         *  Ki: number of links of node i to other nodes in its module si
         *  K'si: average of K over all nodes in si
         *  Oksi: standard deviation of K in si
         * 
         */
        
        CyNode cyNode = Cytoscape.getCyNode(node);
        if (cyNode == null) 
            return Double.POSITIVE_INFINITY;
        
        double _Ki = 0.0;
        double[] arr = new double[cluster.size()];
        
        for (int i=0; i<cluster.size(); i++) {

            if (cluster.get(i).equals(node)) {
                ArrayList<String> degNode = NetworkLoaderThread.getDegreeMap().get(cluster.get(i));
                for (String n: degNode) {
                    if (cluster.contains(n))
                        _Ki++;
                }
            }
            
            try {
                arr[i] = ((double)NetworkLoaderThread.getDegreeMap().get(cluster.get(i)).size());
            } catch (NullPointerException e) {
                excluded.add(cluster.get(i));
                //System.err.println(cluster.get(i) + " - " + NetworkLoaderThread.getDegreeMap().containsKey(cluster.get(i)));
            }
        }
        
        Mean mean = new Mean();
        double _Ksi = mean.evaluate(arr);
        
        /*
        TEST-START
        */  
            /*
            System.out.println("-------------------------------------------");
            System.out.println();
            System.out.println("CLUSTER : " + cluster);
            System.out.println("CLUSTER SIZE : " + cluster.size());
            System.out.println("NODE : " + node);
            System.out.println("NODE DEGREE : " + NetworkLoaderThread.getDegreeMap().get(node));
            System.out.println();
            System.out.println("DATA_FOR_MEAN_&_DEV  --  length = " + arr.length);
            if (arr.length>0) {
                for (int i=0; i<arr.length; i++)
                    System.out.print((String.valueOf(arr[i])).replaceAll("\\.", ",") + ";");
                System.out.println();
            }
            System.out.println();
            System.out.println("Ki : " + (String.valueOf(_Ki)).replaceAll("\\.", ","));
            System.out.println("Ksi : " + (String.valueOf(_Ksi)).replaceAll("\\.", ","));
            */
        /*
        TEST-END 
        */
        
        StandardDeviation std = new StandardDeviation();
        double _DEV_Ksi = std.evaluate(arr);
        
        /*
        TEST-START
        */
            /*
            System.out.println("DEV : " + (String.valueOf(_DEV_Ksi)).replaceAll("\\.", ","));
            System.out.println();
            System.out.println("RESULT z : " + (String.valueOf(((_Ki - _Ksi) / _DEV_Ksi))).replaceAll("\\.", ","));
            System.out.println();
            System.out.println("-------------------------------------------");
            */
        /*
        TEST-END 
        */
        
        inClusterDegree = _Ki;
        
        try {
            return (double)((_Ki - _Ksi) / _DEV_Ksi);
        } catch(ArithmeticException e) {
            return Double.POSITIVE_INFINITY;
        }
    }
    
    public static HashSet getExcluded() {
        return excluded;
    }
    
    public static double getInClusterDegree() {
        return inClusterDegree;
    }
    
    public static void setInClusterDegree(double deg) {
        inClusterDegree = deg;
    }
    
}
