var EMAPSITE_SERVER = "http://ws.emapsite.com";

function findRoutesByLocation(longitude, latitude, distance) {
    // Default distance if non specified.
    if (arguments.length < 3) {
        distance = 100;
    }

    // Build URL to request nearest rides JSON feed from.
    var url = EMAPSITE_SERVER+"/" + emapCode + "/findRoutesByLocation?callback=?";
    url += "&latitude="+latitude+"&longitude="+longitude;
    url += "&distance="+distance; // Distance in kilometers.

    // Send request for JSON.
    jQuery.getJSON(url, showRoutes);
}
function findRoutesByName(routeName) {
    // Build URL to request nearest rides JSON feed from.
    var url = EMAPSITE_SERVER+"/" + emapCode + "/findRoutesByName?callback=?&name="+routeName;

    // Send request for JSON.
    jQuery.getJSON(url, showRoutes);
}
function clearMapControl() {
    // Clear/hide previous searches and layers.
    ridesShapeLayer.DeleteAllShapes();
    waypointShapeLayer.DeleteAllShapes();
    searchResultsShapeLayer.DeleteAllShapes();
    $('#searchResults').css("display", "none");
    $('.pnlSearch').css("display", "none");

    // reset route specific display
    if(searchType == "rides")
        $('.mapHeader h1').html('Routes');
    else
        $('.mapHeader h1').html('Businesses');
    $('.printIcon').css("display", "none");
    $('.pnlRoute').css("display", "none");
}
function showRoutes(data) {
    if (data.numResults == 0) {
        alert("No route found. This route may have been removed for administration purposes.");
    } else if (data.numResults == 1) {
        // Clear the map control and automatically go to this route.
        clearMapControl();
        changeRoute(data.rides[0].GUID);
    } else {
        // Clear the map control and display list of rides.
        clearMapControl();

        // Cycle through results.
        var ol = document.createElement('ol'); // List element for rides result list.
        var routeIds = new Array();
        jQuery.each(data.rides, function(i,ride) {
            if (ride.geometries) {
                // Create VEShapes for each ride returned that has a geometry.
                var veShapes = rideToVEShapes(ride, {'showViewLink': true});

                // Cycle through each shape created and add the shape to the shape layer.
                for (var n = 0; n < veShapes.length; n++) {
                    ridesShapeLayer.AddShape(veShapes[n]);
                }
            }

            // Populate OL element with rides.
            var li = document.createElement('li');
            var a = document.createElement('a');
            a.setAttribute('href', "?route=" + ride.GUID);
            a.setAttribute('onclick', "changeRoute('"+ride.GUID+"')");
            var html = ride.name;
            if (ride.distance) html += " ("+ride.distance.toFixed(1)+"km)";
            a.innerHTML = ride.name;
            li.appendChild(a);
            ol.appendChild(li);
            if (ride.geometries) li.className = "shownOnMap";

            // Add id to array
            routeIds.push(ride.GUID);
        });

        if (data.numResults > 3)
            alert("Multiple routes found, showing top 3 routes\n\nSee list below map for more routes.");

        // Autoscale map to show first three rides.
        map.SetMapView(ridesShapeLayer.GetBoundingRectangle());
        ridesShapeLayer.Show();

        // Display list of rides.
        $('.pnlSearch').find('div:first').find('div:first').empty().append(ol);
        $('.pnlRoute').css("display", "none");
        $('.pnlSearch').css("display", "block");

        // Refresh map adverts.
        getMapAdverts();

        // Pass route ids to bit10
        routeSearchResults(routeIds);
    }
}

function displayRoute(GUID) {
    // Build URL to request nearest rides JSON feed from.
    var url = EMAPSITE_SERVER+"/" + emapCode + "/getRoute?callback=?&GUID="+GUID;

    // Send request for JSON.
    jQuery.getJSON(url, showRoute);
}
function showRoute(data) {

    if (data.numResults == 0) {
        alert("No ride found.");
    } else {
        // Clear the map control.
        ridesShapeLayer.DeleteAllShapes();

        // Convert geometries to VEShape instances.
        var rideShapes = rideToVEShapes(data.ride);

        // Cycle through each shape, autoscale map to this one ride.
        var allCoords = new Array();
        for (var n = 0; n < rideShapes.length; n++) {
            ridesShapeLayer.AddShape(rideShapes[n]);
            allCoords = allCoords.concat(rideShapes[n].GetPoints());
        }
        // Autoscale map.
        map.SetMapView(allCoords);

        // Get waypoints.
        getWaypoints(data.ride.GUID);
    }
}
function rideToVEShapes(ride, options) {
    if (arguments.length < 2) { options = {};}

    var veShapes = new Array();
    // Loop through each ride geometry...
    var hasInfoBox = false;
    for (var n = 0; n < ride.geometries.length; n++) {
        // Each ride geometry will be expanded into VELatLong instances
        // and stored in this array.
        var veCoords = new Array();

        // Get the geometry precision and shrunk coord string.
        var geometryParts = ride.geometries[n].split(":");
        var precision = parseInt(geometryParts[0]) * -1;
        var shrunkCoords = geometryParts[1];

        // Split the shrunk coords into pairs and loop through them.
        var shrunkCoordPairs = shrunkCoords.split(";");
        var prevLon = 0; var prevLat = 0; // For storing coords between iterations.
        for (var c = 0; c < shrunkCoordPairs.length; c++) {
            // Coordinate diff.
            var shrunkCoord = shrunkCoordPairs[c].split(",");
            var diffLon = parseInt(shrunkCoord[0]);
            var diffLat = parseInt(shrunkCoord[1]);

            // Expanded coordinates.
            prevLon = diffLon + prevLon;
            prevLat = diffLat + prevLat;

            // Lat/lon notation.
            var lon = prevLon * Math.pow(10, precision);
            var lat = prevLat * Math.pow(10, precision);

            // Add coordinates to the array.
            veCoords.push(new VELatLong(lat, lon));
        }

        // Create a VEShape from the array of coordinates.
        var shape = new VEShape( VEShapeType.Polyline, veCoords);
        if (n > 0) shape.HideIcon();

        // Set line colour.
        if (ride.colour != undefined && ride.colour != "") {
            // Custom colour.
            var rgb = hexToRGB(ride.colour);
            shape.SetLineColor(new VEColor( rgb[0], rgb[1], rgb[2], 0.5 ));
        } else {
            // Default colour.
            shape.SetLineColor(new VEColor(191, 0, 255, 0.5));
        }
        // Line width.
        shape.SetLineWidth(4);
        shape.HideIcon();

        // Custom properties.
        shape.X_rideId = ride.id;
        shape.X_GUID = ride.GUID;

        // Add to shapes array.
        veShapes.push(shape);
    }
    // Choose where to put pushpin
    if (options.showViewLink) {
        // Get the mid-line of this route.
        var midIdx = Math.ceil(veShapes.length / 2) -1;
        var midShape = veShapes[midIdx];

        // Add infobox details
        midShape.SetTitle(ride.name);
        midShape.SetDescription('<a href="#" onclick="changeRoute(\''+ride.GUID+'\')">View this ride</a>');
        midShape.SetCustomIcon('<div class=\"pin\"><img src=\"/images/emagin/pin_blue.gif\" /><div class=\"pinText\">&nbsp;</div></div>');
        midShape.ShowIcon();

        // Set the icon anchor to the midpoint of the line.
        var points = midShape.GetPoints();
        midShape.SetIconAnchor(points[Math.ceil(points.length / 2) - 1]);

        // Re-insert this shape into the array.
        veShapes[midIdx] = midShape;
    }
    return veShapes;
}

function updateWaypoints(data) {
    // Clear current waypoint layer
    waypointShapeLayer.DeleteAllShapes();

    // bulk add shapes - far higher performance
    var shapes = new Array();
    
    // Cycle through waypoints.
    jQuery.each(data.waypoints, function(i,waypoint) {
        var pushpin = createWaypointPushpin(waypoint);
        shapes.push(pushpin);
    });

    // add shapes to map
    waypointShapeLayer.AddShape(shapes);
    
    waypointShapeLayer.Show();
}
function createWaypointPushpin(waypoint) {
    // Create VELatLong instance for this advert location.
    var location = new VELatLong(waypoint.Latitude, waypoint.Longitude);

    // Create VEShape instance for the advert.
    var pin = new VEShape(VEShapeType.Pushpin, location);

    // Set waypoint title.
    pin.SetTitle(waypoint.Title);
    pin.SetDescription(waypoint.Description);

    // Set the icon to use for this advert.
    if (waypoint.Logo != "") {
        pin.SetCustomIcon(waypoint.Logo);
    }

    return pin;
}
function waypointClusteringCallback(clusters) {
    // This function is called when a group of icons are clustered.
    for (var i = 0; i < clusters.length; ++i) {
        // Customise the icon and mouse-over infobox for each cluster.
        var cluster = clusters[i];
        var clusterShape = cluster.GetClusterShape();
        
        clusterShape.SetTitle("Multiple waypoints at location");
        clusterShape.SetDescription("Please zoom in to see the waypoints.");
        clusterShape.SetCustomIcon('<div class=\"pin\"><img src=\"/images/emagin/pin_multi_orange.gif\" /><div class=\"pinText\">&nbsp;</div></div>');
    }
}

function hexToRGB(h) {
    h = (h.charAt(0) == "#") ? h.substring(1,7) : h; // Remove any preceeding # character.
    var r = parseInt(h.substring(0,2),16);
    var g = parseInt(h.substring(2,4),16);
    var b = parseInt(h.substring(4,6),16);
    return new Array(r,g,b);
}

