﻿var cameraCount = 0;
var cameraLastUpdateCenter;
var cameraLastUpdateZoom;
var cameraRegistry = new Array();
var cameraUpdatesType = "xml";
var defaultCameraIconURL = "images/cctv.png";

var incidentLastUpdateCenter;
var incidentLastUpdateZoom;
var incidentLayerNames = new Array("incidentsLayer", "congestionLayer", "constructionLayer", "detourLayer", "weatherLayer", "specialEventLayer");
var incidentRegistry = new Array();
var incidentUpdatesTimeout;
var incidentUpdatesType = "xml";
var incidentLayersLoaded;

var baseMapVisible = true;
var satelliteVisible = false;

// TrafficLand IFrame dimensions
var tlFrameWidth = 367;
var tlFrameHeight = 310;
// TrafficLand balloon dimensions
var tlBalloonHeight = tlFrameHeight + 30;
var tlBalloonWidth = tlFrameWidth;

function GetCameraBalloonContent(cameraDescription, cameraImageURL, ID) {
    /// <summary>Returns the content of a camera balloon with the balloon div width and the camera image size adjusted, based on the size of the map, to not display any of the image "off the map"</summary>

    /*
    var ID = cameraImageURL.replace("http://", "");
    while (ID.indexOf("/") != -1) { ID = ID.replace("/", ""); }
    while (ID.indexOf(".") != -1) { ID = ID.replace(".", ""); }
    while (ID.indexOf(" ") != -1) { ID = ID.replace(" ", ""); }
    
    var trackID = cameraImageURL.replace("http://", "");
    //while (trackID.indexOf(".") != -1) { trackID = trackID.replace(".", "-"); }
    
    var balloonWidth = 300, imageWidth = 297, imageHeight = 225;
    var maxBalloonWidth = Math.floor(map.getWidth() / 2);
    var maxImageHeight = Math.floor(map.getHeight() / 2) - 43 - 30;  // 43 = dock height, 30 = balloon description area
    if (balloonWidth > maxBalloonWidth) {
    balloonWidth = maxBalloonWidth;
    imageWidth = balloonWidth - 3;
    imageHeight = Math.floor(imageWidth * 0.76);
    }
    if (imageHeight > maxImageHeight) {
    imageHeight = maxImageHeight;
    imageWidth = Math.floor(imageHeight * 1.32);
    balloonWidth = imageWidth + 3;
    }

    var d = new Date();
    var randomString = d.getFullYear().toString() + d.getMonth().toString() + d.getDate().toString() + d.getHours().toString() + d.getMinutes().toString() + d.getSeconds().toString();

    var balloonContent = '<div class="mapBalloon" style="width:' + balloonWidth + 'px">' +
    '<strong>' + cameraDescription + ' (' + new Date().toString() + ')</strong><br />' + 
    '<div id="lc' + ID + '" style="display:block">Loading camera image...</div>' +
    '<img onload="TrackCameraBalloon(\'' + trackID + '\'); HideCameraImageLoading(\'' + ID + '\');" class="cameraImage" width="' + imageWidth + 'px" height="' + imageHeight + 'px" ' +
    'src="' + cameraImageURL + '?random=' + randomString + '" />' +
    '</div>';
    */

    var balloonContent = '<div class="mapBalloon" style="padding: 0px; width: ' + tlBalloonWidth.toString() + 'px">' +
    //'<div style="float: right; padding-bottom: 3px; width: 10px; z-index: 150">' +
        '<div style="position: absolute; left: 353px; padding-top: 3px; width: 10px; z-index: 150">' +
        '<a href="#" onclick="CloseOpenBalloon(); return false;"><img src="/images/cancel.png" width="10" height="10" border="0" alt="Close Balloon" /></a>' +
        '</div>' +
    //'<div>' +
        '<iframe frameborder="0" scrolling="no" style="height: ' + tlFrameHeight.toString() + 'px; width: ' + tlFrameWidth.toString() + 'px;" src="/TLSingleCamera.aspx?webid=' + ID + '" />' +
    //'</div>' + 
        '</div>';

    return balloonContent;
}


function GetIncidentBalloonContent(description) {
    return '<div class="mapBalloon" style="padding: 3px; width: 150px text-align:justify;">' +
    '<div style="position: relative;  padding: 0px; padding-bottom: 3px; text-align:right; vertical-align:top;">' +
           '<a href="#" onclick="CloseOpenBalloon(); return false;"><img src="/images/cancel.png" width="10" height="10" border="0" alt="Close Balloon" /></a>' +
           '</div>' +
            description +
           '</div>';
}

function GetShields() {
    var gspArray = new Array();
    gspArray[0] = "images/gsp.png";
    gspArray[1] = new Array(39.00559, -74.8702);
    gspArray[2] = new Array(39.61214, -74.426);
    gspArray[3] = new Array(40.25002, -74.0819);
    gspArray[4] = new Array(40.50277, -74.3012);
    gspArray[5] = new Array(40.80421, -74.1848);
    gspArray[6] = new Array(41.05415, -74.0657);

    /*
    gspArray[1] = new Array(39.19267515, -74.71106521);
    gspArray[2] = new Array(39.00559213, -74.87022106);
    gspArray[3] = new Array(39.30532206, -74.61799903);
    gspArray[4] = new Array(39.61214249, -74.42597494);
    gspArray[5] = new Array(39.77252763, -74.24519619);
    gspArray[6] = new Array(39.99572714, -74.20713865);
    gspArray[7] = new Array(40.25002074, -74.08192636);
    gspArray[8] = new Array(40.48854301, -74.30235644);
    gspArray[9] = new Array(40.70572677, -74.24566465);
    gspArray[10] = new Array(40.80420764, -74.18480402);
    gspArray[11] = new Array(40.90766632, -74.09971476);
    gspArray[12] = new Array(40.98112628, -74.07105532);
    gspArray[13] = new Array(41.05414774, -74.06573329);
    */

    var njtaArray = new Array();
    njtaArray[0] = "images/njtp.png";

    njtaArray[1] = new Array(39.6857547, -75.4471839);
    njtaArray[2] = new Array(40.0964608, -74.7303578);
    njtaArray[3] = new Array(40.5910884, -74.2367373);
    njtaArray[4] = new Array(40.8385709, -74.0192852);

    /*
    njtaArray[1] = new Array(39.6857547, -75.44718385);
    njtaArray[2] = new Array(39.8600825, -75.0725526);
    njtaArray[3] = new Array(40.09646078, -74.73035777);
    njtaArray[4] = new Array(40.34770669, -74.4748557);
    njtaArray[5] = new Array(40.54148603, -74.30492605);
    njtaArray[6] = new Array(40.63566933, -74.20933987);
    njtaArray[7] = new Array(40.71372323, -74.1412503);
    njtaArray[8] = new Array(40.79615196, -74.08043831);
    njtaArray[9] = new Array(40.83857088, -74.0192852);
    njtaArray[10] = new Array(40.77045552, -74.06272563);
    */

    var acxArray = new Array();
    acxArray[0] = "images/acx.png";
    acxArray[1] = new Array(39.4323789, -74.585355);
    acxArray[2] = new Array(39.7671828, -75.0472918);

    /*
    acxArray[0] = "images/acx.png";
    acxArray[1] = new Array(39.37494319, -74.47696547);
    acxArray[2] = new Array(39.43237887, -74.58535499);
    acxArray[3] = new Array(39.51203539, -74.68453718);
    acxArray[4] = new Array(39.65032634, -74.8735677);
    acxArray[5] = new Array(39.7671828, -75.04729178);
    acxArray[6] = new Array(39.37441986, -74.4405563);
    */

    var layer = MapLayers['shieldsLayer'];
    layer.clear();

    var i;
    for (i = 1; i < gspArray.length; i++) {
        new Telogis.GeoBase.MapLayers.ImageObject({
            id: 'gsp' + i,
            layer: layer,
            location: { lat: gspArray[i][0], lon: gspArray[i][1] },
            src: gspArray[0]
        });
    }

    for (i = 1; i < njtaArray.length; i++) {
        new Telogis.GeoBase.MapLayers.ImageObject({
            id: 'njta' + i,
            layer: layer,
            location: { lat: njtaArray[i][0], lon: njtaArray[i][1] },
            src: njtaArray[0]
        });
    }

    for (i = 1; i < acxArray.length; i++) {
        new Telogis.GeoBase.MapLayers.ImageObject({
            id: 'acx' + i,
            layer: layer,
            location: { lat: acxArray[i][0], lon: acxArray[i][1] },
            src: acxArray[0]
        });
    }
}

function HandleMapIcon(sender, args) {
    var commandName = args.Command.get_name();
    switch (commandName) {
        case "ToggleCamera": ToggleLayer("camerasLayer"); break;
        case "ToggleIncident": ToggleLayer("incidentsLayer"); break;
        case "ToggleCongestion": ToggleLayer("congestionLayer"); break;
        case "ToggleConstruction": ToggleLayer("constructionLayer"); break;
        case "ToggleDetour": ToggleLayer("detourLayer"); break;
        case "ToggleWeather": ToggleLayer("weatherLayer"); break;
        case "ToggleSpecialEvent": ToggleLayer("specialEventLayer"); break;
        case "ToggleSatellite": ToggleLayer("satelliteLayer"); break;
        case "ToggleTraffic": ToggleLayer("trafficLayer"); break;
        case "ToggleBasemap": ToggleBaseMap(); break;
        case "ToggleLabels": ToggleMapLabels(); break;
    }
    args.Command.set_state(args.Command.get_state() == 1 ? 2 : 1);
}

function HideCameraImageLoading(ID) {
    $("#lc" + ID).hide();
}

function LogError(xmlDetails, sourcePage) {
    /*
    AjaxCall(null, "services/MapServiceProxy.asmx/WriteToErrorLog",
    "{'sourcePage':'" + sourcePage + "','xmlDetails':'" + xmlDetails + "'}",
    null, null, function(result) { }, function(xhr, statusText, thrownError) { });
    */
}

function ToggleBaseMap(sender, args) {
    baseMapVisible = !baseMapVisible;
    UpdateBaseMapAndSatellite();
}

function ToggleMapLabels(sender, args) {
    map.set_renderLabels(false);
}

function ToggleLayer(layerName) {
    if (layerName == 'satelliteLayer') {
        satelliteVisible = !satelliteVisible;
        UpdateBaseMapAndSatellite();
        return;
    }
    else if (layerName == "camerasLayer") {
        MapLayers[layerName].toggleVisibility();
    }
    else {
        MapLayers[layerName].toggleVisibility();
        UpdateIncidents();
    }
}

function TrackCameraBalloon(cameraURL) {
    urchinTracker('/cameraballoon.aspx?url=' + cameraURL);
}

function UpdateBaseMapAndSatellite() {
    // Set shields and auxiliary layer visibility to match base map
    MapLayers['shieldsLayer'].setVisibility(baseMapVisible);
    if (MapLayers['main_map_auxiliary'] != null) {
        MapLayers['main_map_auxiliary'].setVisibility(baseMapVisible);
    }

    if (satelliteVisible && baseMapVisible) {
        map.getTileLayer().setVisibility(true);
        map.getTileLayer().reconfigureTiles({ args: { s: 'tileserve', auxLayer: '0', satellite: true} });
    }
    else if (satelliteVisible) {
        map.getTileLayer().setVisibility(true);
        map.getTileLayer().reconfigureTiles({ args: { s: 'blank', auxLayer: '0', satellite: true} });
    }
    else if (baseMapVisible) {
        map.getTileLayer().setVisibility(true);
        map.getTileLayer().reconfigureTiles({ args: { s: 'tileserve', auxLayer: '0'} });
    }
    else {
        map.getTileLayer().setVisibility(false);
    }
}

// == Ajax Calls ========================================================================================================

// As of 3-21-2011, only cameraUpdatesType = "xml" is used.  All other methods should be considered deprecated.
function UpdateCameras() {
    switch (cameraUpdatesType) {
        case 'bylatlon':
            if (cameraLastUpdateCenter == null || cameraLastUpdateZoom == null ||
                map.getCenter().lat != cameraLastUpdateCenter.lat ||
                map.getCenter().lon != cameraLastUpdateCenter.lon ||
                map.getZoomIndex() != cameraLastUpdateZoom) {
                UpdateCamerasByLatLon();
            }
            break;
        case 'xml':
            AjaxCallWithRetry(null, 'services/MapServiceProxy.asmx/GetFullCameraListXML', null, null, null,
                UpdateCamerasXML, UpdateCamerasXMLError, 3);
            break;
        default:
            UpdateCamerasAll();
            break;
    }

    if (cameraUpdatesType == "bylatlon" && !map['CamerasCallbackListener']) {
        map.addListener({
            id: 'CamerasCallbackListener',
            setMap: function (map) { },
            update: function (updateType) {
                if (updateType == Map.UPDATE_END_PAN || updateType == Map.UPDATE_REDRAW || updateType == Map.UPDATE_SIZE) {
                    UpdateCameras();
                }
            }
        });
    }
}

// As of 3-21-2011, only incidentUpdatesType = "xml" is used.  All other update types should be considered deprecated.
function UpdateIncidents() {
    switch (incidentUpdatesType) {
        case 'bylatlon':
            if (IncidentLayersNeedRefresh() ||
                incidentLastUpdateCenter == null || incidentLastUpdateZoom == null ||
                map.getCenter().lat != incidentLastUpdateCenter.lat ||
                map.getCenter().lon != incidentLastUpdateCenter.lon ||
                map.getZoomIndex() != incidentLastUpdateZoom) {
                ClearAllIncidentLayers();
                UpdateIncidentsByLatLon();
            }
            break;
        case 'xml':
            AjaxCallWithRetry(null, 'services/MapServiceProxy.asmx/GetIncidentsXML',
                "{'includeIncidents':'" + MapLayers["incidentsLayer"].isVisible().toString() + "', " +
                "'includeCongestion':'" + MapLayers["congestionLayer"].isVisible().toString() + "', " +
                "'includeConstruction':'" + MapLayers["constructionLayer"].isVisible().toString() + "', " +
                "'includeDetour':'" + MapLayers["detourLayer"].isVisible().toString() + "', " +
                "'includeWeather':'" + MapLayers["weatherLayer"].isVisible().toString() + "', " +
                "'includeSpecialEvents':'" + MapLayers["specialEventLayer"].isVisible().toString() + "'}",
                "application/json; charset=utf-8", "json",
                UpdateIncidentsXML, UpdateIncidentsXMLError, 3);
            break;
        default:
            UpdateIncidentsAll();
            break;
    }

    if (incidentUpdatesType == "bylatlon" && !map['IncidentsCallbackListener']) {
        map.addListener({
            id: 'IncidentsCallbackListener',
            setMap: function (map) { },
            update: function (updateType) {
                if (updateType & Map.UPDATE_END_PAN || (updateType & Map.UPDATE_PAN && !map.isDragging()) || updateType == Map.UPDATE_REDRAW || updateType == Map.UPDATE_SIZE) {
                    //alert("IncidentsCallbackListener = Update type: " + updateType);
                    ClearAllIncidentLayers();
                    UpdateIncidents();
                }
            }
        });
    }

    if (incidentUpdatesTimeout != null) { clearTimeout(incidentUpdatesTimeout); }
    if (incidentUpdatesType == "xml") {
        incidentUpdatesTimeout = setTimeout("UpdateIncidents();", 60 * 1000);
    }
    else {
        incidentUpdatesTimeout = setTimeout("ClearAllIncidentLayers(); UpdateIncidents();", 60 * 1000);
    }
}

// This function should be considered deprecated as of 3-21-2011 as now camerasUpdateType = "xml" is exclusively used.
function UpdateCamerasAll() {
    if (MapLayers['camerasLayer'].isVisible() && map.getZoomIndex() > 5) {
        AjaxCall("POST", "services/MapServiceProxy.asmx/GetFullCameraList", null,
            "application/json; charset=utf-8", "json",
            function (result) {
                UpdateCamerasCallback(result);
            },
            function (xhr, ajaxOptions, thrownError) {
                //alert("AJAX error in UpdateCameras");
                //alert(xhr.status);
                //alert(thrownError);
            }
        );
    }
}

// This function should be considered deprecated as of 3-21-2011 as now camerasUpdateType = "xml" is exclusively used.
function UpdateCamerasByLatLon() {
    if (MapLayers['camerasLayer'].isVisible() && map.getZoomIndex() > 5) {
        var upperLeft = GetMapUpperLeft();
        var lowerRight = GetMapLowerRight();
        AjaxCall("POST", "services/MapServiceProxy.asmx/GetCamerasByLatLon",
            "{'westLon':'" + upperLeft.lon + "', 'northLat':'" + upperLeft.lat + "', 'eastLon':'" + lowerRight.lon + "', 'southLat':'" + lowerRight.lat + "', 'zoom':'" + map.getZoomIndex() + "'}",
            "application/json; charset=utf-8", "json",
            function (result) {
                UpdateCamerasCallback(result);
                cameraLastUpdateCenter = new Telogis.GeoBase.LatLon(map.getCenter().lat, map.getCenter().lon);
                cameraLastUpdateZoom = map.getZoomIndex();
            },
            function (xhr, ajaxOptions, thrownError) {
                //alert("AJAX error in UpdateCameras");
                //alert(xhr.status);
                //alert(thrownError);
            }
        );
    }
}

// As of 3-21-2011, only incidentUpdatesType = "xml" is used.  This function is not used with "xml" so it
// should now be considered deprecated.
function IncidentLayersNeedRefresh() {
    var i;
    if (incidentLayersLoaded == null) {
        incidentLayersLoaded = new Object();
        for (i = 0; i < incidentLayerNames.length; i++) {
            incidentLayersLoaded[incidentLayerNames[i]] = false;
        }
    }

    var refreshNeeded = false;
    for (i = 0; i < incidentLayerNames.length; i++) {
        if (MapLayers[incidentLayerNames[i]]) {
            if (MapLayers[incidentLayerNames[i]].isVisible() && incidentLayersLoaded[incidentLayerNames[i]] == false) {
                refreshNeeded = true;
                break;
            }
        }
    }
    return refreshNeeded;
}

// As of 3-21-2011, only incidentUpdatesType = "xml" is used.  This function is not used with "xml" so it
// should now be considered deprecated.
function ClearAllIncidentLayers() {
    for (var i = 0; i < incidentLayerNames.length; i++) {
        if (MapLayers[incidentLayerNames[i]]) { MapLayers[incidentLayerNames[i]].clear(); }
        incidentLayersLoaded[incidentLayerNames[i]] = false;
    }
    ClearRegistry(incidentRegistry);
}

// This function should be considered deprecated as of 3-21-2011 as now incidentUpdateType = "xml" is used; "xml"
// update type does not use this function.
function UpdateIncidentsAll() {
    if (map.getZoomIndex() > 5) {
        AjaxCall("POST", "services/MapServiceProxy.asmx/GetIncidentList", null,
            "application/json; charset=utf-8", "json",
            function (incidents) {
                UpdateIncidentsCallback(incidents);
            },
            function (xhr, ajaxOptions, thrownError) {
                //alert("AJAX error in UpdateIncidentsAll");
                //alert(xhr.status);
                //alert(thrownError);
            }
        );
    }
}

// This function should be considered deprecated as of 3-21-2011 as now incidentUpdateType = "xml" is used, and
// update type "xml" does not use this function.
function UpdateIncidentsByLatLon() {
    if (map.getZoomIndex() > 5) {
        var upperLeft = GetMapUpperLeft();
        var lowerRight = GetMapLowerRight();
        AjaxCall("POST", "services/MapServiceProxy.asmx/GetIncidentsByLatLon",
            "{'westLon':'" + upperLeft.lon + "', 'northLat':'" + upperLeft.lat + "', 'eastLon':'" + lowerRight.lon + "', 'southLat':'" + lowerRight.lat + "', 'zoomLevel':'" + map.getZoomIndex() + "'}",
            "application/json; charset=utf-8", "json",
            function (incidents) {
                UpdateIncidentsCallback(incidents);
                incidentLastUpdateCenter = new Telogis.GeoBase.LatLon(map.getCenter().lat, map.getCenter().lon);
                incidentLastUpdateZoom = map.getZoomIndex();
            },
            function (xhr, ajaxOptions, thrownError) {
                //alert("AJAX error in UpdateIncidents\nStatus: " + xhr.status + "\nError: " + thrownError);
            }
        );
    }
}

// == Ajax Callbacks ====================================================================================================

function UpdateCamerasXML(result) {
    MapLayers['camerasLayer'].loadXML(result.d);
}

function UpdateCamerasXMLError(xhr, textStatus, thrownError) {
    AjaxErrorHandler("services/MapServiceProxy.asmx/GetFullCameraListXML", xhr, textStatus, thrownError,
        "UpdateCamerasXML(result);",
        "UpdateCamerasXMLError(xhr, textStatus, thrownError);"
    );
}

function UpdateIncidentsXML(result) {
    MapLayers['xmlIncidentsLayer'].loadXML(result.d);
}

function UpdateIncidentsXMLError(xhr, textStatus, thrownError) {
    AjaxErrorHandler("services/MapServiceProxy.asmx/GetIncidentsXML", xhr, textStatus, thrownError,
        "UpdateIncidentsXML(result);",
        "UpdateIncidentsXMLError(xhr, textStatus, thrownError);"
    );
}

// This function used only when cameraUpdatesType = "all" or "bylatlon".  Since "xml" is now used
// exclusively (as of 3-21-2011), this function should be considered deprecated.
function UpdateCamerasCallback(cameras) {
    var count = 0;
    MapLayers['camerasLayer'].clear();
    ClearRegistry(cameraRegistry);
    //var start = new Date().getTime();
    $(cameras.d).each(function () {
        if (cameraCount > 0 && count >= cameraCount) {
            return false;
        }

        var cameraIconURL = defaultCameraIconURL;
        if (this.IconURL) {
            cameraIconURL = this.IconURL;
        }

        cameraRegistry[count++] = CreateImageObject('cam' + this.ID, MapLayers['camerasLayer'],
            new Telogis.GeoBase.LatLon(parseFloat(this.Lat), parseFloat(this.Lon)), cameraIconURL,
            GetCameraBalloonContent(this.Description, this.CameraImageURL, this.ID), false, null);
    });
    //alert("Cameras took " + (new Date().getTime() - start) + " milliseconds.");
}

// This function used only when incidentUpdatesType = "all" or "bylatlon".  Since "xml" is now used
// exclusively (as of 3-21-2011), this function should be considered deprecated.
function UpdateIncidentsCallback(incidents) {
    var count = 0;
    var iconURL = "";
    var layerName = "";

    $(incidents.d).each(function () {
        var eventType = this.Type.toLowerCase();
        if (this.IconURL.toLowerCase().indexOf("incident") != -1) {
            layerName = 'incidentsLayer'
        }
        else if (this.IconURL.toLowerCase().indexOf("congestion") != -1) {
            layerName = 'congestionLayer'
        }
        else if (this.IconURL.toLowerCase().indexOf("construction") != -1) {
            layerName = 'constructionLayer'
        }
        else if (this.IconURL.toLowerCase().indexOf("detour") != -1) {
            layerName = 'detourLayer';
        }
        else if (this.IconURL.toLowerCase().indexOf("weather") != -1) {
            layerName = 'weatherLayer'
        }
        else if (this.IconURL.toLowerCase().indexOf("specialevent") != -1) {
            layerName = 'specialEventLayer'
        }
        else {
            layerName = 'incidentsLayer'
        }

        // Put on incidentsLayer if specific layerName not found
        if (!MapLayers[layerName]) {
            layerName = 'incidentsLayer';
        }

        if (MapLayers[layerName].isVisible()) {
            // MapLayersWrapper.layers[layerName].icons[this.ID] =
            incidentLayersLoaded[layerName] = true;
            incidentRegistry[count++] = CreateImageObject('inc' + this.ID, MapLayers[layerName],
                new Telogis.GeoBase.LatLon(parseFloat(this.Lat), parseFloat(this.Lon)), this.IconURL,
                '<div class="mapBalloon">' + this.Description + '</div>', true, dedicatedBalloonLayer,
                'Balloon.HOVER_ACTIVE | Balloon.REALIGN_TO_VIEWPORT');
            // MRR 3-16-2011 experiment:
            // Current behavior: 'Balloon.HOVER_ACTIVE | Balloon.REALIGN_TO_VIEWPORT');
            // Testing open on click: 'Balloon.LEFT_CLICK_TOGGLE | Balloon.REALIGN_TO_VIEWPORT');
        }
    });

    // Mark layers just loaded
    for (var i = 0; i < incidentLayerNames.length; i++) {
        if (MapLayers[incidentLayerNames[i]]) {
            if (MapLayers[incidentLayerNames[i]].isVisible()) {
                incidentLayersLoaded[incidentLayerNames[i]] = true;
            }
        }
    }
}

// == Scaled Icons Functions ============================================================================================

// To disable scaled icons: set scaledIconsEnabled = false

var scaledIconsEnabled = true;
var currentZoomRange = -1;
var previousZoomRange = -1;

function GetScaledIconURL(iconURL) {
    if (scaledIconsEnabled) {
        if (currentZoomRange == -1) {
            RefreshScaledIcons();
        }
        return iconURL.replace("images", "images/scaledicons").replace(".gif", ".png").replace(".png", "-0" + currentZoomRange.toString() + ".png");
    }
    else return iconURL;
}

function RefreshScaledIcons() {
    if (scaledIconsEnabled) {
        var iconWidthHeight = 0;
        var zoomIndex = map.getZoomIndex();

        switch (true) {
            case (zoomIndex >= 0 && zoomIndex <= 6):
                currentZoomRange = 1;
                iconWidthHeight = 12;
                break;
            case (zoomIndex >= 7 && zoomIndex <= 8):
                currentZoomRange = 2;
                iconWidthHeight = 16;
                break;
            case (zoomIndex >= 9 && zoomIndex <= 10):
                currentZoomRange = 3;
                iconWidthHeight = 20;
                break;
            case (zoomIndex >= 11 && zoomIndex <= 12):
                currentZoomRange = 4;
                iconWidthHeight = 24;
                break;
            case (zoomIndex >= 13 && zoomIndex <= 14):
                currentZoomRange = 5;
                iconWidthHeight = 28;
                break;
            case (zoomIndex >= 15 && zoomIndex <= 16):
                currentZoomRange = 6;
                iconWidthHeight = 32;
                break;
            case (zoomIndex >= 17 && zoomIndex <= 18):
                currentZoomRange = 7;
                iconWidthHeight = 36;
                break;
            case (zoomIndex == 19):
                currentZoomRange = 8;
                iconWidthHeight = 40;
                break;
            default:
                currentZoomRange = 4;
                iconWidthHeight = 24;
                break;
        }

        // If the new currentZoomRange does not match previousZoomRange, update/refresh layers as appropriate.
        if (currentZoomRange != previousZoomRange) {
            previousZoomRange = currentZoomRange;

            // Update incidents layer
            MapLayers['xmlIncidentsLayer'].reconfigure({ size: new Size(iconWidthHeight, iconWidthHeight) });
        }

        // Set this function to be called every time the map's zoom changes, if it isn't already
        if (!map['ScaledIconsListener']) {
            map.addListener({
                id: 'ScaledIconsListener',
                setMap: function (map) { },
                update: function (updateType) {
                    if (updateType & Map.UPDATE_ZOOM) {
                        RefreshScaledIcons();
                    }
                }
            });
        }
    }
}

// == Balloon "open on left click" functions ==================================================================
var openBalloon = null;
var openBalloonID = "";
function OnBalloonOpen(data) {
    // Figure out which XSLTObjectLayer this balloon is on
    var openBalloonLayer = "";
    if (MapLayers["camerasLayer"]._objects["camerasLayer_" + data.id] != null) {
        openBalloonLayer = "camerasLayer";
    }
    else {
        openBalloonLayer = "xmlIncidentsLayer";
    }

    // Close previously opened balloon, if any, and if it is not the same balloon now being opened
    if (openBalloon != null && openBalloon.id != openBalloonLayer + "_" + data.id + "_balloon") {
        openBalloon.hide();
        openBalloon = null;
        openBalloonID = "";
    }

    // Save a global reference to the just-opened balloon
    openBalloonID = openBalloonLayer + "_" + data.id;
    openBalloon = MapLayers[openBalloonLayer]._objects[openBalloonID].balloon;

    // Call special function for positioning the balloon if this balloon is on the cameras layer
    if (openBalloonLayer == "camerasLayer") {
        CameraBalloonShowCallback(data);
    }
}

function CloseOpenBalloon() {
    if (openBalloon != null) {
        openBalloon.hide();
        openBalloon = null;
        openBalloonID = "";
    }
}

function CameraBalloonShowCallback(data) {
    var mapHeight = map.getHeight();
    var mapWidth = map.getWidth();
    var panPadding = 10; // Extra amount to pan left/right and up/down when necessary

    // Set balloon's alignment based on position inside current map
    var h = ((mapWidth / 2) > data.pos.x) ? Balloon.ALIGN_RIGHT : Balloon.ALIGN_LEFT;
    var v = ((mapHeight / 2) > data.pos.y) ? Balloon.ALIGN_BOTTOM : Balloon.ALIGN_TOP;
    openBalloon.setAlignment(h, v);

    // Pan map if necessary
    var xPan = 0;
    if (h == Balloon.ALIGN_RIGHT && data.pos.x + tlBalloonWidth > mapWidth) {
        xPan = (((data.pos.x + tlBalloonWidth) - mapWidth) * -1) - panPadding;
    }
    else if (h == Balloon.ALIGN_LEFT && data.pos.x - tlBalloonWidth < 0) {
        xPan = ((data.pos.x - tlBalloonWidth) * -1) + panPadding;
    }

    var yPan = 0;
    if (v == Balloon.ALIGN_BOTTOM && data.pos.y + tlBalloonHeight > mapHeight) {
        yPan = (((data.pos.y + tlBalloonWidth) - mapHeight) * -1) - panPadding;
    }
    else if (v == Balloon.ALIGN_TOP && data.pos.y - tlBalloonHeight < 0) {
        yPan = ((data.pos.y - tlBalloonHeight) * -1) + panPadding;
    }

    if (xPan != 0 || yPan != 0) {
        map.panBy(new Telogis.GeoBase.Point(xPan, yPan));
    }
}
