package de.visone.nlpext.util;

import static java.lang.Math.sqrt;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;

/**
 * Calculates the correlation of two series of measurement.
 * @author <a href="mailto:endele@inf.uni-konstanz.de">Simon Endele</a>
 */
public class CorrelationComputer {
	
	
	public CorrelationComputer() { }
	
	
	
	public static double getCorrelation(Map<String,Double>[] hashMaps, String key1, String key2) {
		return getCorrelation(Arrays.asList(hashMaps), key1, key2);
	}
	public static double getCorrelation(List<? extends Map<String,Double>> hashMaps, String key1, String key2) {
		List<Double> list1 = new LinkedList<Double>();
		List<Double> list2 = new LinkedList<Double>();
		for (Map<String,Double> hashMap : hashMaps) {
			Double value1 = hashMap.get(key1);
			Double value2 = hashMap.get(key2);
			//list1.add( (value1!=null) ? value1 : new Double(0.0) );
			//list2.add( (value2!=null) ? value2 : new Double(0.0) );
			list1.add(value1);
			list2.add(value2);
		}
		return getCorrelation(list1, list2);
	}
	
	
	
	public static double getCorrelation(Double[] values1, Double[] values2) {
		return getCorrelation(Arrays.asList(values1), Arrays.asList(values2));
	}
	public static double getCorrelation(List<Double> values1, List<Double> values2) {
		//System.out.println(values1);
		//System.out.println(values2);
		if (values1.size()!=values2.size()) {
			throw new IllegalArgumentException("Passed lists do not have the same size!"); ///////////////////////
		}
		int size = values1.size(); // = values2.size()
		double sum1 = sum(values1);
		double sum2 = sum(values2);
		double sum1x2 = 0.0;
		double sum1x1 = 0.0;
		double sum2x2 = 0.0;
		Iterator<Double> it1 = values1.iterator();
		Iterator<Double> it2 = values2.iterator();
		while (it1.hasNext() && it2.hasNext()) {
			Double value1 = it1.next();
			Double value2 = it2.next();
			double val1 = (value1!=null) ? value1.doubleValue()-sum1/size : 0.0; //normalization(?)
			double val2 = (value2!=null) ? value2.doubleValue()-sum2/size : 0.0; //normalization(?)
			sum1x2 += val1*val2;
			sum1x1 += val1*val1;
			sum2x2 += val2*val2;
		}
		double correlation = sum1x2/sqrt(sum1x1*sum2x2);
		/*System.out.println("sum1x2: "+sum1x2);
		System.out.println("sum1x1: "+sum1x1);
		System.out.println("sum2x2: "+sum2x2);
		System.out.println("correlation: "+correlation);*/
		return correlation;
	}
	
	
	public static double sum(List<Double> values) {
		double sum = 0.0;
		for (Double val : values) {
			sum += (val!=null) ? val.doubleValue() : 0.0;
		}
		return sum;
	}
	
	public static void main(String[] args) throws IOException {
		if (args==null || args.length!=5) {
			System.out.println("Usage is:: EntropyComputer <cvsFilesDirectory> <centralityName> <output> <csvRankFile> <n>");
			return;
		}
		File cvsDirectory = new File(args[0]);
		String centralityName = args[1];
		File output = new File(args[2]);
		File csvRankFile = new File(args[3]);
		int n = Integer.parseInt(args[4]);
		
		File[] files = cvsDirectory.listFiles(new GraphMLFileFilter());
		Arrays.sort(files);
		System.out.println("Found "+files.length+" files.");
		
		FileWriter fileWriter = new FileWriter(output);
		CSVWriter writer = new CSVWriter(fileWriter, ',', '"');
		String[] header = {"Words","Correlation of "+centralityName};
		writer.writeNext(header);
		
		CSVReader reader = new CSVReader(new FileReader(csvRankFile));
		reader.readNext(); //read header
		List<String> words = new Vector<String>();
		for (int i=0; i<n; i++) {
			String[] line = reader.readNext();
			words.add(line[0]);
		}
		reader.close();
		
		//read in all centrality-lists
		List<LinkedHashMap<String, Double>> centralitiesList = HashMapReader.readFiles(files, centralityName);
		
		HashMap<String, Double> correlations = new HashMap<String, Double>();
		for (int i=0; i<words.size(); i++) {
			for (int j=i+1; j<words.size(); j++) {
				String word1 = words.get(i);
				String word2 = words.get(j);
				if (word1==word2) continue;
				double correlation = getCorrelation(centralitiesList, word1, word2);
				if (correlation!=0.0) {
					correlations.put(word1+" : "+word2, correlation);
				}
			}
		}
		List<String> list = new LinkedList<String>();
		list.addAll(correlations.keySet());
		Collections.sort(list, new EntropyComputer.ValueComparator<String,Double>(correlations));
		for (String word : list) {
			String[] line = {word, ""+correlations.get(word)};
			writer.writeNext(line);
		}
		writer.close();
		System.out.println("Data successfully written to "+output.getAbsolutePath());
	}
}