/*
* 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 : neighbours.js
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Définit les fonctions d'intéraction avec les voisins lors d'un zoom.
 */

/*
 * Affecte les listeners mouseenter aux voisins lors d'une vue en plein écran.
 * Est appelé : dans les fichiers neighbours > fonction moveToNeighbour et zoomInteractions > fonction zoom.
 */
Mosaic.prototype.listenToNeighbours = function()
{
    //Si on n'est pas en mode recherche, on enlève les notifications.
    if(this.currentMode != 'SEARCH')
    {
        this.removeNotifications();
    }
    
    //Si on est en mode sans utilisateur ou en mode utilisateur approche, on part.
    if(this.currentMode == "NO-USER" || this.currentMode.indexOf("INCOMING") != -1)
    {
        return;
    }
    
    //Si ils n'y a pas de voisins répertoriés, on part.
    if(this.neighboursIds == null || this.neighboursIds != null && this.neighboursIds.length > 0)
    {
        return;
    }
    
    var _this = this;
    
    //On ne peut actuellement pas se déplacer vers un voisin.
    this.canMoveToNeighbour = false;
    //On calcule la ligne et colonne du snapshot du milieu.
    var currentLine = Math.floor(this.centerId / this.config.imagesByLine), currentColumn = this.centerId % this.config.imagesByLine;
    var zoomedImg = $('img', this.previousZoomedSN);
    
    //On cherche l'ID des voisins.
    //Si le voisin de gauche est sur la même ligne, on n'est pas sur la bordure de gauche.
    this.neighboursIds[0] = (currentColumn > 0) ? (this.centerId - 1) : -1;
    //Si le voisin de droite est sur la même ligne, on n'est pas sur la bordure de droite.
    this.neighboursIds[1] = (currentColumn < this.config.imagesByLine - 1) ? (+this.centerId + 1) : -1;
    //Si le voisin du haut est sur la même colonne, on n'est pas sur la bordure du haut.
    this.neighboursIds[2] = (currentLine > 0) ? (this.centerId - this.config.imagesByLine) : -1;
    //Si le voisin du bas est sur la même colonne, on n'est pas sur la bordure du bas.
    this.neighboursIds[3] = (currentLine < (this.config.imagesToShow / this.config.imagesByLine)) ? (+this.centerId + this.config.imagesByLine) : -1;
    
    //ID du cadre voisin.
    var preId;
    
    //Si les voisins ont un id supérieur au maximum, on les met à -1.
    for(var i = 0 ; i < this.neighboursIds.length ; i++)
    {
        if(this.neighboursIds[i] >= this.config.imagesToShow)
        {
            this.neighboursIds[i] = -1;
        }
    }
    
    //Si on est sur une bordure.
    //On crée des voisins supplémentaires.
    if(_.include(this.neighboursIds, -1))
    {
        this.createAdditionalNeighbours();
    }
}

/*
 * Crée des voisins supplémentaires pour garantir le déplacement / dézoom quand on arrive sur le bord de la mosaïque.
 * Est appelé : dans le fichier neighbours > fonction listenToNeighbours.
*/
Mosaic.prototype.createAdditionalNeighbours = function()
{
    //Si on est en mode sans utilisateur, on part.
    if(this.currentMode == "NO-USER")
    {
        return;
    }
	
    //Pour tous les voisins.
    var additionalNeighbours = '';
    for(var i = 0 ; i < this.neighboursIds.length ; i++)
    {
        //Snapshot du milieu.
        var sn = $('#snapshotDiv-' + this.centerId);
        //Marge de celui-ci.
        var m = parseInt(sn.css('margin'));
        //Ses coordonnées.
        var centerTop = sn.position().top + this.notifyTopVideo + this.MPTop_margin, centerLeft = sn.position().left + this.notifyLeftVideo;
        //Ses dimensions.
        var centerWidth = sn.width(), centerHeight = sn.height();
        
        var top, left;
        
        //Si on est sur une bordure, on calcule les coordonnées du voisin à l'extérieur de la bordure en fonction de sa position dans le tableau des voisins.
        if(this.neighboursIds[i] == -1)
        {
            if(i == 0)
            {
                top = centerTop + m / 2;
                left = centerLeft - centerWidth - 2 * m;
            }
            else if(i == 1)
            {
                top = centerTop + m / 2;
                left = centerLeft + centerWidth + 3 * m;
            }
            else if(i == 2)
            {
                top = centerTop - centerHeight - 2 * m;
                left = centerLeft + m / 2;
            }
            else if(i == 3)
            {
                top = centerTop + centerHeight + 3 * m;
                left = centerLeft + m / 2;
            }
            
            //On place le voisin additionnel.
            additionalNeighbours += '<div id="borderNeighbour-' + i + '" class="borderNeighbours" style="opacity: 0; width: ' + centerWidth + 'px; height: ' + centerHeight + 'px; top: ' + top + 'px; left: ' + left + 'px;"></div>';
        }
    }
    
    $('body').append(additionalNeighbours);
    //On le fait apparaître.
    $('.borderNeighbours').fadeTo(this.config.timeANFade, '1');
}

/*
 * Supprime les voisins supplémentaires.
 * Est appelé : dans les fichiers neighbours > fonction moveToNeighbour et zoomInteractions > fonction unzoom.
*/
Mosaic.prototype.removeAdditionalNeighbours = function()
{
    $('.borderNeighbours').fadeTo(this.config.timeANFade, '0', function()
    {
        $('.borderNeighbours').remove();
    });
    this.deselectAllNeighbours();
}

/*
 * Déselectionne tous les voisins, même les additionnels.
 * Est appelé : dans les fichier neighbours > fonction removeAdditionalNeighbours.
*/
Mosaic.prototype.deselectAllNeighbours = function()
{
    $('.neighbourFrame').fadeTo(this.config.timeANFade, '0', function()
    {
        $('.neighbourFrame').remove();
    });
}

/*
 * Change la coloration d'une bordure où on se positionne lors d'une vue en plein écran.
 * Est appelé : dans le fichier pointers > fonction pointersVideoInteractions.
 */
Mosaic.prototype.selectNeighbour = function(neighbour, pointer)
{
    //Si on est en train de se déplacer vers un voisin ou dézoomer ou si l'aide est affichée, on part.
    if(this.currentlyMoving || this.currentlyUnzooming || this.helpDisplayed)
    {
        return;
    }
    
    //Si on est sur une notification de gesture de recherche.
    if(this.gestureDelRequested)
    {
        //On récupère l'id du voisin.
        var tab = neighbour.attr('id').split('-');
        var snapshotId = tab[1];
        //On le déselectionne.
        this.deselectNeighbour(snapshotId);
        //On part.
        return;
    }
    
    //On ne peut pas faire de swipes.
    this.canSwipe = false;
    
    var _this = this;
    
    //Si on est en mode VIDEO (plein écran) ET si le snapshot pointé est un voisin.
	if((this.currentMode == 'VIDEO' || this.currentMode == 'SEARCH') && (neighbour.attr('id') != 'snapshotDiv-' + this.centerId))
    {
        //On crée le cadre qui va être superposé au voisin.
        //On le colle au voisin.
        var tab = neighbour.attr('id').split('-');
        var snapshotId = tab[1];
        var neighbourFrame = '';
        var marginValue = parseFloat(neighbour.css('margin'));
        
        //Si la frame existe déjà, on quitte.
        if($('#neighbourFrame-' + snapshotId).length > 0)
        {
            return;
        }
        
        //Si c'est un voisin additionnel.
        if(neighbour.attr('id').indexOf('borderNeighbour') != -1)
        {
            //On le sélectionne quand même.
            snapshotId = +snapshotId + this.config.imagesToShow;
            neighbourFrame += '<div class="neighbourFrame" id="neighbourFrame-' + snapshotId + '"></div>';
            if($('#neighbourFrame-' + snapshotId).length > 0)
            {
                return;
            }
            $('body').append(neighbourFrame);
        }
        //Si c'est un voisin normal.
        else
        {
            //On le sélectionne.
            neighbourFrame += '<div class="neighbourFrame" id="neighbourFrame-' + snapshotId + '"><div class="neighbourImgBg" id="neighbourImgBg-' + snapshotId + '"><div class="neighbourImg" id="neighbourImg-' + snapshotId + '"></div></div></div>';
            if($('#neighbourFrame-' + snapshotId).length > 0)
            {
                return;
            }
            $('#mainPanel').append(neighbourFrame);
        }
        
        //On positionne le div de background juste au niveau du voisin.
        $('#neighbourFrame-' + snapshotId).css(
        {
            'top': (+neighbour.position().top + marginValue),
            'left': (+neighbour.position().left + marginValue),
            'width': neighbour.width(),
            'height': neighbour.height()
        });
        //On positionne le div de background noir juste au niveau de l'image du voisin.
        $('#neighbourImgBg-' + snapshotId).css(
        {
            'top': marginValue,
            'left': marginValue,
            'width': neighbour.width() - marginValue*2,
            'height': neighbour.height() - marginValue*2,
        });
        //On met par dessus le div de l'image clonée du voisin.
        $('#neighbourImg-' + snapshotId).css(
        {
            'top': 0,
            'left': 0,
            'width': neighbour.width() - marginValue*2,
            'height': neighbour.height() - marginValue*2,
            'background-image': 'url("' + $('img', neighbour).attr('src') + '")',
            'background-size': neighbour.width() + 'px ' + neighbour.height() + 'px',
            'background-position': -marginValue + 'px ' + -marginValue + 'px',
            'opacity': '0.4'
        });
        
        var fId = '#neighbourFrame-' + snapshotId;
        
        $(fId).animate(
        {
            //On le fait apparaître.
            opacity: '1'
        }, _this.config.timeNeighbourGlowing, function()
        {
            //Si on est en mode d'intéraction souris.
            if(_this.config.mouseInteractions)
            {
                //Si on est en mode video.
                if(_this.currentMode == 'VIDEO')
                {
                    //On notifie.
                    _this.removeNotifications();
                    _this.videoMove(snapshotId);
                }
                //Si on est en mode de recherche mais sans gesture encore.
                else if(_this.currentMode == 'SEARCH' && _this.currentSearchGesture[_this.centerId] == '')
                {
                    //On notifie.
                    _this.removeNotifications();
                    _this.searchSearchAndMove(snapshotId);
                }
                //Si on est en mode de recherche avec une gesture.
                else if(_this.currentMode == 'SEARCH' && _this.currentSearchGesture[_this.centerId] != '')
                {
                    //On notifie.
                    _this.removeNotifications();
                    _this.searchGestureAndMove(_this.currentSearchGesture[_this.centerId], 'valid', snapshotId);
                }
                
                //On peut bouger vers un voisin.
                _this.canMoveToNeighbour = true;
            }
            //Si on est en mode d'intéractions Kinect.
            else
            {
                //Si on est en mode video, on notifie mais avec un dézoom possible.
                if(_this.currentMode == 'VIDEO')
                {
                    _this.removeNotifications();
                    _this.videoMoveAndUnzoom(snapshotId);
                }
                //Si on est en mode de recherche mais sans gesture encore, on notifie mais avec un dézoom possible.
                else if(_this.currentMode == 'SEARCH' && !_this.currentSearchGesture[_this.centerId])
                {
                    _this.removeNotifications();
                    _this.searchSearchAndMoveAndUnzoom(snapshotId);
                }
                //Si on est en mode de recherche avec une gesture, on notifie mais avec un dézoom possible.
                else if(_this.currentMode == 'SEARCH' && _this.currentSearchGesture[_this.centerId])
                {
                    _this.removeNotifications();
                    _this.searchGestureAndMoveAndUnzoom(_this.currentSearchGesture[_this.centerId], 'valid', snapshotId);
                }
            }
        });
        
        //On repère de quel côté le voisin se trouve en fonction du centre.
        var side = $.inArray(parseInt(snapshotId), this.neighboursIds);
        
        //S'il n'est nulle part on part.
        if(side == -1)
        {
            return;
        }
        
        //On affecte l'image de la notification en fonction du côté.
        var sides = ['left', 'right', 'down', 'up'];
        pointer.css('background-image', 'url(./img/cursors/' + sides[side] + '_gray.png)');
    }
}

/*
 * Change la coloration d'une bordure quittée lors d'une vue en plein écran.
 * Est appelé : dans les fichiers neighbours > fonction selectNeighbour et pointers > fonction pointersVideoInteractions.
 */
Mosaic.prototype.deselectNeighbour = function(neighbourId)
{
    if($('#neighbourFrame-' + neighbourId).length <= 0)
    {
        return;
    }
    
    var _this = this;
    
    //On ne peut plus se déplacer vers les voisins.
    this.canMoveToNeighbour = true;
    
    //On récupère le voisin.
    var neighbourFrame = $('#neighbourFrame-' + neighbourId);
    
    //Si on est en mode VIDEO.
    if(this.currentMode == 'VIDEO' || this.currentMode == 'SEARCH')
    {
        //On le fait disparaître progressivement.
        neighbourFrame.animate(
        {
            opacity: '0'
        }, this.config.timeNeighbourUnglowing, function()
        {
            //Une fois invisible, on le supprime.
            neighbourFrame.remove();
            _this.removeNotifications();
            
            if(_this.currentMode == 'SEARCH' && _this.currentSearchGesture[_this.centerId] == '')
            {
                _this.searchSearch();
            }
            else if(_this.currentMode == 'SEARCH' && _this.currentSearchGesture[_this.centerId] != '')
            {
                _this.searchGesture(_this.currentSearchGesture[_this.centerId], 'valid');
            }
            
            _this.canSwipe = true;
        });
    }
}

/*
 * Permet de savoir si un déplacement est possible en fonction de l'id de snapshot entré.
 * x et y sont les positions du pointeur.
 * Déplace vers le voisin si possible.
 * Est appelé : dans le fichier pointers > fonction pointersVideoInteractions.
*/
Mosaic.prototype.correctMoveToNeighbour = function(id, x, y)
{
    var _this = this;
    
    if(this.neighboursIds != null && this.neighboursIds.length > 0 && this.canMoveToNeighbour)
    {
        var idx = $.inArray(id, this.neighboursIds);
        //Si l'id du snapshot qu'on vient de quitter fait partie des voisins.
        if(idx > -1)
        {
            //Correspondance indices : position par rapport au snapshot du milieu.
            //0 : gauche.
            //1 : droite.
            //2 : haut.
            //3 : bas.
            
            //On cherche le symétrique de l'id du voisin quitté.
            //Astuce : S'il est pair, cela signifie qu'on doit faire +1, sinon c'est -1.
            //var sym = (idx % 2 == 0) ? (+idx + 1) : (idx - 1);
            
            //S'il est > -1 alors forcément il existe.
            //Si on peut se déplacer vers un voisin, on le fait.
            if(this.neighboursIds[idx] > -1)
            {
                var centerWidth = -this.notifyLeftVideo + $(window).width() / 2, centerHeight = -this.notifyTopVideo + $(window).height() / 2;
                
                //Si l'id du tableau est pair, alors forcément le pointeur doit être plus à droite/plus en bas que le milieu de l'écran pour se déplacer vers le voisin.
                //Sinon c'est l'inverse.
                //(sym et idx on été échangés).
                if(idx == 0 && x > centerWidth || idx == 2 && y > centerHeight || idx == 1 && x < centerWidth || idx == 3 && y < centerHeight)
                {
                    this.moveToNeighbour($('#snapshotDiv-' + this.neighboursIds[idx]));
                }
            }
        }
        else if(id >= this.config.imagesToShow)
        {
            //On otbient le vrai ID du voisin additionnel.
            var additionalNeighbourId = id - this.config.imagesToShow;
            var sym = (additionalNeighbourId % 2 == 0) ? (+additionalNeighbourId + 1) : (additionalNeighbourId - 1);
        }
    }
}

/*
 * Lors d'une vue en plein écran, on se déplace vers le voisin dont l'id a été spécifié dans la fonction appelante.
 * Est appelé : dans les fichiers neighbours > fonction correctMoveToNeighbour, playerControl > fonction playNextVideo et zoomInteractions > zoom.
 */
Mosaic.prototype.moveToNeighbour = function(neighbour)
{
    var _this = this;
    
    //Si on ne peut pas se déplacer vers les voisins, on quitte.
    if((!this.canMoveToNeighbour || neighbour.length <= 0 || this.currentlyMoving) && !this.autoMove)
    {
        return;
    }
    
    this.canMoveToNeighbour = false;
    this.currentlyMoving = true;
    this.removeAdditionalNeighbours();
    
    //On obtient l'ID de destination.
    var tab = neighbour.attr('id').split('-');
    var destinationId = tab[1];
    
    var startId = this.previousZoomedSN.attr('id').replace('snapshotDiv-', '');
    
    //On charge les attributs nécessaires aux calculs.
    var length = _this.config.imagesByLine;
    var MPCurrentTop = $('#mainPanel').position().top, MPCurrentLeft = $('#mainPanel').position().left;
    var divideCoeffTop = Math.floor(destinationId / length) == 0 ? 1 : Math.floor(destinationId / length);
    var divideCoeffLeft = destinationId % length == 0 ? 1 : destinationId % length;
    var neighbourFrameTop = $('#snapshotDiv-' + destinationId).position().top, neighbourFrameLeft = $('#snapshotDiv-' + destinationId).position().left;
    
    _this.previousZoomedSN = $('#snapshotDiv-' + this.centerId);
    
    //On définit pour le déplacement vertical s'il est nécessaire de se déplacer en haut ou en bas.
    if(_this.previousZoomedSN.position().top > neighbourFrameTop)
        MPCurrentTop += Math.abs(neighbourFrameTop - _this.previousZoomedSN.position().top);
    else if(_this.previousZoomedSN.position().top < neighbourFrameTop)
        MPCurrentTop -= Math.abs(neighbourFrameTop - _this.previousZoomedSN.position().top);
    //On définit pour le déplacement horizontal s'il est nécessaire de se déplacer à gauche ou à droite.
    if(_this.previousZoomedSN.position().left > neighbourFrameLeft)
        MPCurrentLeft += Math.abs(neighbourFrameLeft - _this.previousZoomedSN.position().left);
    else if(_this.previousZoomedSN.position().left < neighbourFrameLeft)
        MPCurrentLeft -= Math.abs(neighbourFrameLeft - _this.previousZoomedSN.position().left);
    
    //On passe le snapshot de destination en HD.
    var destinationImg = $('#snapshot-' + destinationId);
    var destinationImgSrc = destinationImg.attr('src');
    destinationImg.attr('src', destinationImgSrc.replace('snapshots-little/', 'snapshots/'));
    
    //On passe l'ancien snapshot en SD.
    var currentImgSrc = $('img', _this.previousZoomedSN).attr('src');
    $('img', _this.previousZoomedSN).attr('src', currentImgSrc.replace('snapshots/', 'snapshots-little/'));

    $('#snapshotDiv-' + destinationId).css('opacity', '1');
    
    //Si le player est prêt.
    if(_this.player && _this.player.widgets[0] && _this.playerIsReady)
    {
        //Si on est en mode timeline on la quitte.
        if(_this.currentMode == 'TIMELINE')
        {
            _this.exitTimeline('move');
        }
        
        //Si le move est automatique (fin de vidéo).
        if(_this.autoMove)
        {
            //On remet à jour la position du curseur de la vidéo.
            _this.timeToGoAt[_this.centerId] = 0;
            _this.autoMove = false;
        }
        //Sinon on revient là où on était la dernière fois que la video a été jouée.
        else
        {
            _this.timeToGoAt[_this.centerId] = Math.floor(_this.player.popcorn.currentTime());
        }
        //On libère le player.
        _this.player.widgets[0].freePlayer();
        _this.playerIsReady = false;
        $('.LdtPlayer').remove();
        $('body').append('<div class="LdtPlayer" id="LdtPlayer"></div>');
    }
    
    //On obtient l'ID du div de coloration du snapshot vers lequel on se déplace afin de le supprimer.
    _this.centerId = destinationId;
    
    //On grise le snapshot qu'on vient de quitter.
    _this.previousZoomedSN.fadeTo(_this.config.zoomTime, '0.4');
    
    //console.log(MPCurrentLeft);
    
    //On se déplace.
    $('#mainPanel').animate(
    {
        top: MPCurrentTop,
        left: MPCurrentLeft
    }, _this.config.timeMovingToNeighbour, function()
    {
        //On passe en mode recherche et on recherche dans la vidéo en fonction de la gesture de recherche enregistrée dans la nouvelle vidéo.
        if(_this.currentSearchGesture[_this.centerId] != '')
        {
            _this.currentMode = 'SEARCH';
            _this.isCurrentlyInASearchByGesture = true;
            _this.removeNotifications();
            _this.searchGesture(_this.currentSearchGesture[_this.centerId], 'valid');
        }
        
        //On fait apparaître le snapshot vers lequel on s'est déplacé.
        $('#snapshotDiv-' + destinationId).fadeTo(_this.config.zoomTime, '1', function()
        {
            //On recharge les voisins.
            _this.previousZoomedSN = $('#snapshotDiv-' + _this.centerId);
            
            _this.notifyTopVideo = MPCurrentTop;
            _this.notifyLeftVideo = MPCurrentLeft;
            _this.neighboursIds.length = 0;
            _this.currentlyMoving = false;
            _this.listenToNeighbours();
            
            //On charge le player.
            _this.loadPlayer((destinationImg.position().top + MPCurrentTop + _this.MPTop_margin), (destinationImg.position().left + MPCurrentLeft), destinationImg.width(), destinationImg.height(), MPCurrentTop, MPCurrentLeft, _this.timeToGoAt[_this.centerId]);
        });
    });
}

/*
 * Donne éventuellement un snapshot d'après les coordonnées du pointeur sur l'écran.
 * Renvoie null sinon.
 * Est appelé : dans les fichiers pointers > fonction pointersMosaicInteractions et pointersVideoInteractions et zoomInteractions > zoom.
*/
Mosaic.prototype.pointerPositionToSN = function(x, y, isMainPointer)
{
    if(this.helpDisplayed)
    {
        return;
    }
    
    x += $('#mainPointer').width() / 2;
    y += $('#mainPointer').height() / 2;
    
    //Taille de la marge des snapshots.
    var m = parseInt($('.snapshotDivs').css('margin'));
    
    //Dimensions d'un snapshot de la mosaïque.
    var W = $('.snapshotDivs').width() + m * 2, H = $('.snapshotDivs').height() + m * 2;
    
    //Position supposée du snapshot dans la mosaïque.
    //Au départ on ne sélectionne rien.
    var i = -1, j = -1;
    
    //Espace de centrage vertical de la mosaïque.
    var top_margin = parseInt(this.MPTop_margin);
    //Dimensions de la mosaïque en nombre de snapshots.
    var mosW = this.config.imagesByLine, mosH = this.config.imagesToShow / mosW;
    
    //Si le pointeur se trouve au niveau de la mosaïque.
    if(x < W * mosW && y >= top_margin && y < H * mosH + top_margin)
    {
        //Si le pointeur est sur une des bordures.
        var xb = x % W;
        var yb = y - top_margin;
        yb %= H;
        
        if(xb < m || xb > W - m || yb < m || yb > H - m)
        {
            //On renvoie null.
            return null;
        }
        //Sinon il est forcément sur un des snapshots.
        else
        {
            i = Math.floor(x / W);
            j = Math.floor((y - top_margin) / H);
        }
        
        //On passe des coordonnées 2D en 1D.
        var snapshot = $('#snapshotDiv-' + (j * mosW + i));
        
        //Si le snapshot a été filtré, on renvoie null si on se trouve dans la mosaïque.
        if(this.isMosaicFiltered && (this.currentMode == "MOSAIC" || this.currentMode == "FILTER") && snapshot.css('opacity') == 0)
        {
            return null;
        }
        
        //On renvoie le snapshot.
        return snapshot;
    }
    
    //Si on est arrivé là, c'est que le pointeur n'est pas dans la mosaïque.
    return null;
}

/*
 * Donne éventuellement un voisin additionnel d'après les coordonnées du pointeur sur l'écran.
 * Renvoie null sinon.
 * Est appelé : dans le fichier pointers > fonction pointersVideoInteractions.
*/
Mosaic.prototype.pointerPositionToAN = function(x, y, isMainPointer)
{
    //Si l'aide est affichée, on part.
    if(this.helpDisplayed)
    {
        return;
    }
    
    x += $('#mainPointer').width() / 2;
    y += $('#mainPointer').height() / 2;
    
    //Pour tous les voisins.
    for(var i = 0 ; i < this.neighboursIds.length ; i++)
    {
        //Si on est sur un bord.
        if(this.neighboursIds[i] == -1)
        {
            //On récupère un voisin au delà du bord.
            var neighbour = $('#borderNeighbour-' + i);
            
            if(neighbour == null || neighbour == undefined || neighbour.position() == null)
            {
                return;
            }
            
            //Si le pointeur est sur le voisin, on le retourne.
            if(x > neighbour.position().left && x < +neighbour.position().left + neighbour.width() && y > neighbour.position().top && y < +neighbour.position().top + neighbour.height())
            {
                return neighbour;
            }
        }
    }
    return null;
}

/*
 * Vérifie l'intéraction dézoom.
 * Est appelé : dans le fichier pointers > fonction pointersVideoInteractions.
*/
Mosaic.prototype.checkForDezoom = function()
{
    //Si on se trouve en mode VIDEO ou SEARCH.
    if(this.currentMode == "VIDEO" || this.currentMode == "SEARCH")
    {
        //Si les deux pointeurs sont allés puis ont quitté une bordure.
        if(this.mainPointerExitBorder && this.secondPointerExitBorder)
        {
            //Si les voisins existent.
            if(this.neighboursIds != null && this.neighboursIds.length > 0)
            {
                var localIdMainPointerNeighbour = $.inArray(this.mainPointerNeighbourSelectedId, this.neighboursIds);
                var localIdSecondPointerNeighbour = $.inArray(this.secondPointerNeighbourSelectedId, this.neighboursIds);
                
                //Cas où on a des voisins additionnels.
                if(this.mainPointerNeighbourSelectedId >= this.config.imagesToShow)
                {
                    localIdMainPointerNeighbour = this.mainPointerNeighbourSelectedId - this.config.imagesToShow;
                }
                if(this.secondPointerNeighbourSelectedId >= this.config.imagesToShow)
                {
                    localIdSecondPointerNeighbour = this.secondPointerNeighbourSelectedId - this.config.imagesToShow;
                }
                
                if(localIdMainPointerNeighbour > -1 && localIdMainPointerNeighbour < 4 && localIdSecondPointerNeighbour > -1 && localIdSecondPointerNeighbour < 4)
                {
                    var sym = (localIdMainPointerNeighbour % 2 == 0) ? (+localIdMainPointerNeighbour + 1) : (localIdMainPointerNeighbour - 1);
                    
                    //Si les voisins sélectionnés sont opposés.
                    if(sym == localIdSecondPointerNeighbour)
                    {
                        //Positions des pointeurs.
                        var xMain = $('#mainPointer').position().left - $('#mainPointer').width() / 2;
                        var yMain = $('#mainPointer').position().top - $('#mainPointer').height() / 2;
                        var xSecond = $('#secondPointer').position().left - $('#secondPointer').width() / 2;
                        var ySecond = $('#secondPointer').position().top - $('#secondPointer').height() / 2;
                        
                        //Snapshot central.
                        var centerSN = $('#snapshotDiv-' + this.centerId);
                        
                        //Quarts du snapshot central.
                        var center1QuartWidth = centerSN.position().left + this.notifyLeftVideo + centerSN.width() / 4;
                        var center3QuartsWidth = centerSN.position().left + this.notifyLeftVideo + centerSN.width() * 3 / 4;
                        var center1QuartHeight = centerSN.position().top + this.notifyTopVideo + centerSN.height() / 4;
                        var center3QuartsHeight = centerSN.position().top + this.notifyTopVideo + centerSN.height() * 3 / 4;
                        
                        //Pour activer le dézoom, il suffit que les pointeurs soient dans un rectangle délimité au centre de l'écran.
                        //Si les voisins sélectionnés sont de disposition horizontale.
                        if(sym == 0 || sym == 1)
                        {
                            if(xMain > center1QuartWidth && xSecond > center1QuartWidth && xMain < center3QuartsWidth && xSecond < center3QuartsWidth)
                            {
                                this.unzoom();
                            }
                        }
                        //Sinon s'ils sont de disposition verticale.
                        else if(sym == 2 || sym == 3)
                        {
                            if(yMain > center1QuartHeight && ySecond > center1QuartHeight && yMain < center3QuartsHeight && ySecond < center3QuartsHeight)
                            {
                                this.unzoom();
                            }
                        }
                    }
                }
            }
        }
    }
}