﻿function CalculateBalloonHAlign(lat, lon) {
    var markerPoint = map.getXY(new Telogis.GeoBase.LatLon(lat, lon));
    return (map.getWidth() - markerPoint.x > markerPoint.x) ? Balloon.ALIGN_RIGHT : Balloon.ALIGN_LEFT;
}

function CalculateBalloonVAlign(lat, lon) {
    var markerPoint = map.getXY(new Telogis.GeoBase.LatLon(lat, lon));
    return (map.getHeight() - markerPoint.y > markerPoint.y) ? Balloon.ALIGN_BOTTOM : Balloon.ALIGN_TOP;
}

function ClearRegistry(registryToClear) {
    for (var i = 0; i < registryToClear.length; i++) {
        if (registryToClear[i] != null) {
            if (registryToClear[i].getBalloon() != null) {
                registryToClear[i].getBalloon().destroy();
            }
            registryToClear[i].destroy();
            delete registryToClear[i];
            registryToClear[i] = null;
        }
    }
}

function CreateImageObject(id, layer, latLon, imageSrc, balloonContent, adjustBalloonOnUpdate) {
    /// <summary>Creates a new Telogis.GeoBase.MapLayers.ImageObject</summary>
    /// <param name='id' type='String'>Name for the ImageObject</param>
    /// <param name='layer' type='Telogis.GeoBase.MapLayers.AbstractLayer'>Layer object to which the ImageObject should be added</param>
    /// <param name='latLon' type='Telogis.GeoBase.LatLon'>Latitude/longitude coordinates of the ImageObject</param>
    /// <param name='imageSrc' type='String'>URL of the image that should represent the ImageObject on the map</param>
    /// <param name='balloonContent' type='String'>HTML to be displayed in the ImageObject's balloon</param>
    /// <param name='adjustBalloonOnUpdate' type='True if the alignment of the ImageObject's balloon should be adjusted each time the map zooms, finishes a pan, or is resized'></param>
    /// <returns type='Telogis.GeoBase.MapLayers.ImageObject'>A new Telogis.GeoBase.MapLayers.ImageObject</returns>

    var imgObj = new Telogis.GeoBase.MapLayers.ImageObject({
        id: id,
        layer: layer,
        location: latLon,
        src: imageSrc,
        balloonConfig: {
            behavior: Balloon.HOVER_ACTIVE | Balloon.REALIGN_TO_VIEWPORT,
            hAlign: CalculateBalloonHAlign(latLon.lat, latLon.lon),
            vAlign: CalculateBalloonVAlign(latLon.lat, latLon.lon),
            content: balloonContent
        }
    });

    return imgObj;
}

function GetMapLowerRight() {
    return map.getLatLon(new Telogis.GeoBase.Point(map.getWidth(), map.getHeight()));
}

function GetMapUpperLeft() {
    return map.getLatLon(new Telogis.GeoBase.Point(0, 0));
}

function PanAndZoom(lat, lon, zoom) {
    if (lat != null && lon != null) {
        map.pan(new Telogis.GeoBase.LatLon(lat, lon));
    }
    if (zoom != null) {
        map.setZoomIndex(zoom);
    }
}

// == Functions that can be refactored further =====================================================================

function ZoomToIncident(lat, lon) {
    // This one should be replaced by calls to PanAndZoom
    PanAndZoom(lat, lon, 15);
}

function ZoomMap(sender, args) {
    // This one should be moved to the page that calls it and then it should call PanAndZoom
    PanAndZoom(null, null, sender.get_value());
}

// == Cookie Functions =============================================================================================

function GetCurrentPageName() {
    /// <summary>Gets name and path of current page, adding default.aspx if no page name is present.</summary>
    var currentPageName = location.pathname.toLowerCase();
    if (currentPageName.substring(currentPageName.length - 5) != ".aspx") {
        if (currentPageName.substring(currentPageName.length - 1) != "/") {
            currentPageName += "/";
        }
        currentPageName += "default.aspx";
    }
    return currentPageName;
}

function GetMapCookie() {
    /// <summary>Reads cookie and returns data within it as an object array</summary>
    var cookieData = new Array();
    if (typeof $.cookie == 'function') {
        if ($.cookie(mapCookieName)) {
            var mapName, lat, lon, zoom;
            var mapData = $.cookie(mapCookieName).split("|");
            for (i = 0; i < mapData.length; i = i + 2) {
                mapName = mapData[i];
                lat = ""; lon = ""; zoom = "";
                var dataFields = mapData[i + 1].split("&");
                for (j = 0; j < dataFields.length; j++) {
                    keyValuePair = dataFields[j].split("=");
                    if (keyValuePair[0] == "lat") { lat = keyValuePair[1]; }
                    else if (keyValuePair[0] == "lon") { lon = keyValuePair[1]; }
                    else if (keyValuePair[0] == "zoom") { zoom = keyValuePair[1]; }
                }
                cookieData[cookieData.length] = { Name: mapName, Lat: lat, Lon: lon, Zoom: zoom };
            }
        }
    }
    return cookieData;
}

function LoadCookieSettings() {
    if (map['setMapCookieCallback']) { map.removeListener({ id: 'setMapCookieCallback' }); }

    var cookieData = GetMapCookie();
    for (i = 0; i < cookieData.length; i++) {
        if (cookieData[i].Name == GetCurrentPageName()) {
            if (cookieData[i].Lat != null && cookieData[i].Lon != null) {
                map.pan(new Telogis.GeoBase.LatLon(cookieData[i].Lat, cookieData[i].Lon));
            }
            if (cookieData[i].Zoom != null) {
                map.setZoomIndex(cookieData[i].Zoom);
            }
            break;
        }
    }

    map.addListener({
        id: 'setMapCookieCallback',
        setMap: function(map) { },
        update: function(updateType) {
            if (updateType == Map.UPDATE_END_PAN || updateType == Map.UPDATE_REDRAW) {
                SetMapCookie();
            }
        }
    });
}

function SetMapCookie() {
    if (map && typeof $.cookie == 'function') {
        var cookieData = GetMapCookie();
        var cookieValue = "";

        // Write current cookie contents into string format.  Skip current page.
        for (i = 0; i < cookieData.length; i++) {
            if (cookieData[i].Name != GetCurrentPageName()) {
                if (cookieValue != "") { cookieValue += "|"; }
                cookieValue += cookieData[i].Name + "|lat=" + cookieData[i].Lat + "&lon=" + cookieData[i].Lon + "&zoom=" + cookieData[i].Zoom;
            }
        }

        // Add current page to cookieValue and set cookie
        if (cookieValue != "") { cookieValue += "|"; }
        cookieValue += GetCurrentPageName() + "|lat=" + map.getCenter().lat + "&lon=" + map.getCenter().lon + "&zoom=" + map.getZoomIndex();
        $.cookie(mapCookieName, cookieValue, { expires: 7 });
    }
}

// == AJAX Functions ============================================================================================================================

var ajaxCalls = new Object();
var displayMapError = "DisplayMapError(GetErrorMessage(xhr, textStatus, thrownError));";
var hideMapErrorBarTimeout;
var logError = "LogError(GetDefaultErrorDetailsXml(url, xhr, textStatus, thrownError), location.pathname);";

function AjaxCall(callType, url, data, dataType, resultType, successFunction, errorFunction) {
    /// <summary>Makes an AJAX call to a service URL</summary>
    /// <param name='callType' value='String'>GET or POST</param>
    /// <param name='url' value='String'>URL (relative to the current host) of the service to call</param>
    /// <param name='data' value='String'>Parameter data to send to the service</param>
    /// <param name='dataType' value='String'>Type of parameter data to be sent to the service</param>
    /// <param name='resultType' value='String'>Type of data expected back from the service</param>
    /// <param name='successFunction' value='Function'>Function to be called on success</param>
    /// <param name='errorFunction' value='Function'>Function to be called on error</param>
    if (callType == null || callType == "") {
        callType = "POST";
    }
    
    if (data == null || data == "") {
        data = "{}";
    }

    if (dataType == null || dataType == "") {
        dataType = "application/json; charset=utf-8";
    }

    if (resultType == null || resultType == "") {
        resultType = "json";
    }

    if (errorFunction == null) {
        errorFunction = function(xhr, textStatus, thrownError) {
            eval(displayMapError);
            eval(logError);
            // alert("AJAX error calling " + url + "\nXHR Status: " + xhr.status + "\nStatus Text: " + textStatus + "\nError: " + thrownError);
        };
    }
    else if (errorFunction == "displayOnly") {
        errorFunction = function(xhr, textStatus, thrownError) {
            eval(displayMapError);
        }
    }
    else if (errorFunction == "logOnly") {
        errorFunction = function(xhr, textStatus, thrownError) {
            eval(logError);
        };
    }
    else if (errorFunction == "none") {
        errorFunction = null;
    }

    $.ajax({
        type: callType,
        url: url,
        data: data,
        contentType: dataType,
        dataType: resultType,
        success: successFunction,
        error: errorFunction
    });
}

function AjaxCallWithRetry(callType, url, data, dataType, resultType, successFunction, errorFunction, maxRetries) {
    /// <summary>Makes an AJAX call to a service URL and if unsuccessful retries the call maxRetries number of times.</summary>
    /// <param name='callType' value='String'>GET or POST</param>
    /// <param name='url' value='String'>URL (relative to the current host) of the service to call</param>
    /// <param name='data' value='String'>Parameter data to send to the service</param>
    /// <param name='dataType' value='String'>Type of parameter data to be sent to the service</param>
    /// <param name='resultType' value='String'>Type of data expected back from the service</param>
    /// <param name='successFunction' value='Function'>Function to be called on success</param>
    /// <param name='errorFunction' value='Function'>Function to be called on error</param>
    /// <param name='maxRetries' value='Integer'>Maximum number of times call should be retried if unsuccessful</param>
    if (maxRetries == null) { maxRetries = 3; }
    
    if (ajaxCalls[url] == null) {
        ajaxCalls[url] = new Object;
        ajaxCalls[url].failCount = 0;
    }
    ajaxCalls[url].callType = callType;
    ajaxCalls[url].data = data;
    ajaxCalls[url].dataType = dataType;
    ajaxCalls[url].maxRetries = maxRetries;
    ajaxCalls[url].resultType = resultType;

    AjaxCall(ajaxCalls[url].callType, url, ajaxCalls[url].data, ajaxCalls[url].dataType, ajaxCalls[url].resultType,
        successFunction, errorFunction);
}

function AjaxErrorHandler(url, xhr, textStatus, thrownError, successScript, errorScript) {
    var debug = false;
    if (xhr.status > 12000) {
        // Supply default values if none exist
        if (ajaxCalls[url] == null) { ajaxCalls[url] = new Object(); }
        if (ajaxCalls[url].failCount == null) { ajaxCalls[url].failCount = 0; }
        if (ajaxCalls[url].maxRetries == null) { ajaxCalls[url].maxRetries = 3; }
    
        ajaxCalls[url].failCount++;
        if (ajaxCalls[url].failCount < ajaxCalls[url].maxRetries) {
            if (debug) { alert('Failure #' + ajaxCalls[url].failCount); }
            AjaxCall(ajaxCalls[url].callType, url, ajaxCalls[url].data, ajaxCalls[url].dataType, ajaxCalls[url].resultType,
                function(result) {
                    eval(successScript);
                    ajaxCalls[url].failCount = 0;
                    if (debug) { alert("Successful call to " + url); }
                },
                function(xhr, textStatus, thrownError) {
                    eval(errorScript);
                }
            );
        }
        else {
            if (debug) { alert(ajaxCalls[url].maxRetries + ' failures, displaying and logging.'); }
            eval(displayMapError); eval(logError);
        }
    }
    else {
        if (debug) { alert("Non 12000 error: " + xhr.status); }
        eval(displayMapError); eval(logError);
    }
}

function DisplayMapError(errorMessage) {
    if ($("#MapErrorBar").html().indexOf(errorMessage) == -1) {
        if ($("#MapErrorBar").html() != "") {
            $("#MapErrorBar").html($("#MapErrorBar").html() + "<br />" + errorMessage);
        }
        else {
            $("#MapErrorBar").html(errorMessage);
        }

        $("#MapErrorBar").show("normal");

        if (hideMapErrorBarTimeout != null) {
            clearTimeout(hideMapErrorBarTimeout);
        }
        hideMapErrorBarTimeout = setTimeout("HideMapError();", 7 * 1000);
    }
}

function GetDefaultErrorDetailsXml(url, xhr, textStatus, thrownError) {
    detailsXml = "<errorData>";
    detailsXml += "<ajaxUrl>" + url + "</ajaxUrl>";
    detailsXml += "<xhrStatus>" + xhr.status + "</xhrStatus>";
    detailsXml += "<textStatus>" + textStatus + "</textStatus>";
    detailsXml += "<thrownError>" + thrownError + "</thrownError>";
    detailsXml += "</errorData>";
    return detailsXml;
}

function GetErrorMessage(xhr, textStatus, thrownError) {
    /// <summary>Examines AJAX error details to present a friendly message to the user.</summary>
    var message = "Additional map data could not be loaded. If you continue to receive this error, please check your Internet connection.";
    return message;
}

function HideMapError() {
    $("#MapErrorBar").hide("normal");
    $("#MapErrorBar").html("");
}