package Model;

import java.util.List;

public class Comparaison {

	static Parameters parameters = new Parameters();
	// Taille des images PNG
	static int size = 1300;
	// Nombre de points souhaités en fin de traitement
	static int nbPoints = 1000;

	public double compareXSumMoves (List<Point> pointList1, List<Point> pointList2) {
		double xSumMoves1 = parameters.extractXSumMoves(pointList1);
		double xSumMoves2 = parameters.extractXSumMoves(pointList2);
		return Math.abs(xSumMoves1 - xSumMoves2);
	}

	public double compareYSumMoves (List<Point> pointList1, List<Point> pointList2) {
		double ySumMoves1 = parameters.extractYSumMoves(pointList1);
		double ySumMoves2 = parameters.extractYSumMoves(pointList2);
		return Math.abs(ySumMoves1 - ySumMoves2);
	}

	public double compareSumMoves (List<Point> pointList1, List<Point> pointList2) {
		double sumMoves1 = parameters.extractSumMoves(pointList1);
		double sumMoves2 = parameters.extractSumMoves(pointList2);
		return Math.abs(sumMoves1 - sumMoves2);
	}

	public static float compareAveragedSpeedX (List<Point> pointList1, List<Point> pointList2) {
		float averagedSpeedX1 = parameters.extractAveragedSpeedX(pointList1);
		float averagedSpeedX2 = parameters.extractAveragedSpeedX(pointList2);
		return Math.abs(averagedSpeedX1 - averagedSpeedX2);
	}	

	public static float compareAveragedSpeedY (List<Point> pointList1, List<Point> pointList2) {
		float averagedSpeedY1 = parameters.extractAveragedSpeedY(pointList1);
		float averagedSpeedY2 = parameters.extractAveragedSpeedY(pointList2);
		return Math.abs(averagedSpeedY1 - averagedSpeedY2);
	}	

	public static float compareAveragedSpeed (List<Point> pointList1, List<Point> pointList2) {
		float averagedSpeed1 = parameters.extractAveragedSpeed(pointList1);
		float averagedSpeed2 = parameters.extractAveragedSpeed(pointList2);
		return Math.abs(averagedSpeed1 - averagedSpeed2);
	}	

	public static int compareNumberOfPenUp (List<Point> pointList1, List<Point> pointList2) {
		int numberOfPenUp1 = parameters.extractNumberOfPenUp(pointList1);
		int numberOfPenUp2 = parameters.extractNumberOfPenUp(pointList2);
		return Math.abs(numberOfPenUp1 - numberOfPenUp2);
	}

	public static float compareAveragedPressure (List<Point> pointList1, List<Point> pointList2) {
		float averagedPressure1 = parameters.extractAveragedPressure(pointList1);
		float averagedPressure2 = parameters.extractAveragedPressure(pointList2);
		return Math.abs(averagedPressure1 - averagedPressure2);
	}	

	public static float compareTotalTime (List<Point> pointList1, List<Point> pointList2) {
		float totalTime1 = parameters.extractTotalTime(pointList1);
		float totalTime2 = parameters.extractTotalTime(pointList2);
		return Math.abs(totalTime1 - totalTime2);
	}	

	public static double meanCurveOverWindow (double[] curve, int i, int K) {
		double mean = 0;
		for (int j=i-K; j<i+K; j++) {
			mean += curve[j];
		}
		mean *= 1/(2*K + 1);
		return mean;
	}

	public static double meanCurveOverWindow (int[] curve, int i, int K) {
		double mean = 0;
		for (int j=i-K; j<i+K; j++) {
			mean += curve[j];
		}
		mean *= 1/(2*K + 1);
		return mean;
	}

	public static double meanCurveOverWindow (float[] curve, int i, int K) {
		double mean = 0;
		for (int j=i-K; j<i+K; j++) {
			mean += curve[j];
		}
		mean *= 1/(2*K + 1);
		return mean;
	}

	public static double CORTX (List<Point> pointList1, List<Point> pointList2, int K) {
		double[] curve1 = parameters.extractXCurve(pointList1);
		double[] curve2 = parameters.extractXCurve(pointList2);
		double numerator = 0;
		double carre1 = 0;
		double carre2 = 0;
		for (int i=K; i<curve1.length-K; i++) {
			numerator += (curve1[i] - meanCurveOverWindow(curve1, i, K)) * (curve2[i] - meanCurveOverWindow(curve2, i, K));
			carre1 += (curve1[i] - meanCurveOverWindow(curve1, i, K)) * (curve1[i] - meanCurveOverWindow(curve1, i, K));
			carre2 += (curve2[i] - meanCurveOverWindow(curve2, i, K)) * (curve2[i] - meanCurveOverWindow(curve2, i, K));
		}
		double denominator = Math.sqrt(carre1*carre2);
		return numerator/denominator;
	}

	public static double CORTY  (List<Point> pointList1, List<Point> pointList2, int K) {
		double[] curve1 = parameters.extractYCurve(pointList1);
		double[] curve2 = parameters.extractYCurve(pointList2);
		double numerator = 0;
		double carre1 = 0;
		double carre2 = 0;
		for (int i=K; i<curve1.length-K; i++) {
			numerator += (curve1[i] - meanCurveOverWindow(curve1, i, K)) * (curve2[i] - meanCurveOverWindow(curve2, i, K));
			carre1 += (curve1[i] - meanCurveOverWindow(curve1, i, K)) * (curve1[i] - meanCurveOverWindow(curve1, i, K));
			carre2 += (curve2[i] - meanCurveOverWindow(curve2, i, K)) * (curve2[i] - meanCurveOverWindow(curve2, i, K));
		}
		double denominator = Math.sqrt(carre1*carre2);
		return numerator/denominator;
	}

	public static double CORTPressure (List<Point> pointList1, List<Point> pointList2, int K) {
		double[] curve1 = parameters.extractPressureCurve(pointList1);
		double[] curve2 = parameters.extractPressureCurve(pointList2);
		double numerator = 0;
		double carre1 = 0;
		double carre2 = 0;
		for (int i=K; i<curve1.length-K; i++) {
			numerator += (curve1[i] - meanCurveOverWindow(curve1, i, K)) * (curve2[i] - meanCurveOverWindow(curve2, i, K));
			carre1 += (curve1[i] - meanCurveOverWindow(curve1, i, K)) * (curve1[i] - meanCurveOverWindow(curve1, i, K));
			carre2 += (curve2[i] - meanCurveOverWindow(curve2, i, K)) * (curve2[i] - meanCurveOverWindow(curve2, i, K));
		}
		double denominator = Math.sqrt(carre1*carre2);
		return numerator/denominator;
	}

	public static double DTWDistanceX(List<Point> pointList1, List<Point> pointList2, int nbPoints) {
		double[] curve1 = parameters.extractXCurve(pointList1);
		double[] curve2 = parameters.extractXCurve(pointList2);
		double DTW[][]=new double[nbPoints+1][nbPoints+1], cost;

		for(int i=1;i<nbPoints+1;i++){
			DTW[0][i] = Integer.MAX_VALUE;
			DTW[i][0] = Integer.MAX_VALUE;
		}
		DTW[0][0]= 0;

		for(int i=0;i<nbPoints;i++){
			for(int j=0;j<nbPoints;j++){
				cost= Math.abs(curve1[i] - curve2[j]);
				DTW[i+1][j+1] = cost + Math.min(Math.min(DTW[i][j+1],    // insertion
						DTW[i+1][j]),    // deletion
						DTW[i][j]);    // match
			}
		}
		return DTW[nbPoints][nbPoints];
	}

	public static double DTWDistanceY(List<Point> pointList1, List<Point> pointList2, int nbPoints) {
		double[] curve1 = parameters.extractYCurve(pointList1);
		double[] curve2 = parameters.extractYCurve(pointList2);
		double DTW[][]=new double[nbPoints+1][nbPoints+1], cost;

		for(int i=1;i<nbPoints+1;i++){
			DTW[0][i] = Integer.MAX_VALUE;
			DTW[i][0] = Integer.MAX_VALUE;
		}
		DTW[0][0]= 0;

		for(int i=0;i<nbPoints;i++){
			for(int j=0;j<nbPoints;j++){
				cost= Math.abs(curve1[i] - curve2[j]);
				DTW[i+1][j+1] = cost + Math.min(Math.min(DTW[i][j+1],    // insertion
						DTW[i+1][j]),    // deletion
						DTW[i][j]);    // match
			}
		}
		return DTW[nbPoints][nbPoints];
	}

	public static double DTWDistancePressure(List<Point> pointList1, List<Point> pointList2, int nbPoints) {
		double[] curve1 = parameters.extractPressureCurve(pointList1);
		double[] curve2 = parameters.extractPressureCurve(pointList2);
		double DTW[][]=new double[nbPoints+1][nbPoints+1], cost;

		for(int i=1;i<nbPoints+1;i++){
			DTW[0][i] = Integer.MAX_VALUE;
			DTW[i][0] = Integer.MAX_VALUE;
		}
		DTW[0][0]= 0;

		for(int i=0;i<nbPoints;i++){
			for(int j=0;j<nbPoints;j++){
				cost= Math.abs(curve1[i] - curve2[j]);
				DTW[i+1][j+1] = cost + Math.min(Math.min(DTW[i][j+1],    // insertion
						DTW[i+1][j]),    // deletion
						DTW[i][j]);    // match
			}
		}
		return DTW[nbPoints][nbPoints];
	}


	public static float pourcentageOfRadianceNormalization (List<Point> pointList1, List<Point> pointList2, int size) {
		int[][] matrix1 = parameters.matrixRadianceNormalization(pointList1, size);
		int[][] matrix2 = parameters.matrixRadianceNormalization(pointList2, size);
		return parameters.pourcentage(matrix1, matrix2, size);
	}

	public static float sumOfRadianceNormalization (List<Point> pointList1, List<Point> pointList2, int size) {
		int[][] matrix1 = parameters.matrixRadianceNormalization(pointList1, size);
		int[][] matrix2 = parameters.matrixRadianceNormalization(pointList2, size);
		return parameters.sum(matrix1, matrix2, size);
	}

	public static float pourcentageOfRadiance (List<Point> pointList1, List<Point> pointList2, int size) {
		int[][] matrix1 = parameters.matrixRadiance(pointList1, size);
		int[][] matrix2 = parameters.matrixRadiance(pointList2, size);
		return parameters.pourcentage(matrix1, matrix2, size);
	}

	public static float sumOfRadiance (List<Point> pointList1, List<Point> pointList2, int size) {
		int[][] matrix1 = parameters.matrixRadiance(pointList1, size);
		int[][] matrix2 = parameters.matrixRadiance(pointList2, size);
		return parameters.sum(matrix1, matrix2, size);
	}
	///////////////// Méthode à utiliser pour construction du modèle //////////////////////

	public static double[] comparaison (List<Point> pointList1, List<Point> pointList2, List<String> attributesList) {
		double[] data = new double[attributesList.size()];
		for (int i=0; i<attributesList.size(); i++) {
			// Si vitesse sélectionnée
			if (attributesList.get(i).equals("averagedSpeedX")) {
				data[i] = (double) compareAveragedSpeedX(pointList1, pointList2);
			} else if (attributesList.get(i).equals("averagedSpeedY")) {
				data[i] = (double) compareAveragedSpeedY(pointList1, pointList2);
			} else if (attributesList.get(i).equals("averagedSpeed")) {
				data[i] = (double) compareAveragedSpeed(pointList1, pointList2);
			} else if (attributesList.get(i).equals("totalTime")) {
				data[i] = (double) compareTotalTime(pointList1, pointList2);
				// Dans tous les cas, on prend le nombre de lever de stylos
			}  else if (attributesList.get(i).equals("numberPenUp")) {
				data[i] = (double) compareNumberOfPenUp(pointList1, pointList2);
			// Si pression sélectionnée
			} else if (attributesList.get(i).equals("averagedPressure")) {
				data[i] = (double) compareAveragedPressure(pointList1, pointList2);
			} else if (attributesList.get(i).equals("CORTPressure")) {
				data[i] = (double) CORTPressure(pointList1, pointList2, 4);
			} else if (attributesList.get(i).equals("DTWPressure")) {
				data[i] = (double) DTWDistancePressure(pointList1, pointList2, nbPoints);
			// Si positionX sélectionnée
			} else if (attributesList.get(i).equals("CORTX")) {
				data[i] = (double) CORTX(pointList1, pointList2, 4);
			} else if (attributesList.get(i).equals("DTWX")) {
				data[i] = (double) DTWDistanceX(pointList1, pointList2, nbPoints);
			// Si positionY sélectionnée
			} else if (attributesList.get(i).equals("CORTY")) {
				data[i] = (double) CORTY(pointList1, pointList2, 4);
			} else if (attributesList.get(i).equals("DTWY")) {
				data[i] = (double) DTWDistanceY(pointList1, pointList2, nbPoints);
			// SI positionX et positionY sélectionnées
			} else if (attributesList.get(i).equals("pourcentageRadiance")) {
				data[i] = (double) pourcentageOfRadianceNormalization(pointList1, pointList2, size);
			} else if (attributesList.get(i).equals("sumRadiance")) {
				data[i] = (double) sumOfRadianceNormalization(pointList1, pointList2, size);
			}
		}
		return data;
	}
}
