package antipatternsrecovery.metrics;

import java.util.Vector;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;

public class LevenshteinDistance {
	private NOC noc;
	private int maxValue=50;
	private ICompilationUnit clazz;

	public int computeDistance(ICompilationUnit pClass) {
		if(pClass.exists()) {
			IType type = pClass.getType(pClass.getElementName().substring(0, pClass.getElementName().length()-5));
			this.noc = new NOC();
			this.clazz=pClass;
			int numberOfChild = this.noc.computeNOC(pClass);

			try {
				if(type.getSuperclassName() == null) { // Class don't have a superclass
					if(numberOfChild == 0) { // Class don't have a subclass
						return this.maxValue;
					} else if (numberOfChild > 0) {
						int min = 10000;

						for(String classInHierarchy: this.getAllSuperclasses()) {
							if(! classInHierarchy.equals(type.getElementName())) {
								int value = this.computeDistance(type.getElementName(), classInHierarchy);

								if(value < min) {
									min = value;
								}
							}
						}
						return min;
					}
				} else { // Class has a superclass
					int min = 10000;

					for(String classInHierarchy: this.getAllSuperclasses()) {
						if(! classInHierarchy.equals(type.getElementName())) {
							int value = this.computeDistance(type.getElementName(), classInHierarchy);

							if(value < min) {
								min = value;
							}
						}
					}
					return min;
				}

			} catch (JavaModelException e) {
				e.printStackTrace();
			}
		}
		return 50;

	}

	/**
	 * data una classe, controlla che appartenga ad una gerarchia:
	 * 		se non appartiene ad una gerarchia, levDist = max
	 *		else calcola la somiglianza con tutte le classi della gerarchia e prendi il valore minimo
	 * @param s1
	 * @param s2
	 * @return
	 */
	public int computeDistance(String s1, String s2) {
		s1 = s1.toLowerCase();
		s2 = s2.toLowerCase();

		int[] costs = new int[s2.length() + 1];
		for (int i = 0; i <= s1.length(); i++) {
			int lastValue = i;
			for (int j = 0; j <= s2.length(); j++) {
				if (i == 0)
					costs[j] = j;
				else {
					if (j > 0) {
						int newValue = costs[j - 1];
						if (s1.charAt(i - 1) != s2.charAt(j - 1))
							newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
						costs[j - 1] = lastValue;
						lastValue = newValue;
					}
				}
			}
			if (i > 0)
				costs[s2.length()] = lastValue;
		}
		return costs[s2.length()];
	}

	private Vector<String> getAllSuperclasses() {
		Vector<String> superclasses=new Vector<String>();

		try {
			for(IPackageFragment pack: this.clazz.getJavaProject().getPackageFragments()){
				for(ICompilationUnit cu: pack.getCompilationUnits()) {
					for(IType type: cu.getTypes()) {
						if(type.getSuperclassName()!=null)
							superclasses.add(type.getSuperclassName());
					}
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}

		return superclasses;
	}

}