﻿$(document).ready(function() {
    var MAX_DISTANCE = 200; 	// 200 km radius
    var MAX_SECONDARY_RESULTS = 5; 	// top[x] secondary results

    var $j = jQuery.noConflict();
    var geocoder = new GClientGeocoder();
    var distances = new Array();

    var tableHeaderHtml = "<h3>Locations</h3>" +
			"<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">" +
			"<tr><th>Your two men and a truck location</th><th></th><th>Next steps</th></tr>";

    // Init Function
    function initjQuery() {

        $j("#submit").click(function() {
            postalCodeLookup();
        }); // end click handler

        $j("#tester").click(function() { getLatLng('results', 0); });

        $j("#postal_code").bind('keypress', function(e) {
            var key = (e.keyCode ? e.keyCode : e.which);

            if (key == 13) { // If Enter key is pressed
                postalCodeLookup();
            }
        });
    }

    // Validates the postal code input
    function validatePostalCode(val) {
        var regex = /^([A-Z][0-9][A-Z]) ([0-9][A-Z][0-9])$/;

        return regex.test(val);
    }

    // Loops through the addresses array, gets and prints out the coordinates (using the google API) in the specified div
    function getLatLng(div, i) {
        if (addresses.length == i) return;
        geocoder.getLatLng(addresses[i], function(response) {
            if (response) {
                var coords = new GLatLng(response.lat(), response.lng());
                var html = $j("#" + div).html();

                html += "<br/>&quot;" + coords.lat() + "," + coords.lng() + "&quot;,";

                $j("#" + div).html(html);
                getLatLng(div, i + 1);
            }
        });
    }

    function postalCodeLookup() {
        var postal_code = $j("#postal_code").attr('value');
        postal_code = postal_code.toUpperCase();

        // Validate the input
        if (!validatePostalCode(postal_code)) {
            alert("Please enter a valid postal code.");
            return false;
        }
        // Put a loading icon
        $j("#results").html("<div style='padding-top: 15px;text-align:center;'><img src='/common/images/ajax-loader.gif' /></div>");

        // First get the source coordinates
        geocoder.getLatLng(postal_code + ", Canada", function(response) {
            if (!response) {
                $j("#results").html(""); // Clear the loading image
                alert("Please enter a valid postal code.");
            }
            else {
                var bucketMatch = getBucketMatch(postal_code);

                var sourceCoords = new GLatLng(response.lat(), response.lng());

                if (bucketMatch >= 0) {
                    var mainMatch = getMainMatch(bucketMatch, sourceCoords);

                    if (mainMatch >= 0) {
                        var location = getLocation(mainMatch);
                        // Then the destination coordinates
                        var tempCoords = coordinates[mainMatch].split(',');

                        var destCoords = new GLatLng(tempCoords[0], tempCoords[1]);

                        // Get the distance between source and main match (destination)
                        var distanceToMainMatch = sourceCoords.distanceFrom(destCoords) / 1000;

                        $j.ajax({
                            url: "locations/ON.asp?addSpace=1&id=" + mainMatch
						       + "&distances=" + Math.ceil(distanceToMainMatch),
                            cache: false,
                            success: function(result) {
                                getClosestMatches(mainMatch, tableHeaderHtml + result, sourceCoords);
                            }
                        });
                    }
                    else {
                        showErrorPage();
                    }
                }
                // Nothing found
                else {
                    // Try to find the closest matches
                    getClosestMatches(-1, tableHeaderHtml, sourceCoords);

                    // Show error
                    //showErrorPage();
                }
            } // end response valid for get source coords
        }); // end get source coords
    }

    // Shows the generic error message
    function showErrorPage() {
        $j.ajax({
            url: "locations/error.asp",
            cache: false,
            success: function(result) {
                $j("#results").html(result);
            }
        });
    }

    // Returns the bucket match (index) for the specified postal code
    function getBucketMatch(full_postal_code) {
        var temp = full_postal_code.split(' ');
        if (temp.length == 1) return;

        var postal_search = temp[0];

        var bucket_match = -1;

        for (var i = 0; i < postal_code_buckets.length; i++) {
            var bucket = postal_code_buckets[i];

            if ($j.inArray(postal_search, bucket) >= 0) {
                bucket_match = i;
                break;
            }
        }

        return bucket_match;
    }

    // Returns the main match (from the closest bucket)
    function getMainMatch(bucketIndex, sourceCoords) {
        var bucket = postal_code_buckets[bucketIndex];

        // 1. GET LIST OF BUCKET MATCHES
        var locationIndex = -1;
        var minDistance = 99999999;


        for (var i = 0; i < locationPostalCodes.length; i++) {
            if ($j.inArray(locationPostalCodes[i], bucket) >= 0) {
                // 2. FIND THE CLOSEST ONE AMONG THEM (ASSUMING > 1)
                var tempCoords = coordinates[i].split(',');
                var destCoords = new GLatLng(tempCoords[0], tempCoords[1]);

                var distance = getDistance(sourceCoords, destCoords);

                if (distance < minDistance) {
                    locationIndex = i;
                    minDistance = distance;
                }
            }
        }

        // 3. THEN USE THAT AS THE FINAL MAIN MATCH
        return locationIndex;
    }

    // Converts Degrees to Radians
    function toRad(deg) {
        var pi = Math.PI;
        return (deg * (pi / 180));
    }

    // Calculates the distance between 2 coordinates. Accepts GLatLng objects as params
    function getDistance(coord1, coord2) {
        var lat1 = coord1.lat();
        var lat2 = coord2.lat();
        var lon1 = coord1.lng();
        var lon2 = coord2.lng();

        var R = 6371; // Earth's mean radius in km
        var dLat = toRad(lat2 - lat1);
        var dLon = toRad(lon2 - lon1);
        var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
                Math.sin(dLon / 2) * Math.sin(dLon / 2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        var d = R * c;

        return d;
    }

    // Returns the next closest matches (skipping the main match)
    function getClosestMatches(skip, html, sourceCoords) {
        distances = new Array(); // re-init array

        if (skip == 0) {
            calculateDistance(sourceCoords, addresses[1], 1, skip, html); // start from the 2nd one if the 1st one is the main match
        }
        else {
            calculateDistance(sourceCoords, addresses[0], 0, skip, html);
        }
    }

    function getLocation(index) {
        return addresses[index];
    }

    // Calculates the distance between the source and the various destinations (skipping the main match), and sets the HTML of the results
    function calculateDistance(sourceCoords, destination, i, skip, html) {
        // Skip this one if applicable
        if (skip != i) {
            var tempCoords = coordinates[i].split(',');
            var destCoords = new GLatLng(tempCoords[0], tempCoords[1]);
            var d = sourceCoords.distanceFrom(destCoords) / 1000;

            if (d < MAX_DISTANCE) {
                distances.push({ id: i, distance: Math.ceil(d) });
            }
        }

        if (i < addresses.length - 1) {
            i++;
            calculateDistance(sourceCoords, addresses[i], i, skip, html);
        }
        else {
            var postal_code = $j("#postal_code").attr('value');
            var ids = "";
            var distanceList = "";

            var endIndex = distances.length;

            // Show only the top [x] results
            if (endIndex > MAX_SECONDARY_RESULTS) {
                endIndex = MAX_SECONDARY_RESULTS;
            }

            // Sort the locations by distance
            distances.sort(sortByDistance);

            for (var d = 0; d < endIndex; d++) {
                if (ids.length > 0) {
                    ids += ",";
                    distanceList += ",";
                }

                ids += distances[d].id;
                distanceList += distances[d].distance;
            }

            if (ids.length > 0) {
                $j.ajax({
                    url: "locations/ON.asp?id=" + ids + "&distances=" + distanceList,
                    cache: false,
                    success: function(result) {
                        var separatorRow = "";

                        // If there was a main match, then put a separator row, otherwise just show the next closest locations
                        if (skip >= 0) {
                            separatorRow = "<tr><th colspan=\"3\">The next closest locations to you</th></tr>";
                        }

                        $j("#results").html(html + separatorRow + result + "</table>");
                    }
                });
            }
            // if nothing found AND there was no main location found, then redirect to error page
            else if (skip == -1) {
                showErrorPage();
            }
        }

    }

    // Sorts in ascending order
    function sortByDistance(a, b) {
        var x = a.distance;
        var y = b.distance;

        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    }

    initjQuery();
});