/* 
 * KoremSpider.js
 * 
 * Created: 20-Oct-2008
 * 
 * KOREM 2008.
 */

        var deltalngPerPx = 0;
        var deltalatPerPx = 0;
        var lineColor = new Array("#376f03", "#df3f3f", "#cc6500", "#2763a2");
        var backPoints;
        var defaultDistance = 50;
        var point;
        var eventMove;
        var iteration = 0;
        var nbIteration = 8;
        var nbIterationLine = 4;
        var points;
        var infoOpened = false;
        var shrinking = false;
        var listClicked = false;
        var indexPoint = -1;
        var timeOut = 25;
        var pointsPerLevel = 5;


        function splitPoints(currentPoint, middleX, middleY){
            var pointsTakenX = new Array();
            var pointsTakenY = new Array();
            var pointsToMove = new Array();
            var sizeTaken = 0;
            var size = currentPoint.group.length;
            var cpt = 0;
            var distance = 0;
            
            pointsTakenX[0] = middleX;
            pointsTakenY[0] = middleY;
            for(var i = 0; i < size; i++){
                sizeTaken = pointsTakenX.length;
                for(var k = 0; k < sizeTaken; k++){
                    if(currentPoint.group[i].getLatLng().lng() == pointsTakenX[k] && currentPoint.group[i].getLatLng().lat() == pointsTakenY[k]){
                        pointsToMove[cpt] = currentPoint.group[i];
                        pointsToMove[cpt].groupIndex = i;
                        cpt++;
                    }
                }
                pointsTakenX[i+1] = currentPoint.group[i].getLatLng().lng();
                pointsTakenY[i+1] = currentPoint.group[i].getLatLng().lat();
                currentPoint.group[i].offsetX = currentPoint.group[i].getLatLng().lng();
                currentPoint.group[i].offsetY = currentPoint.group[i].getLatLng().lat();
                
            }
            sizeTaken = pointsTakenX.length;
            if(pointsToMove.length > 0){
                var diffAngle = 360 / pointsToMove.length;
                for(var i = 0; i < pointsToMove.length; i++){
                    var angle = diffAngle * i;
                    distance = 20;
                    var invalidPosition = true;
                    var newX = 0;
                    var newY = 0;
                    while(invalidPosition){
                        var deltaX = getDeltaX(angle, distance);
                        var deltaY = getDeltaY(angle, distance);
                        var pointMoved = false;
                        newX = deltaX * deltalngPerPx + pointsToMove[i].getLatLng().lng();
                        newY = deltaY * deltalatPerPx + pointsToMove[i].getLatLng().lat();
                        for(var k = 0; k < sizeTaken; k++){
                            invalidPosition = false;
                            if(newX == pointsTakenX[k] && newY == pointsTakenY[k]){
                                invalidPosition = true;
                            }
                            if(pointsToMove[i].getLatLng().lng() == pointsTakenX[k] && pointsToMove[i].getLatLng().lat() == pointsTakenY[k] && !pointMoved){
                                pointsTakenX[k] = newX;
                                pointsTakenY[k] = newY;
                                pointMoved = true;
                            }
                        }
                        distance++;
                    }
                    currentPoint.group[pointsToMove[i].groupIndex].offsetX = newX;
                    currentPoint.group[pointsToMove[i].groupIndex].offsetY = newY;
                }
            }
            return currentPoint;
        }
        
        function initGroupDispersion(currentPoint){
            var size = currentPoint.group.length;
            var middleX = 0;
            var middleY = 0;
            var cpt = 0;
            var distance = 0;
            var deltaDistance = 0;
            var pointTest;
            var fallback = false;
            for(; cpt < size; cpt++){
                middleX = middleX + currentPoint.group[cpt].getLatLng().lng();
                middleY = middleY + currentPoint.group[cpt].getLatLng().lat();
            }
            middleX = middleX / cpt;
            middleY = middleY / cpt;

            currentPoint = splitPoints(currentPoint, middleX, middleY);
            cpt = 0;
            var result = pointsPerLevel * Math.pow(2, 0);
            for(var i = 0; cpt < size; i++){
                distance = defaultDistance * (i+1);
                for(; cpt < result && cpt < size; cpt++){
                    point = currentPoint.group[cpt];
                    var deltaX = point.offsetX - middleX;
                    var deltaY = point.offsetY - middleY;
                    deltaDistance = Math.sqrt(Math.pow(deltaX/deltalngPerPx, 2) + Math.pow(deltaY/deltalatPerPx, 2));
       
                    point.newX = distance / deltaDistance * deltaX;
                    point.newY = distance / deltaDistance * deltaY;
                    currentPoint.group[cpt] = point;
                }
                result = pointsPerLevel * Math.pow(2, i+1);
            }
            
            //We check if the points are correctly dispersed if not we fall back on the circle algorythm
            
            for(var i = 0; i < size; i++){
                pointTest = currentPoint.group[i];
                for(var j = 0; j < size; j++){
                    if(pointTest.indexPoint != currentPoint.group[j].indexPoint && isTouching(pointTest, currentPoint.group[j], true)){
                        fallback = true;
                    }
                }
            }
            if(fallback){
                currentPoint = circleSpider(currentPoint);
            }
            return currentPoint;
        }
        
        function circleSpider(currentPoint){
            var size = currentPoint.group.length;
            var result = pointsPerLevel * Math.pow(2, 0);
            var cpt = 0;
            var offset = 0;
            var distance = 0;
            for(var i = 0; cpt < size; i++){
                var diffAngle = result - cpt;
                diffAngle = 360 / diffAngle;
                distance = defaultDistance * (i+1);
                var j=0;
                for(; cpt < result && cpt < size; cpt++){
                    point = currentPoint.group[cpt];
                    var angle = (diffAngle * j) + offset;
                    var deltaX = getDeltaX(angle, distance);
                    var deltaY = getDeltaY(angle, distance);
                    point.newX = deltaX * deltalngPerPx; - (point.getLatLng().lng() - currentPoint.getLatLng().lng());
                    point.newY = deltaY * deltalatPerPx; - (point.getLatLng().lat() - currentPoint.getLatLng().lat());
                    j++;
                    currentPoint.group[cpt] = point;
                }
                if(i > 0){
                    offset = diffAngle / 4;
                }else{
                    offset = diffAngle / 2;
                }
                result = pointsPerLevel * Math.pow(2, i+1);
            }
            return currentPoint;
        }

        function getDeltaX(angle, distance) {
            if(angle == 0) {
                return distance;
            }
            if(angle % 180 == 0) {
                return -distance;
            }
            if(angle % 90 == 0) {
                return 0;
            }
            var quadrant = Math.floor(angle / 90);
            var deltaX = 0.0;
            if(quadrant == 1 || quadrant == 3) {
                deltaX = Math.sin((angle % 90) * Math.PI/180) * distance;
            } else {
                deltaX = Math.cos((angle % 90) * Math.PI/180) * distance;
            }
            if(quadrant == 1 || quadrant == 2) {
                deltaX = -deltaX;
            }
            return deltaX;
        }

        function getDeltaY(angle, distance) {
            if(angle == 0 || angle == 180){
                return 0;
            }
            if(angle % 90 == 0 && angle % 180 != 0 && angle % 270 != 0) {
                return distance;
            }
            if(angle % 180 != 0 && angle % 270 == 0) {
                return -distance;
            }
            var quadrant = Math.floor(angle / 90);
            var deltaY = 0.0;
            if(quadrant == 1 || quadrant == 3) {
                deltaY = Math.cos((angle % 90) * Math.PI/180) * distance;
            } else {
                deltaY = Math.sin((angle % 90) * Math.PI/180) * distance;
            }
            if(quadrant == 2 || quadrant == 3) {
                deltaY = -deltaY;
            }
            return deltaY;
        }

        function markerClick(clickPoint){
            clickPoint = initGroupDispersion(clickPoint);
            var polygon;
            var lng = 0;
            var lat = 0;
            var height = clickPoint.getIcon().iconSize.height;
            var width = clickPoint.getIcon().iconSize.width;
            var minLat = clickPoint.getLatLng().lat();
            var minLng = clickPoint.getLatLng().lng() - width * deltalngPerPx / 2;
            var maxLat = clickPoint.getLatLng().lat();
            var maxLng = clickPoint.getLatLng().lng();
            var currentPoint;
            for(var i = 0; i < clickPoint.group.length; i++){
                currentPoint = clickPoint.group[i];
                currentPoint.latLngArr = new Array();
                var j = 0;
                for(; j <= nbIteration; j++){
                    lng = currentPoint.getLatLng().lng() + (currentPoint.newX * j / nbIteration);
                    lat = currentPoint.getLatLng().lat() + (currentPoint.newY * j / nbIteration);
                    currentPoint.latLngArr[j] = new GLatLng(lat, lng);
                }
                currentPoint = createMovingLine(currentPoint, currentPoint.latLngArr[j-1]);
                height = currentPoint.getIcon().iconSize.height;
                width = currentPoint.getIcon().iconSize.width;
                if(lng - (width * deltalngPerPx / 2) < minLng){
                    minLng = lng - (width * deltalngPerPx / 2);
                }else if(lng + (width * deltalngPerPx / 2) > maxLng){
                    maxLng = lng + (width * deltalngPerPx / 2);
                }
                if(lat < minLat){
                    minLat = lat;
                }else if((lat + height * deltalatPerPx) > maxLat){
                    maxLat = (lat + height * deltalatPerPx);
                }
                currentPoint.hasMoved = true;
                clickPoint.group[i] = currentPoint;
            }
            point = clickPoint;
            point.expanding = true;
            
            polygon = new GPolygon([
                new GLatLng(minLat, minLng),
                new GLatLng(minLat, maxLng),
                new GLatLng(maxLat, maxLng),
                new GLatLng(maxLat, minLng),
                new GLatLng(minLat, minLng)
            ], null, 0, 0, null, 0);
            map.addOverlay(polygon);
            eventMove = GEvent.addListener(map, 'mousemove', function(latlng){polygonOut(polygon, latlng);});
            backPoints = new Array();
            var cptBack = 0;

            for(var cpt = points.length-1; cpt >= 0; cpt--){
                currentPoint = points[cpt];
                if(!currentPoint.hasMoved){
                    currentPoint.picChanged = true;
                    currentPoint.indexPoint = cpt;
                    points[cpt] = currentPoint;
                    
                    var newPoint = createPoint(currentPoint.getLatLng().lat(), currentPoint.getLatLng().lng(), "", currentPoint.labelText_, false, false, true);
                    newPoint.indexPoint = cpt;
                    backPoints[cptBack] = newPoint;
                    map.removeOverlay(currentPoint);
                    map.addOverlay(newPoint);
                    GEvent.addListener(newPoint, "click", function(){
                        for(var i = points.length-1; i >= 0; i--){
                            map.closeInfoWindow();
                        }
                        indexPoint = this.indexPoint;
                    });
                    cptBack++;
                }
            }
            setTimeout("expand()", 1);
        }
        
        function isTouching(currentPoint, pointTesting, useNew){
            var offSetSize = currentPoint.labelOffset_;
            var currentX;
            var currentY;
            var testX;
            var testY;
            if(offSetSize.width == 0 && offSetSize.height == 0){
                offSetSize = new GSize(-2, -37);
            }
            if(useNew){
                currentX = currentPoint.newX + offSetSize.width * deltalngPerPx;
                currentY = currentPoint.newY + offSetSize.height * deltalatPerPx;                
            }else{
                currentX = currentPoint.getLatLng().lng() + offSetSize.width * deltalngPerPx;
                currentY = currentPoint.getLatLng().lat() + offSetSize.height * deltalatPerPx;
            }
            
            offSetSize = pointTesting.labelOffset_;
            if(offSetSize.width == 0 && offSetSize.height == 0){
                offSetSize = new GSize(-2, -37);
            }
            if(useNew){
                testX = pointTesting.newX + offSetSize.width * deltalngPerPx;
                testY = pointTesting.newY + offSetSize.height * deltalatPerPx;                
            }else{
                testX = pointTesting.getLatLng().lng() + offSetSize.width * deltalngPerPx;
                testY = pointTesting.getLatLng().lat() + offSetSize.height * deltalatPerPx;
            }
            
            if(currentPoint.getIcon().iconSize.width >= pointTesting.getIcon().iconSize.width){
                var maxX = currentX + (currentPoint.labelSize_.width * deltalngPerPx);
                var minX = currentX - (currentPoint.labelSize_.width * deltalngPerPx);
                var maxY = currentY + (currentPoint.labelSize_.height * deltalatPerPx);
                var minY = currentY - (currentPoint.labelSize_.height * deltalatPerPx);
                if(testX > minX && testX < maxX){
                    if(testY > minY && testY < maxY){
                        return true;
                    }
                }
            }else{
                maxX = currentX + (pointTesting.labelSize_.width * deltalngPerPx);
                minX = currentX - (pointTesting.labelSize_.width * deltalngPerPx);
                maxY = currentY + (pointTesting.labelSize_.height * deltalatPerPx);
                minY = currentY - (pointTesting.labelSize_.height * deltalatPerPx);
                if(testX > minX && testX < maxX){
                    if(testY > minY && testY < maxY){
                        return true;
                    }
                }                
            }
            return false;
        }

        function polygonOut(poly, latlng){
            var maxLat = poly.getBounds().getNorthEast().lat();
            var maxLng = poly.getBounds().getNorthEast().lng();
            var minLat = poly.getBounds().getSouthWest().lat();
            var minLng = poly.getBounds().getSouthWest().lng();
            if(latlng.lat() < minLat || latlng.lat() > maxLat || latlng.lng() < minLng || latlng.lng() > maxLng){
                setTimeout("eraseLine()", 1);
                map.removeOverlay(poly);
                GEvent.removeListener(eventMove);
            }
        }

        function shrink(){
            var currentPoint;
            if(iteration >= nbIteration){
                iteration = 0;
                for(var cpt = points.length - 1; cpt >= 0; cpt--){
                    currentPoint = points[cpt];
                    if(currentPoint.picChanged){
                        currentPoint.picChanged = false;
                        map.addOverlay(currentPoint);
                    }
                }
                for(var cptBack in backPoints){
                    map.removeOverlay(backPoints[cptBack]);
                }
                backPoints = null;
                shrinking = false;
                if(indexPoint >= 0){
                    point = points[indexPoint];
                    GEvent.trigger(point, "click");
                    indexPoint = -1;
                }
                return;
            }
            for(var i = 0; i < point.group.length; i++){
                currentPoint = point.group[i];
                currentPoint.setLatLng(currentPoint.latLngArr[nbIteration-(iteration + 1)]);
                if((iteration + 1) >= nbIteration){
                    currentPoint.hasMoved = false;
                }
            }
            iteration++;
            setTimeout("shrink()", timeOut);
        }

        function eraseLine(){
            if(infoOpened){
                return
            }
            if(!point.expanding){
                if(iteration >= nbIterationLine){
                    iteration = 0;
                    setTimeout("shrink()", 1);
                    return;
                }
                shrinking = true;
                var currentPoint;
                for(var i = 0; i < point.group.length; i++){
                    currentPoint = point.group[i];
                    currentPoint.poly.setStrokeStyle({'opacity': 1 - ((iteration+1) / nbIterationLine)});
                    if((iteration + 1) >= nbIterationLine){
                        map.removeOverlay(currentPoint.poly);
                    }
                }
                iteration++;
            }
            setTimeout("eraseLine()", timeOut);
        }

        function expand(){
            if(iteration >= nbIteration){
                iteration = 0;
                setTimeout("drawLine()", 1);
                return;
            }
            var currentPoint;
            for(var i = 0; i < point.group.length; i++){
                currentPoint = point.group[i];
                currentPoint.setLatLng(currentPoint.latLngArr[iteration + 1]);
            }
            iteration++;
            setTimeout("expand()", timeOut);
        }

        function drawLine(){
            if(iteration >= nbIterationLine){
                iteration = 0;
                point.expanding = false;
                if (listClicked){
                    listClicked = false;
                    GEvent.trigger(point, "click");
                }
                return;
            }
            var currentPoint;
            for(var i = 0; i < point.group.length; i++){
                currentPoint = point.group[i];
                currentPoint.poly.setStrokeStyle({'opacity': (iteration+1) / nbIterationLine});
            }
            iteration++;
            setTimeout("drawLine()", timeOut);
        }

        function createGroup(){
            for(var cpt = 0; cpt < points.length; cpt++){
                var j = 0;
                var currentPoint = points[cpt];
                currentPoint.group = new Array();
                for(var i = 0; i < points.length; i++){
                    var pointTesting = points[i];
                    if(isTouching(currentPoint, pointTesting, false)){
                        currentPoint.group[j] = pointTesting;
                        j++;
                    }
                }
                points[cpt] = currentPoint;
            }
        }

        function zIndexProcesser(marker, b){
            if(!marker.zIndexTmp){
                var lat = marker.getLatLng().lat();
                var lng = marker.getLatLng().lng();
                marker.zIndexTmp = GOverlay.getZIndex(lat + (lng/1000000));
                return GOverlay.getZIndex(lat + (lng/1000000));
            }else{
                return marker.zIndexTmp
            }
        }
        
        function zIndexProcesserLow(marker, b){
            var lat = marker.getLatLng().lat();
            var lng = marker.getLatLng().lng();
            return GOverlay.getZIndex(lat + (lng/1000000)) - 1000000000;
        }

        function infoClosed(){
            var sameGroup = false;
            infoOpened = false;
            if(point != null && point.group != null){
              for(var i = 0; i < points.length; i++){
                  var infoPoint1 = points[i];
                  if(infoPoint1.infoOpened){
                      for(var j = 0; j < infoPoint1.group.length; j++){
                          var infoPoint2 = infoPoint1.group[j];
                          if(infoPoint2.infoOpened && infoPoint2.indexPoint != infoPoint1.indexPoint){
                              for(var k = 0; k < infoPoint2.group.length; k++){
                                  if(infoPoint1.indexPoint == infoPoint2.group[k].indexPoint){
                                      infoPoint1.infoOpened = false;
                                      sameGroup = true;
                                  }
                              }
                          }
                      }
                  }
              }
              if(!sameGroup){
                  for(var i = 0; i < points.length; i++){
                      points[i].infoOpened = false;
                  }
                  if(point.group.length > 1 && point.hasMoved && !point.expanding){
                      setTimeout("eraseLine()", timeOut);
                      GEvent.removeListener(eventMove);
                  }
              }
            }else{
              for(var i = 0; i < points.length; i++){
                  points[i].infoOpened = false;
              }
            }
        }
        
        function initDeltas(){
            var bounds = map.getBounds();
            var southWest = bounds.getSouthWest();
            var northEast = bounds.getNorthEast();
            var deltalng = northEast.lng() - southWest.lng();
            var deltalat = northEast.lat() - southWest.lat();

            var width = map.getSize().width; 
            var height = map.getSize().height; 

            deltalngPerPx = deltalng / width;
            deltalatPerPx = deltalat / height;
            
        }

        function initializeGroups(){
            for(var cpt = 0; cpt < points.length; cpt++){
                points[cpt].hasMoved = false;
                points[cpt].picChanged = false;
                points[cpt].indexPoint = cpt;
            }
        }

        function createMovingLine(currentPoint, latLngMoved){
            var polyline = new GPolyline([currentPoint.getLatLng(), latLngMoved], lineColor[color-1], 2, 0);
            currentPoint.poly = polyline;
            map.addOverlay(currentPoint.poly);
            return currentPoint;
        }


