package Model;

import java.util.List;

public class Parameters {

	public double[] extractXCurve (List<Point> pointList) {
		double[] xCurve = new double[pointList.size()];
		for (int i=0; i<pointList.size(); i++) {
			xCurve[i] = pointList.get(i).getPoint().x;
		}
		return xCurve;
	}

	public double[] extractXMoves (List<Point> pointList) {
		double[] xMoves = new double[pointList.size()];
		for (int i=1; i<pointList.size(); i++) {
			xMoves[i] = pointList.get(i).getPoint().x - pointList.get(i-1).getPoint().x;
		}
		return xMoves;
	}

	public double extractXSumMoves (List<Point> pointList) {
		double xSum = 0;
		for (int i=1; i<pointList.size(); i++) {
			xSum += pointList.get(i).getPoint().x - pointList.get(i-1).getPoint().x;
		}
		return xSum;
	}

	public float[] extractSpeedXCurve (List<Point> pointList) {
		float[] speedXCurve = new float[pointList.size()-1];
		for (int i=0; i<pointList.size()-1; i++) {
			speedXCurve[i] = ((float) (pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		return speedXCurve;
	}

	public float extractSpeedXSum (List<Point> pointList) {
		float speedXSum = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			speedXSum += ((float) (pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		return speedXSum;
	}

	public float extractAveragedSpeedX (List<Point> pointList) {
		float averagedSpeedX = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			averagedSpeedX += (float) ((pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		averagedSpeedX /= pointList.size()-1;
		return averagedSpeedX;
	}

	public double[] extractYCurve (List<Point> pointList) {
		double[] yCurve = new double[pointList.size()];
		for (int i=0; i<pointList.size(); i++) {
			yCurve[i] = pointList.get(i).getPoint().y;
		}
		return yCurve;
	}

	public double[] extractYMoves (List<Point> pointList) {
		double[] yMoves = new double[pointList.size()];
		for (int i=1; i<pointList.size(); i++) {
			yMoves[i] = pointList.get(i).getPoint().y - pointList.get(i-1).getPoint().y;
		}
		return yMoves;
	}

	public double extractYSumMoves (List<Point> pointList) {
		double ySum = 0;
		for (int i=1; i<pointList.size(); i++) {
			ySum += pointList.get(i).getPoint().y - pointList.get(i-1).getPoint().y;
		}
		return ySum;
	}

	public double extractSumMoves (List<Point> pointList) {
		double sumMoves = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			double dx = pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x;
			double dy = pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y;
			sumMoves += Math.sqrt(dx*dx + dy*dy);
		}
		return sumMoves;
	}

	public float[] extractSpeedYCurve (List<Point> pointList) {
		float[] speedYCurve = new float[pointList.size()-1];
		for (int i=0; i<pointList.size()-1; i++) {
			speedYCurve[i] = (float) ((pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		return speedYCurve;
	}

	public float extractSpeedYSum (List<Point> pointList) {
		float speedYSum = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			speedYSum += ((float) (pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		return speedYSum;
	}

	public float extractAveragedSpeedY (List<Point> pointList) {
		float averagedSpeedY = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			averagedSpeedY += (float) ((pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		averagedSpeedY /= pointList.size()-1;
		return averagedSpeedY;
	}

	public float[] extractSpeedCurve (List<Point> pointList) {
		float[] speedCurve = new float[pointList.size()-1];
		for (int i=0; i<pointList.size()-1; i++) {
			double dx = pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x;
			double dy = pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y;
			speedCurve[i] = (float) (Math.sqrt(dx*dx + dy*dy) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		return speedCurve;
	}

	public float extractSpeedSum (List<Point> pointList) {
		float speedSum = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			double dx = pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x;
			double dy = pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y;
			speedSum += (float) (Math.sqrt(dx*dx + dy*dy) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		return speedSum;
	}

	public float extractAveragedSpeed (List<Point> pointList) {
		float averagedSpeed = 0;
		for (int i=0; i<pointList.size()-1; i++) {
			double dx = pointList.get(i+1).getPoint().x - pointList.get(i).getPoint().x;
			double dy = pointList.get(i+1).getPoint().y - pointList.get(i).getPoint().y;
			averagedSpeed += (float) (Math.sqrt(dx*dx + dy*dy) / (pointList.get(i+1).getTime() - pointList.get(i).getTime()));
		}
		averagedSpeed /= pointList.size()-1;
		return averagedSpeed;
	}

	public int extractNumberOfPenUp (List<Point> pointList) {
		int numberOfPenUp = 0;
		float previousTime = 0;
		for (int i=0; i<pointList.size(); i++) {
			if (pointList.get(i).getTime() >= previousTime+32) {
				numberOfPenUp++;
			}
			previousTime = pointList.get(i).getTime();
		}
		return numberOfPenUp;
	}

	public double[] extractPressureCurve (List<Point> pointList) {
		double[] pressureCurve = new double[pointList.size()];
		for (int i=0; i<pointList.size(); i++) {
			pressureCurve[i] = (double) pointList.get(i).getPressure();
		}
		return pressureCurve;
	}

	public float extractAveragedPressure (List<Point> pointList) {
		int averagedPressure = 0;
		for (int i=0; i<pointList.size(); i++) {
			averagedPressure += (double) pointList.get(i).getPressure();
		}
		averagedPressure /= pointList.size();
		return averagedPressure;
	}

	public float[] extractTimeCurve (List<Point> pointList) {
		float[] timeCurve = new float[pointList.size()];
		for (int i=0; i<pointList.size(); i++) {
			timeCurve[i] = pointList.get(i).getTime();
		}
		return timeCurve;
	}

	public float extractTotalTime (List<Point> pointList) {
		return (pointList.get(pointList.size()-1).getTime() - pointList.get(0).getTime());
	}

	public Object[][] extractAllCurves (List<Point> pointList) {
		Object[][] allCurves = new Object[4][pointList.size()];
		for (int i=0; i<pointList.size(); i++) {
			allCurves[0][i] = pointList.get(i).getPoint().x;
			allCurves[1][i] = pointList.get(i).getPoint().y;
			allCurves[2][i] = pointList.get(i).getPressure();
			allCurves[3][i] = pointList.get(i).getTime();
		}
		return allCurves;
	}

	/**
	 * Retourne la matrice issue du rayonnement appliqué sur une liste de points
	 * @param pointList, la liste de points
	 * @param size, la taille de la matrice
	 * @return la matrice rayonnée par pourcentage de valeurs
	 */
	public int[][] matrixRadianceNormalization(List<Point> pointList, int size){

		// Matrice qui subira le rayonnement
		int matrixOut[][] = new int[size][size];
		for (int x=0; x<size; x++) {
			for (int y=0; y<size; y++) {
				matrixOut[x][y] = 0;
			}
		}
		// Impact du rayonnement sur les pixels situés dans un rayon de 10 pixels
		int impact[] = new int[10];
		// Pour chaque distance, calcul de l'impact
		for(int i=0; i<impact.length; i++){
			int pourcentage = 100 - (5*i*i)/2;
			if (pourcentage > 0){
				impact[i] = pourcentage;
			} else {
				impact[i] = 0;
			}
		}

		// Pour chaque point
		for(int i=0;i<pointList.size();i++){
			int x = (int) pointList.get(i).getPoint().x;
			int y = (int) pointList.get(i).getPoint().y;
			// On récupère la valeur du pixe d'origine
			matrixOut[x][y]=1;

			// Pout tous les pixels inclus dans la zoned'impact du rayonnement
			for(int xTemp=0; xTemp<5; xTemp++){
				for(int yTemp=0; yTemp<5; yTemp++){
					if (x-xTemp>0 && y-yTemp>0) {
						if(matrixOut[x-xTemp][y-yTemp]<impact[xTemp+yTemp])
							matrixOut[x-xTemp][y-yTemp] = impact[xTemp+yTemp];
					}
					if (x-xTemp>0 && y+yTemp<size) {
						if(matrixOut[x-xTemp][y+yTemp]<impact[xTemp+yTemp])
							matrixOut[x-xTemp][y+yTemp] = impact[xTemp+yTemp];
					}
					if (x+xTemp<size && y-yTemp>0) {
						if(matrixOut[x+xTemp][y-yTemp]<impact[xTemp+yTemp])
							matrixOut[x+xTemp][y-yTemp] = impact[xTemp+yTemp];
					}
					if (x+xTemp<size && y+yTemp<size) {
						if(matrixOut[x+xTemp][y+yTemp]<impact[xTemp+yTemp])
							matrixOut[x+xTemp][y+yTemp] = impact[xTemp+yTemp];
					}
				}
			}
		}
		return matrixOut;
	}

	/**
	 * Retourne le rapport nombre de pixels communs sur nombre de pixels non nuls
	 * @param matrix1, la première matrice rayonnée
	 * @param matrix2, la seconde matrice rayonnée
	 * @param taille, la taille de ces matrices
	 * @return la rapport nombre de pixels communs sur nombre de pixels non nuls
	 */
	public float pourcentage(int[][] matrix1,int[][] matrix2, int size){
		int union=0, diff=0;

		for(int x=0;x<size;x++){
			for(int y=0;y<size;y++){
				if (matrix1[x][y]!=0 && matrix2[x][y]!=0){
					union++;
				} else if (matrix1[x][y]!=0 || matrix2[x][y]!=0){
					diff++;
				}
			}
		}
		return (float) ((100.*union)/(union + diff));
	}


	/**
	 * 
	 * @param matrix1, la première matrice rayonnée
	 * @param matrix2, la seconde matrice rayonnée
	 * @param taille, la taille de ces matrices
	 * @return
	 */
	public float sum(int[][] matrix1,int[][] matrix2, int size){
		int res=0;

		for(int x=0;x<size;x++){
			for(int y=0;y<size;y++){
				res += matrix1[x][y]*matrix2[x][y];
			}
		}
		return res;

	}

	/**
	 * Retourne la matrice issue du rayonnement appliqué sur une liste de points
	 * @param pointList, la liste de points
	 * @param size, la taille de la matrice
	 * @return la matrice rayonnée par somme de valeurs
	 */
	public int[][] matrixRadiance(List<Point> pointList, int size){

		// Matrice qui subira le rayonnement
		int matrixOut[][] = new int[size][size];
		for (int x=0; x<size; x++) {
			for (int y=0; y<size; y++) {
				matrixOut[x][y] = 0;
			}
		}
		// Impact du rayonnement sur les pixels situés dans un rayon de 10 pixels
		int impact[] = new int[10];
		// Pour chaque distance, calcul de l'impact
		for(int i=0; i<impact.length; i++){
			int pourcentage = 100 - (5*i*i)/2;
			if (pourcentage > 0){
				impact[i] = pourcentage;
			} else {
				impact[i] = 0;
			}
		}

		// Pour chaque point
		for(int i=0;i<pointList.size();i++){
			int x = (int) Math.round(pointList.get(i).getPoint().x);
			int y = (int) Math.round(pointList.get(i).getPoint().y);
			// On récupère la valeur du pixe d'origine
			matrixOut[x][y]=1;

			// Pout tous les pixels inclus dans la zone d'impact du rayonnement
			for(int xTemp=0; xTemp<5; xTemp++){
				for(int yTemp=0; yTemp<5; yTemp++){
					if(0<x-xTemp && 0<y-yTemp)
						matrixOut[i-xTemp][y-yTemp]+=impact[xTemp+yTemp];
					if(0<x-xTemp && y+yTemp<size)
						matrixOut[i-xTemp][y+yTemp]+=impact[xTemp+yTemp];
					if(x+xTemp<size && 0<y-yTemp)
						matrixOut[i+xTemp][y-yTemp]+=impact[xTemp+yTemp];
					if(x+xTemp<size && y+yTemp<size)
						matrixOut[i+xTemp][y+yTemp]+=impact[xTemp+yTemp];
				}
			}
		}
		return matrixOut;
	}
}
