package de.visone.nlpext.util;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;

/**
 * Compares two text by calculating their Word Resonance from a centrality.
 * A functionality for comparing a set of texts pairwisely and printing a
 * color-coded matrix is included.
 * @author <a href="mailto:endele@inf.uni-konstanz.de">Simon Endele</a>
 */
public class TextComparator {
	
    private static Logger logger = Logger.getLogger(TextComparator.class);
	
	public static enum NormType {SQUARE, LINEAR, SQRT, CBRT, LOG2}
	
	public static final int blockSize = 10; //width and height of a block in pixels
	public static final String formatName = "png";
	
	
	private TextComparator() { }
	
	public static double calcCoherence(Map<String, Double> map1, Map<String, Double> map2) {
		double sum = 0.0;
		Map<String, Double> smallerMap = (map1.size()<map2.size()) ? map1 : map2;
		for (String s : smallerMap.keySet()) {
			Double d1 = map1.get(s);
			Double d2 = map2.get(s);
			if (d1!=null && d2!=null)  sum += d1.doubleValue()*d2.doubleValue();
		}
		return sum;
	}
	
	public static double[][] calcCoherenceMatrix(List<LinkedHashMap<String, Double>> centralitiesList) {
		int num = centralitiesList.size();
		double[][] matrix = new double[num][num];
		//calculate values
		for (int i=0; i<num; i++) {
			for (int j=i; j<num; j++) {
				double coherence = calcCoherence(centralitiesList.get(i), centralitiesList.get(j));
				matrix[i][j] = coherence;
				matrix[j][i] = coherence;
			}
		}
		return matrix;
	}
	
	public static void normalize(double[][] matrix, NormType normType) {
		int num = matrix.length;
		double max = -Double.MAX_VALUE;
		//calculate max value
		for (int i=0; i<num; i++) {
			for (int j=i; j<num; j++) {
				if (matrix[i][j]>max) max = matrix[i][j];
			}
		}
		//normalize
		for (int i=0; i<num; i++) {
			for (int j=0; j<num; j++) {
				matrix[i][j] /= max;
				switch (normType) {
					case SQUARE: matrix[i][j] = matrix[i][j]*matrix[i][j]; break;
					case SQRT: matrix[i][j] = Math.sqrt(matrix[i][j]); break;
					case CBRT: matrix[i][j] = Math.cbrt(matrix[i][j]); break;
					case LOG2: //matrix[i][j] = Math.log(matrix[i][j]+1.0)/Math.log(2.0); break; //calc base 2 log of (value+1)
						//matrix[i][j] = (matrix[i][j]==0.0) ? Double.MAX_VALUE : -1.0/Math.log(matrix[i][j]);
				}
			}
		}
		if (normType==NormType.LOG2) normalize(matrix, NormType.LINEAR);
	}
	
	public static void standardize(double[][] matrix) {
		int num = matrix.length;
		for (int i=0; i<num; i++) {
			for (int j=0; j<num; j++) {
				if (i!=j) {
					matrix[i][j] /= Math.sqrt(matrix[i][i] * matrix[j][j]);
				}
			}
		}
		for (int i=0; i<num; i++) {
			matrix[i][i] = 1.0;
		}
	}
	
	public static void paintCoherenceMatrix(double[][] matrix, File output) throws IOException {
		int num = matrix.length;
		BufferedImage image = new BufferedImage(num*blockSize, num*blockSize, BufferedImage.TYPE_INT_RGB);
		Graphics g = image.getGraphics();
		for (int i=0; i<num; i++) {
			for (int j=0; j<num; j++) {
				double value = matrix[i][j];
				Color col = new Color((float) value, 0.0f, (float)(1.0-value));
				g.setColor(col);
				g.fillRect(i*blockSize, j*blockSize, blockSize, blockSize);
			}
		}
		
		int offset = 15;
		BufferedImage image2 = new BufferedImage(num*blockSize+offset, num*blockSize, BufferedImage.TYPE_INT_RGB);
		Graphics g2 = image2.getGraphics();
		g2.setColor(Color.WHITE); g2.fillRect(0,0,image2.getWidth(),image2.getHeight());
		g2.setColor(Color.BLACK);
		g2.drawImage(image, offset, 0, null);
		for (int i=0; i<num; i++) {
			String number = (i+1)+"";
			if (number.length()==1) number = "0"+number;
			g2.drawString(number, 0, (i+1)*blockSize);
		}
		
		ImageIO.write(image2, formatName, output);
	}
	
	public static void main(String[] args) throws IOException {
		if (args==null || args.length!=2) {
			System.out.println("Usage is:: TextComparator <cvsFilesDirectory> <centralityName>");
			return;
		}
		String cvsDirectory = args[0];
		String centralityName = args[1];
		
		File[] files = new File(cvsDirectory).listFiles();
		Arrays.sort(files);
		System.out.println("Found "+files.length+" files.");
		
		File output = new File("CoherenceMatrix."+formatName);
		System.out.println("output: "+output.getAbsolutePath());
		
		//read in all centrality-lists
		List<LinkedHashMap<String, Double>> centralitiesList = HashMapReader.readFiles(files, centralityName);
		int numMeasures = centralitiesList.size();
		
		double[][] matrix = calcCoherenceMatrix(centralitiesList);
		standardize(matrix);
		//normalize(matrix, NormType.LINEAR); //{SQUARE, LINEAR, SQRT, CBRT, LOG2}
		paintCoherenceMatrix(matrix, output);
	}
}