/*
* This file is part of the TraKERS\Front IDILL package.
*
* (c) IRI <http://www.iri.centrepompidou.fr/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/*
 * Projet : TraKERS
 * Module : Front IDILL
 * Fichier : curvesDetector.js
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Détecteur de courbes de recherche, appelé par la classe de création du canvas de recherche.
 */

/*
 * Détecteur de courbes (lignes droites, arcs de cercles et cercles).
*/
function curvesDetector(divisions, sizeTreshold, dictionary, mosaic)
{
	//Précision de la détection de direction en divisions (par défaut 12, selon une modélisation horaire et non mathématique).
	this.divisions = divisions;
	//Taille limite pour un segment/courbe pour être considéré comme tel en px.
	this.sizeTreshold = sizeTreshold;
	
	this.dictionary = dictionary;
	
	this.mosaic = mosaic;
	
	//Code actuel généré. Il représente la structure de la courbe de recherche.
	this.actualCode = '';
	
	this.joints = [];
	this.jInc = 0;
	
	//Longueur totale de la courbe.
	this.MPTotalDist = 0;
	this.SPTotalDist = 0;
	//Longueur de la partie actuelle (après début ou changement de direction).
	this.MPActualDist = 0;
	this.SPActualDist = 0;
	//Angles actuels.
	this.MPActualAngle = -1;
	this.SPActualAngle = -1;
	
	//Centre du repère du pointeur principal.
	this.MPrepX;
	this.MPrepY;
	//Centre du repère du pointeur secondaire.
	this.SPrepX;
	this.SPrepY;
	
	//Coordonnées actuelles du/des pointeur/s.
	this.MPx = 0;
	this.MPy = 0;
	this.SPx = 0;
	this.SPy = 0;
	//Coordonnées précédentes du/des pointeur/s.
	this.MPpx = 0;
	this.MPpy = 0;
	this.SPpx = 0;
	this.SPpy = 0;
	
	//Si les paramètres sont incorrects, on leur donne une valeur par défaut.
	if(isNaN(divisions) || divisions < 1 || divisions > 360)
	{
		this.divisions = 12;
	}
	if(sizeTreshold < 1)
	{
		sizeTreshold = 30;
	}
}

/*
 * Reinit les paramètres du détecteur.
*/
curvesDetector.prototype.reinit = function()
{
	this.MPrepX = 0;
	this.MPrepY = 0;
	this.MPpx = 0;
	this.MPpy = 0;
	this.MPActualAngle = -1;
	this.SPActualAngle = -1;
	this.actualCode = '';
	
	/*for(var i = 0 ; i < this.joints.length ; i++)
	{
		if(this.joints[i])
		{
			this.joints[i].remove();
		}
	}
	
	this.jInc = 0;*/
	this.MPActualDist = 0;
	this.MPTotalDist = 0;
}

/*
 * Met à jour les positions des pointeurs
*/
curvesDetector.prototype.updatePos = function(mpx, mpy, spx, spy)
{
	//On met à jour les coordonnées récentes.
	this.MPx = mpx;
	this.MPy = mpy;
	
	//Si les coordonnées précédentes n'existent pas, alors on les met à jour.
	if(!this.MPpx)
	{
		this.MPpx = mpx;
	}
	if(!this.MPpy)
	{
		this.MPpy = mpy;
	}
	if(!this.MPrepX)
	{
		this.MPrepX = mpx;
	}
	if(!this.MPrepY)
	{
		this.MPrepY = mpy;
	}
	
	//Si on a un second pointeur.
	if(spx && spy)
	{
		//On met les coordonnées à jour.
		this.SPx = spx;
		this.SPy = spy;
		
		//Si les coordonnées précédentes n'existent pas, alors on les met à jour.
		if(!this.SPpx)
		{
			this.SPpx = spx;
		}
		if(!this.SPpy)
		{
			this.SPpy = spy;
		}
	}
	
	this.updateDists();
}

/*
 * Met à jour les distances parcourues.
*/
curvesDetector.prototype.updateDists = function()
{
	var foundGestures;
	
	//Si on a de quoi calculer les distances.
	if(this.MPx && this.MPy && this.MPpx && this.MPpy && this.MPrepX && this.MPrepY)
	{
		var MPDist = Math.floor(Math.sqrt((this.MPx - this.MPpx) * (this.MPx - this.MPpx) + (this.MPy - this.MPpy) * (this.MPy - this.MPpy)));
		this.MPTotalDist += MPDist;
		this.MPActualDist += MPDist;
		
		var MPCurrentA = -1;
		
		if(MPDist > 0)
		{
			MPCurrentA = this.currentAngle(this.MPrepX, this.MPrepY, this.MPx, this.MPy, this.divisions);
			// console.log(MPCurrentA);//, this.MPActualDist);
		}
		
		if(this.MPActualDist > this.sizeTreshold && MPCurrentA != -1)
		{
			console.log(this.MPActualAngle, MPCurrentA, this.MPActualAngle != -1, this.MPActualAngle != MPCurrentA);
			
			if(this.MPActualAngle == -1 || this.MPActualAngle != MPCurrentA)
			{
				this.MPActualAngle = MPCurrentA;
				this.actualCode += 'D' + MPCurrentA;
				this.mosaic.actualCode = this.actualCode;
				
				foundGestures = this.codeToGestures(this.actualCode);
				
				console.log(+this.jInc+1, this.MPActualDist);
				console.log(this.actualCode);
				console.log(foundGestures);
				
				if(foundGestures.length == 0 || foundGestures.split(';').length != 1)
				{
					console.log('many curves');
					this.mosaic.curvesGesturesFound = true;
					this.mosaic.removeNotifications();
					this.mosaic.curvesGestures(foundGestures);
					
					if(foundGestures.length == 0 && !this.mosaic.helpDisplayed)
					{
						this.mosaic.notifyHelp();
						foundGestures = '';
						this.mosaic.curvesGesturesFound = false;
						this.mosaic.isSearchByCurvesOn = false;
						this.mosaic.leaveSearch();
					}
					else if(foundGestures.split(';').length != 1 && this.mosaic.helpDisplayed)
					{
						if(this.mosaic.helpDisplayed)
						{
							this.mosaic.removeHelp();
						}
					}
				}
				else
				{
					// console.log(this.mosaic.currentMode);
					this.mosaic.currentSearchGesture[this.mosaic.centerId] = foundGestures;
					this.mosaic.isUserInSearchZone = false;
					
					if(this.mosaic.currentMode == "SEARCH" && this.mosaic.playerIsReady)
					{
						this.mosaic.player.widgets[0].searchByGesture(foundGestures);
						this.mosaic.isCurrentlyInASearchByGesture = this.mosaic.player.widgets[0].isCurrentlyInASearchByGesture;
						
						this.mosaic.removeNotifications();
						this.mosaic.searchGesture(foundGestures, 'valid');
						
						if(this.mosaic.player && this.mosaic.player.widgets[0] && this.mosaic.timeToGoAt[this.mosaic.centerId] === 0 && this.mosaic.player.widgets[0].atLeastOneSearchMarker(this.mosaic.currentSearchGesture[this.mosaic.centerId]))
						{
							this.mosaic.player.widgets[0].goToFirstSearchedMarker(this.mosaic.currentSearchGesture[this.mosaic.centerId]);
						}
						
						this.mosaic.currentSearchGesture[this.mosaic.centerId] = foundGestures;
						
						foundGestures = '';
						this.mosaic.curvesGesturesFound = false;
						
						this.mosaic.isSearchByCurvesOn = false;
						this.mosaic.leaveSearch();
					}
					else if(this.mosaic.currentMode == "FILTER")
					{
						if(this.mosaic.isMosaicFiltered)
						{
							console.log('1 curve : ' + foundGestures);
							this.mosaic.filterSearchedType = foundGestures;
							this.mosaic.searchFilter(foundGestures);
							this.mosaic.curvesGesturesFound = false;
							
							this.mosaic.removeNotifications();
							this.mosaic.filterGesture(foundGestures, 'valid');
							
							foundGestures = '';
							
							this.mosaic.isSearchByCurvesOn = false;
							this.mosaic.leaveSearch();
						}
					}
				}
				
				this.MPActualDist = 0;
				//this.jInc++
			}
			else
			{
				this.MPrepX = this.MPpx;
				this.MPrepY = this.MPpy;
				
				/*if(this.joints[this.jInc])
				{
					this.joints[this.jInc].remove();
				}
				this.joints[this.jInc] = new paper.Path.Circle(new paper.Point(this.MPrepX, this.MPrepY), 10);
				this.joints[this.jInc].strokeColor = 'black';
				this.joints[this.jInc].fillColor = 'green';*/
			}
			
			if(this.MPActualAngle == -1)
			{
				this.MPActualAngle = MPCurrentA;
			}
		}
		
		//On met à jour les coordonnées précédentes.
		if(this.MPpx != this.MPx)
		{
			this.MPpx = this.MPx;
		}
		if(this.MPpy != this.MPy)
		{
			this.MPpy = this.MPy;
		}
	}
	//Idem au cas où on aurait un deuxième pointeur.
	if(this.SPx && this.SPy && this.SPpx && this.SPpy)
	{
		var SPDist = Math.floor(Math.sqrt((this.SPx - this.SPpx) * (this.SPx - this.SPpx) + (this.SPy - this.SPpy) * (this.SPy - this.SPpy)));
		this.SPTotalDist += SPDist;
		this.SPActualDist += SPDist;
		
		if(SPDist > 0)
		{
			this.currentAngle(this.SPpx, this.SPpy, this.SPx, this.SPy);
		}
		
		//On met à jour les coordonnées précédentes.
		if(this.SPpx != this.SPx)
		{
			this.SPpx = this.SPx;
		}
		if(this.SPpy != this.SPy)
		{
			this.SPpy = this.SPy;
		}
	}
}

/*
 * Renvoie les noms de gestures du dictionnaire qui ont un code qui commence par le code en entrée.
*/
curvesDetector.prototype.codeToGestures = function(code)
{
	//Variable qui va stocker tous les noms trouvés.
	var retNames = '';
	
	//Pour tout le dictionnaire.
	for(var i = 0 ; i < this.dictionary.length ; i++)
	{
		//Pour touts les codes de chaque gesture du dictionnaire.
		for(var j = 0 ; j < this.dictionary[i].codes.length ; j++)
		{
			//Si le code en entrée est une partie début d'un des codes.
			if(this.dictionary[i].codes[j].indexOf(code) == 0)
			{
				//On ajoute le nom de la gesture et on passe à la gesture suivante.
				retNames += this.dictionary[i].name + ';';
				break;
			}
		}
	}
	//Comme on sépare chaque nom par un ;, il faut supprimer le dernier si au moins un nom a été trouvé.
	if(retNames.length > 0)
	{
		retNames = retNames.substring(0, retNames.length-1);
	}
	
	//On renvoit les noms.
	return retNames;
}

/*
 * Calcule l'angle emprunté par le morceau de segment actuel. On prend A va vers B.
*/
curvesDetector.prototype.currentAngle = function(xa, ya, xb, yb, divisions)
{
	//On calcule l'angle de la droite AB et des abscisses, et on effectue une rotation de 90° vers la gauche.
	var angleRad = Math.atan2((ya - yb), (xa - xb)) - Math.PI / 2;
	//On traduit les radians en divisions en passant de [-PI/2 ; PI/2] à [0 ; divisions - 1].
	var angleDiv = Math.floor((angleRad > 0 ? angleRad : (2*Math.PI + angleRad)) * divisions / (2*Math.PI));
	
	//L'angle initial est 0.
	if(angleDiv == divisions)
	{
		angleDiv = 0;
	}
	
	return angleDiv;
}