﻿var widget = new Array();
widget.map = new Array();
widget.data = new Array();
widget.data.addresses = new Array();
widget.data.clipart = new Array();
widget.data.imageDir = "";

var body;
var map;
var mapContainer;
var geocoder;
var standardTimeout = 100;

widget.data.logoMaxWidth = 70;
widget.data.logoMaxHeight = 70;

widget.data.photoMaxWidth = 150;
widget.data.photoMaxHeight = 150;

widget.data.balloonImageMaxWidth = 100;
widget.data.balloonImageMaxHeight = 100;

widget.data.infoBarImageMaxWidth = 150;
widget.data.infoBarImageMaxHeight = 150;

widget.map.initialZoom = 1;
widget.map.defaultCenter = new GLatLng(33, -45);

widget.map.zoom = 14;
widget.map.nonUsZoom = 5;

widget.map.clipartVisibleAtZoom = widget.map.zoom;
widget.map.photosVisibleAtZoom = widget.map.initialZoom + 3;

widget.data.invisibleIcon = widget.data.imageDir + "spacer.gif";

widget.map.showMainLogo = (hasData(widget.map.showMainLogo)) ? (widget.map.showMainLogo == true) : false;
widget.map.showPhotos = (hasData(widget.map.showPhotos)) ? (widget.map.showPhotos == true) : false;
widget.map.showLabels = (hasData(widget.map.showLabels)) ? (widget.map.showLabels == true) : false;
widget.map.showZoomControls = (hasData(widget.map.showZoomControls)) ? (widget.map.showZoomControls == true) : false;
widget.map.showTypeControls = (hasData(widget.map.showTypeControls)) ? (widget.map.showTypeControls == true) : false;

widget.map.logoPosition = G_ANCHOR_TOP_RIGHT;

var existingEvent = (window.onload) ? window.onload : function () {};
window.onload = function () {existingEvent(); start();};

function start()
{
    widget.data.mapLogoImage = document.createElement("IMG");
    widget.data.mapLogoImage.src = widget.data.mapLogo;
    
    widget.data.invisibleIconImage = document.createElement("IMG");
    widget.data.invisibleIconImage.src = widget.data.invisibleIcon;
    
    // set up address defaults
    for (var i = 0; i < widget.data.addresses.length; i++)
    {
        var thisAddressRecord = widget.data.addresses[i];
        
        // preload all image for later existence check
        thisAddressRecord._iconImage = document.createElement("IMG");
        thisAddressRecord._iconImage.src = thisAddressRecord.icon;
        
        thisAddressRecord._iconShadowImage = document.createElement("IMG");
        thisAddressRecord._iconShadowImage.src = thisAddressRecord.iconShadow;
        
        thisAddressRecord._logoImage = document.createElement("IMG");
        thisAddressRecord._logoImage.src = thisAddressRecord.logo;
        
        thisAddressRecord._logoShadowImage = document.createElement("IMG");
        thisAddressRecord._logoShadowImage.src = thisAddressRecord.logoShadow;
        
        thisAddressRecord._photoImage = document.createElement("IMG");
        thisAddressRecord._photoImage.src = thisAddressRecord.photo;
        
        thisAddressRecord._photoShadowImage = document.createElement("IMG");
        thisAddressRecord._photoShadowImage.src = thisAddressRecord.photoShadow;
        
        thisAddressRecord._point = null;
        
        // format the address that will be sent to the geocoder
        // prepend and append street address, zip and country only if they contain data
        thisAddressRecord._fullAddress = "";
        thisAddressRecord._balloonAddress = "";
        
        if (hasData(thisAddressRecord.streetAddress))
        {
            thisAddressRecord._fullAddress += trim(thisAddressRecord.streetAddress);
            thisAddressRecord._balloonAddress += trim(thisAddressRecord.streetAddress);
        }
        
        if (hasData(thisAddressRecord.city)) 
        {
            if (hasData(thisAddressRecord._fullAddress)) thisAddressRecord._fullAddress += ", ";
            thisAddressRecord._fullAddress += thisAddressRecord.city;
 
            if (hasData(thisAddressRecord._balloonAddress)) thisAddressRecord._balloonAddress += "<br>";
            thisAddressRecord._balloonAddress += thisAddressRecord.city;
        }
        
        if (hasData(thisAddressRecord.state)) 
        {
            if (hasData(thisAddressRecord._fullAddress)) thisAddressRecord._fullAddress += ", ";
            thisAddressRecord._fullAddress += thisAddressRecord.state;
  
            if (hasData(thisAddressRecord._balloonAddress)) thisAddressRecord._balloonAddress += ", ";
            thisAddressRecord._balloonAddress += thisAddressRecord.state;
       }
        
        if (hasData(thisAddressRecord.zip)) 
        {
            if (hasData(thisAddressRecord._fullAddress)) thisAddressRecord._fullAddress += ", ";
            thisAddressRecord._fullAddress += thisAddressRecord.zip;
  
            if (hasData(thisAddressRecord._balloonAddress)) thisAddressRecord._balloonAddress += ", ";
            thisAddressRecord._balloonAddress += thisAddressRecord.zip;
        }
        
        if (hasData(thisAddressRecord.country)) 
        {
            if (hasData(thisAddressRecord._fullAddress)) thisAddressRecord._fullAddress += ", ";
            thisAddressRecord._fullAddress += thisAddressRecord.country;
   
            if (hasData(thisAddressRecord._balloonAddress)) thisAddressRecord._balloonAddress += ", ";
            thisAddressRecord._balloonAddress += thisAddressRecord.country;
       }
        
        if (hasData(thisAddressRecord.phone)) 
        {
            thisAddressRecord._balloonAddress += "<p class='phone'>" + thisAddressRecord.phone + "</p>";
       }
        
        // if name field is empty, replace with concatenated first and last name
        if (isEmpty(thisAddressRecord.name)) thisAddressRecord.name = thisAddressRecord.firstName + " " + thisAddressRecord.lastName;

        // if there is a location name, add it to the name for use in labels, otherwise use just the name
        if (hasData(thisAddressRecord.locationName))
        {
            thisAddressRecord._fullName = thisAddressRecord.name + "<br>" + thisAddressRecord.locationName;
        } else {
            thisAddressRecord._fullName = thisAddressRecord.name;
        }
        
        // create the default balloon text for this record
        thisAddressRecord._infoHtml = "<p class='companyName'>" + thisAddressRecord._fullName + "</p>";
        thisAddressRecord._infoHtml += "<p class='address'>" + thisAddressRecord.streetAddress + "<br>" + thisAddressRecord.city + ", " + thisAddressRecord.state + " " + thisAddressRecord.zip + "</p>";
        thisAddressRecord._infoHtml += "<p class='phone'>" + thisAddressRecord.phone + "</p>";
        thisAddressRecord._infoHtml += "<p class='infoLink'><a class='infoLink' href='http://maps.google.com/?q=" + escape(thisAddressRecord._fullAddress) + "'>detailed map</a></p>"
    }

    // get the infoHtml template; will overwrite the above if found
    if (hasData(widget.data.balloonTemplateUrl)) getHtml(widget.data.balloonTemplateUrl, "infoHtmlTemplate")

    // preload images
    for (var i = 0; i < widget.data.clipart.length; i++)
    {
        widget.data.clipart[i].div = document.createElement("DIV");
        widget.data.clipart[i].image = document.createElement("IMG");
        widget.data.clipart[i].image.src = widget.data.clipart[i].url;
    }

    // start the asynchronous process of getting addresses from the geocoder
    getAddressLocations();
        
    if (addMapContainer()) initializeMap();
}

function addMapContainer()
{
    // must run before creating new map
    
    mapContainer = document.getElementById("map");
    
    try
    {

        if (mapContainer == null)
        {
            mapContainer = document.createElement("DIV");
            mapContainer.id = "map";
            
            body.insertBefore(mapContainer, body.firstChild);
        }

        mapContainer.className = "map";

        if (widget.map.top != null)
        {
            mapContainer.style.top = widget.map.top + "px";
            mapContainer.style.left = widget.map.left + "px";
            mapContainer.style.height = widget.map.height + "px";
            mapContainer.style.width = widget.map.width + "px";
        }

        return true;
    }
    catch (ex)
    {
        return false;
    }
}

function initializeMap()
{
    try
    {
        map = new GMap2(mapContainer);
    }
    catch (ex)
    {
        window.setTimeout("initializeMap()", standardTimeout);
    }
   
    map.setCenter(widget.map.defaultCenter, widget.map.initialZoom);

    switch (widget.map.type)
    {
        case "both":
            widget.map.type = G_HYBRID_MAP;
            break;
            
        case "satellite":
            widget.map.type = G_SATELLITE_MAP;
            break;
            
        default:
            widget.map.type = G_NORMAL_MAP;
            break;
    }

    map.setMapType(widget.map.type);

    if (widget.map.showZoomControls == true) map.addControl(new GSmallMapControl(), new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(10, 10)));
    if (widget.map.showTypeControls == true) map.addControl(new GMapTypeControl(), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10, 10)));

    if (map.isLoaded())
    {
        continueInitializing();
    } else {
        GEvent.addListener(map, "load", continueInitializing); 
    }
}

function continueInitializing()
{
    if (widget.map.showMainLogo) window.setTimeout("showMapLogo()", standardTimeout);
    createAndAddImages();
}

function showMapLogo()
{
    if (hasData(widget.data.mapLogo))
    {
        var logo = widget.data.mapLogoImage;
        if (logo) map.addControl(new ControlOverlay(logo));
    }
}

function getAddressLocations()
{
    try
    {
        geocoder = new GClientGeocoder();
    }
    catch (ex)
    {
        window.setTimeout("getAddressLocations()", standardTimeout);
        window.setTimeout("addAllAddressesToMap()", standardTimeout);
    }
    
    widget.data.addressRequests = 0;
    widget.data.addressReplies = 0;
    widget.data.addressRequestMaxTime = 5000;
    widget.data.addressRequestStart = new Date();
    widget.data.addressesAllRequested = false;
    
    // begin getting addresses asynchronously
    getNextAddress(0);
}

function getNextAddress(i)
{
    if (widget.data.addressRequests < widget.data.addresses.length)
    {
        var thisAddressRecord = widget.data.addresses[i];
        
        if (thisAddressRecord)
        {
            var thisPoint = null;
            
            if (hasData(thisAddressRecord.lat) && hasData(thisAddressRecord.lng))
            {
                try {var thisPoint = new GLatLng(thisAddressRecord.lat, thisAddressRecord.lng);}
                catch (ex) {}
            }
            
            if (thisPoint != null)
            {
                recordAddressPoint (i, thisPoint);
            } else {
                // get the point via the geocoder
                var thisAddress = thisAddressRecord._fullAddress;
                var script = "geocoder.getLatLng('" + thisAddress + "', function (point) {recordAddressPoint(" + i + ", point);})";

                eval(script);
            }
            
            widget.data.addressRequests += 1;
            eval("window.setTimeout('getNextAddress(" + widget.data.addressRequests + ")', " + standardTimeout + ")");
        }
    } else {
        widget.data.addressesAllRequested = true;
        window.setTimeout("addAllAddressesToMap()", standardTimeout);
    }
}

function recordAddressPoint (index, point)
{
    if (point)
    {
        widget.data.addresses[index]._point = point;
        widget.data.addressReplies += 1;
        
        if (isEmpty(widget.data.addresses[index].lat))
        {
            widget.data.addresses[index].lat = point.lat();
            widget.data.addresses[index].lng = point.lng();
        }
    }
}

function addAllAddressesToMap ()
{
    var allAddressesReceived = (widget.data.addressesAllRequested && (widget.data.addressReplies == widget.data.addressRequests));
    var elapsedTime = new Date() - widget.data.addressRequestStart;
    var addressTimeout = (elapsedTime > widget.data.addressRequestMaxTime);
    
    for (var i = 0; i < widget.data.addresses.length; i++)
    {
        var thisRecord = widget.data.addresses[i];
        
        if (thisRecord._added != true)
        {
            addAddressToMap (thisRecord, i);
            thisRecord._added == true;
        }
    }        
    
    if (allAddressesReceived || addressTimeout)
    {
        if (addressTimeout && widget.data.addressReplies == 0)
        {
            //alert ("No addresses were retrieved after " + elapsedTime + " microseconds.");
        } else {
            try
            {
            GEvent.addListener(map, "zoomend", setImageVisibility); 
            }
            catch (ex) {}
            
            finalizeMap();
        }
    } else {
        window.setTimeout("addAllAddressesToMap()", standardTimeout)
    }
}

function addAddressToMap (thisRecord, i)
{
    if (thisRecord._point != null && thisRecord._added != true)
    {
        createMarker(thisRecord, i);
        addMarkerToMap(thisRecord);
        thisRecord._added = true;
    }
}

function finalizeMap()
{
    var mapInfo = document.getElementById("mapInfo");
    if (widget.data.addresses.length > 0)
    {
        marker = widget.data.addresses[widget.data.addresses.length - 1]._marker;

        setMapInfo(marker);
    }
    
    zoomToBounds();
    
    if (getQuerystringValue("showdata")) if (getQuerystringValue("showdata").toLowerCase() == "true") displayData();
}

function setMapInfo(thisMarker)
{
    var mapInfo = document.getElementById("mapInfo");

    if (thisMarker && mapInfo)
    {
        var infoText = thisMarker._SLI_infoHtml2;
        var newId = "fromAddress1";

        infoText = infoText.replace(/id="fromAddress"/, 'id="' + newId + '"');

        mapInfo.innerHTML = "<div id='infoHTMLBar'>" + infoText + "</div>";

        window.setTimeout("focusOnField('" + newId + "')", 2000);
    }
}

function displayData()
{
    output = "";
    
    for (var i = 0; i < widget.data.addresses.length; i++)
    {
        var record = "";
        
        for (var item in widget.data.addresses[i])
        {
            if (item.substring(0, 1) != "_")
            {
                if (record != "") record += ", "
                record += "'" + item + "' : '" + widget.data.addresses[i][item] + "'";
            }
        }
        
        output += "widget.data.addresses.push({" + record + "});\n";
    }
    
    var textarea = document.createElement("TEXTAREA");
    textarea.innerText = output;
    textarea.style.position = "absolute";
    textarea.style.left = "0px";
    textarea.style.top = "0px";
    textarea.style.height = "250px";
    textarea.style.width = "500px";
    mapContainer.appendChild(textarea);
}

function zoomToBounds()
{
    if (widget.data.addresses.length > 1)
    {
        // zoom to include all points added so far
        var bounds = new GLatLngBounds();
        
        for (var j = 0; j < widget.data.addresses.length; j++)
        {
            var thisPoint = widget.data.addresses[j]._point;
            
            if (thisPoint != null) bounds.extend(thisPoint);
        }
        
        try
        {
            var zoom = map.getBoundsZoomLevel(bounds);
            if (zoom > 1) zoom = zoom - 1;
        }
        catch (ex) {return;}
        
        if (zoom > widget.map.zoom) zoom = widget.map.zoom;
        var center = bounds.getCenter();
    }
    else if (widget.data.addresses.length == 1)
    {
        zoom = widget.map.zoom
        var center = widget.data.addresses[0]._point;
    }
    else
    {
        return;
    }
    
    try
    {
    map.setCenter(center, zoom);
    }
    catch (ex) {}
    
    setImageVisibility(zoom);
}

function setImageVisibility(zoomLevel)
{
    // delay to allow map to calc it's zoom level
    window.setTimeout("finishSettingImageVisibility()", standardTimeout);
}

function finishSettingImageVisibility(zoomLevel)
{
    if (zoomLevel == null) zoomLevel = map.getZoom();
    
    var clipArtVisibility = "hidden";
    if (zoomLevel >= widget.map.clipartVisibleAtZoom) clipArtVisibility = "visible";
    
    var photoVisibility = "hidden";
    if (zoomLevel >= widget.map.photosVisibleAtZoom) photoVisibility = "visible";

    for (var i = 0; i < widget.data.clipart.length; i++)
    {
        if (widget.data.clipart[i].overlay) widget.data.clipart[i].overlay.div_.style.visibility = clipArtVisibility;
    }

    for (var i = 0; i < widget.data.addresses.length; i++)
    {
        if (widget.data.addresses[i]._imageOverlay) widget.data.addresses[i]._imageOverlay.div_.style.visibility = photoVisibility;
    }
    
}

function createAndAddImages()
{
    // create any map images; pre-loaded above
    for (var i = 0; i < widget.data.clipart.length; i++)
    {
        var thisImage = widget.data.clipart[i].image;
        
        if (imageInitialized(thisImage))
        {
            var thisPoint = new GLatLng(widget.data.clipart[i].lat, widget.data.clipart[i].lng);
            var thisDiv = widget.data.clipart[i].div;
            
            thisImage.style.position = "absolute";
            var imageHeight = Math.round(thisImage.height * widget.data.clipart[i].scale);
            var imageWidth =  Math.round(thisImage.width * widget.data.clipart[i].scale);

            thisImage.height = imageHeight;
            thisImage.width = imageWidth;

            var divHeight = parseFloat(thisImage.height);
            var divWidth = parseFloat(thisImage.width);
            
            thisDiv.style.visibility = "hidden";
            thisDiv.style.position = "absolute";
            thisDiv.style.height = divHeight + "px";
            thisDiv.style.width = divWidth + "px";

            thisDiv.appendChild(thisImage); // must follow all image size calcs; appending prevents image height/width changes
            
            var anchor = "center";
            var lockToMap = true;
            var fixedSize = false;
            
            widget.data.clipart[i].overlay = new overlayDiv (map, thisDiv, thisPoint, anchor, lockToMap, fixedSize);
        }
        else
        {
            window.setTimeout("createAndAddImages()", standardTimeout);
            return;
        }
    }
    
    if (map.isLoaded())
    {
        addImagesToMap();
    } else {
        GEvent.addListener(map, "load", addImagesToMap());
    }
}

function createMarker(thisRecord, i)
{
    if (thisRecord._point)
    {
        if (isEmpty(thisRecord._infoHtml)) widget.map.showBalloonEvent = "";
       
        switch (widget.map.showBalloonEvent)
        {
            case "load":
                widget.data._markerTooltip = "click for more map detail on " + thisRecord.name + "..."
                break;
                
            case "click":
                widget.data._markerTooltip = "click for more on " + thisRecord.name + "...";
                break;
                
            default:
                widget.data._markerTooltip = "click for more map detail on " + thisRecord.name + "...";
                break;
                
        }
        
        // choose Google marker icon
        if (isEmpty(thisRecord.firstName))
        {
            // a company location (not an employee)
            if (imageInitialized(thisRecord._iconImage) & !widget.map.useLogoAsIcon)
            {
                var thisIcon = createMarkerIcon(thisRecord.icon, thisRecord.iconShadow, thisRecord._iconImage, thisRecord._iconShadowImage);
                thisRecord._markerIconType = "icon";
            }
            else if (imageInitialized(thisRecord._logoImage) & widget.map.useLogoAsIcon)
            {
                var thisIcon = createMarkerIcon(thisRecord.logo, thisRecord.logoShadow, thisRecord._logoImage, thisRecord._logoShadowImage);
                thisRecord._markerIconType = "logo";
            }
            else if (!imageInitialized(thisRecord._logoImage))
            {
                var thisIcon = G_DEFAULT_ICON;
                thisRecord._markerIconType = "default";
            }
            else
            {
                var thisIcon = createMarkerIcon(widget.data.invisibleIcon, "", widget.data.invisibleIconImage, "");
                thisRecord._markerIconType = "invisible";
            }
        } else {
            // an employee
            if (hasData(thisRecord.icon))
            {
                var thisIcon = createMarkerIcon(thisRecord.icon, thisRecord.iconShadow, thisRecord._iconImage, thisRecord._iconShadowImage);
                thisRecord._markerIconType = "icon";
            }
            else
            {
                var thisIcon = createMarkerIcon(widget.data.invisibleIcon, "", widget.data.invisibleIconImage, "");
                thisRecord._markerIconType = "invisible";
            }
        }

        // create Google marker
        thisRecord._marker = new GMarker(thisRecord._point, {icon: thisIcon, title: widget.data._markerTooltip, clickable: true, draggable: false, zIndexProcess: function (marker, x) {return 1;}});
        
        thisRecord._marker._SLI_infoHtml = thisRecord._infoHtml;
        thisRecord._marker._SLI_infoHtml2 = thisRecord._infoHtml2;
        
        thisRecord._marker._SLI_index = i;

        var imageOverlay = null;
        var lockToMap = true;
        
        var vectorOverlay = null;
        var textOverlay = null;
        
        // add any images, vector markers and labels to map
        if ((hasData(thisRecord.logo) && thisRecord._markerIconType != "logo") && !widget.map.useLogoAsIcon)
        { 
            imageOverlay = createImageOverlay(map, thisRecord._point, thisRecord._marker, thisRecord._logoImage, thisRecord._logoShadowImage, "bottomRight", lockToMap, false, "imageOverlayLogo");
            vectorOverlay = isEmpty(thisRecord.icon) ? createVectorOverlay(map, thisRecord._point, thisRecord._marker, "center", lockToMap, false, "vectorOverlay") : null;
        }
        else if (hasData(thisRecord.firstName))
        {
            if (!hasData(thisRecord.icon)) vectorOverlay = createVectorOverlay(map, thisRecord._point, thisRecord._marker, "center", lockToMap, false, "vectorOverlay");
            imageOverlay = hasData(thisRecord.photo) ? createImageOverlay(map, thisRecord._point, thisRecord._marker, thisRecord._photoImage, thisRecord._photoShadowImage, "bottomRight", lockToMap, false, "imageOverlayPhoto") : null;
            if (widget.map.showLabels) textOverlay = createTextOverlay(map, thisRecord._point, thisRecord._marker, thisRecord.firstName, "topLeft", lockToMap, false, "textOverlay");
        }
        
        thisRecord._vectorOverlay = vectorOverlay;
        thisRecord._imageOverlay = imageOverlay;
        thisRecord._textOverlay = textOverlay;

        var mapLinks = document.getElementById("maplinks");
        
        if (mapLinks && !hasData(thisRecord.firstName))
        {
            var thisDiv = document.createElement("DIV");
            thisDiv.className = "mapLinkDiv";
            
            var thisLink = document.createElement("A");
            thisLink.href = "#";
            thisLink.className = "mapLink";
            thisLink.onclick = function () {map.setCenter(thisRecord._point, widget.map.zoom); thisRecord._marker.openInfoWindowHtml(thisRecord._infoHtml);};
            
            if (hasData(thisRecord.locationName))
            {
                var thisName = thisRecord.locationName;
            } else {
                var thisName = thisRecord.name;
            }

            thisLink.innerHTML = "<p class='mapLinkLine'>" + thisName + "</p><p class='mapLinkLine'>" + thisRecord.streetAddress + "</p><p class='mapLinkLine'>" + thisRecord.city + ", " + thisRecord.city + " " + thisRecord.zip + "</p>";
                        
            thisDiv.appendChild(thisLink);
            mapLinks.appendChild(thisDiv);
        }
    }
}

function createMarkerIcon(iconImageUrl, iconImageShadowUrl, iconImage, iconImageShadow)
{
    // scale if required
    if (iconImageUrl == widget.data.invisibleIcon)
    {
        var imageWidth = 1;
        var imageHeight = 1;
    } else {
        iconImage = scaleImage(iconImage, widget.data.logoMaxHeight, widget.data.logoMaxWidth);

        var imageWidth = iconImage.width;
        var imageHeight = iconImage.height;
    }

    
    // create the icon using the passed-in urls and calculated dimensions
    var thisIcon = new GIcon();

    thisIcon.image = iconImageUrl;
    thisIcon.shadow = iconImageShadowUrl;
    thisIcon.iconAnchor = new GPoint(Math.round(imageWidth / 4), Math.round(imageHeight / 2));
    thisIcon.infoWindowAnchor = thisIcon.iconAnchor;

    thisIcon.iconSize = new GSize(imageWidth, imageHeight);
    thisIcon.shadowSize = new GSize(imageWidth, imageHeight);
    
    return thisIcon;
}

function createVectorOverlay(map, point, marker, anchor, lockToMap, fixedSize, className)
{
    var vectorOverlay = document.createElement("DIV");
    
    // set the height and width before initializing; Google Maps doesn't like it set later in css
    vectorOverlay.style.height = 3 + "px";
    vectorOverlay.style.width = 3 + "px";
    vectorOverlay.style.position = "absolute";
    
    // store a reference to the marker for access during events
    vectorOverlay.marker = marker;
    
    // read the stylesheets and override defaults if height and width found
    if (hasData(className))
    {
        var classStyles = getStyles(className);
        if (classStyles)
        {
            if (classStyles.width && classStyles.height)
            {
                vectorOverlay.style.height = classStyles.height;
                vectorOverlay.style.width = classStyles.width;
            }
        }
    }
    
    vectorOverlay.className = className;
    
    vectorOverlay.onmouseover = function ()
    {
        setMapInfo(marker);;
    }
    
    vectorOverlay.onclick = function ()
    {
        widget.map.clickedMarker = this.marker;
        
        switch (widget.map.showBalloonEvent)
        {
            case "load":
                complexClick(widget.map.clickedMarker);
                break;
                
            case "click":
                simpleClick(widget.map.clickedMarker);
                break;
                
            default:
                complexClick(widget.map.clickedMarker);
                break;
        }
    }
    
    return new overlayDiv (map, vectorOverlay, point, anchor, lockToMap, fixedSize);
}

function createImageOverlay(map, point, marker, image, imageShadow, anchor, lockToMap, fixedSize, className)
{
    if (imageInitialized(image))
    {
        var thisPoint = point;
        var thisDiv = document.createElement("DIV");
        
        if (hasData(className))
        {
            image.className = className;
            
            var classStyles = getStyles(className);
            if (classStyles)
            {
                // use as needed
            }
        }
        
        var photoHeight;
        var photoWidth;
        var classStyles = getStyles("imageOverlayPhotoSize");
        
        if (classStyles)
        {
            photoHeight = classStyles.height;
            photoWidth = classStyles.width;
        }
        
        photoHeight = (photoHeight) ? parseFloat(photoHeight) : widget.data.photoMaxHeight;
        photoWidth = (photoWidth) ? parseFloat(photoWidth) : widget.data.photoMaxWidth;
        
        image = scaleImage(image, photoHeight, photoWidth);
        imageShadow = scaleImage(imageShadow, photoHeight, photoWidth);
        
        image.style.position = "absolute";
        imageShadow.style.position = "absolute";
        
        var divHeight = image.height;
        var divWidth = image.width;
        
        if (imageInitialized(imageShadow)) thisDiv.appendChild(imageShadow); // must follow all image size calcs; appending prevents image height/width changes
        thisDiv.appendChild(image); 
        
        thisDiv.style.visibility = "hidden";
        thisDiv.style.position = "absolute";
        thisDiv.style.height = divHeight + "px";
        thisDiv.style.width = divWidth + "px";
        
        image.marker = marker;
        
        if (marker)
        {
            image.onmouseover = function ()
            {
                setMapInfo(marker);;
            }

            image.onclick = function ()
            {
                widget.map.clickedMarker = this.marker;
                
                switch (widget.map.showBalloonEvent)
                {
                    case "load":
                        complexClick(widget.map.clickedMarker);
                        break;
                        
                    case "click":
                        simpleClick(widget.map.clickedMarker);
                        break;
                        
                    default:
                        complexClick(widget.map.clickedMarker);
                        break;
                }
            }
        }

        return new overlayDiv (map, thisDiv, thisPoint, anchor, lockToMap, fixedSize);
    } else {
        return null;
    }
}

function createTextOverlay(map, point, marker, text, anchor, lockToMap, fixedSize, className)
{
    if (hasData(text))
    {
        var textNode = document.createTextNode(text);
        var span = document.createElement("SPAN");
        var table = document.createElement("TABLE");
        var tablebody = document.createElement("TBODY");
        var row = document.createElement("TR");
        var cell = document.createElement("TD");
        var div = document.createElement("DIV");

        span.marker = marker;
        
        if (marker)
        {
    
            span.onmouseover = function ()
            {
                setMapInfo(marker);;
            }

            span.onclick = function ()
            {
                widget.map.clickedMarker = this.marker;
                
                switch (widget.map.showBalloonEvent)
                {
                    case "load":
                        complexClick(widget.map.clickedMarker);
                        break;
                        
                    case "click":
                        simpleClick(widget.map.clickedMarker);
                        break;
                        
                    default:
                        complexClick(widget.map.clickedMarker);
                        break;
                }
            }
        }

        var tableWidth;
        var tableHeight;
        var filter;
        var opacity;
        
        if (hasData(className))
        {
            span.className = className;
            
            var classStyles = getStyles(className);
            if (classStyles)
            {
                tableHeight = classStyles.height;
                tableWidth = classStyles.width;
                filter = classStyles.filter;
                opacity = classStyles.opacity;
            }
        }
        
        table.style.height = (tableHeight) ? tableHeight : "100px";
        table.style.width = (tableWidth) ? tableWidth : "100px";
        table.border = "0px";
        
        switch (anchor.toLowerCase())
        {
            case "topleft":
                cell.style.textAlign = "left";
                cell.style.verticalAlign = "top";
                break;
                
            case "topright":
                cell.style.textAlign = "right";
                cell.style.verticalAlign = "top";
                break;
                
            case "bottomleft":
                cell.style.textAlign = "left";
                cell.style.verticalAlign = "bottom";
                break;
                
            case "bottomright":
                cell.style.textAlign = "right";
                cell.style.verticalAlign = "bottom";
                break;
                
            case "center":
                cell.style.textAlign = "center";
                cell.style.verticalAlign = "middle";
                break;
                
            default:
                // same as center
                cell.style.textAlign = "center";
                cell.style.verticalAlign = "middle";
                break;
                
        }
        
        span.appendChild(textNode);
        cell.appendChild(span);
        row.appendChild(cell);
        tablebody.appendChild(row);
        table.appendChild(tablebody);
        div.appendChild(table);
        
        if (filter) table.style.filter = filter;
        if (opacity) table.style.opacity = opacity;
        
        div.style.position = "absolute";
        div.style.height = table.style.height;
        div.style.width = table.style.width;

        return new overlayDiv (map, div, point, anchor, lockToMap, fixedSize);
    } else {
        return null;
    }
}

function addImagesToMap()
{
    try
    {
        for (var i = 0; i < widget.data.clipart.length; i++)
        {
            map.addOverlay(widget.data.clipart[i].overlay);
        }
    }
    catch (ex) {}
}

function addMarkerToMap(thisRecord)
{
    // add the marker
    var thisMarker = thisRecord._marker;
    
    try
    {
        if (thisMarker)
        {
            map.addOverlay(thisMarker);
            
            // add logo overlay, if any
            var thisImageOverlay = thisRecord._imageOverlay;
            if (thisImageOverlay) map.addOverlay(thisImageOverlay);
            
            // add text overlay, if any
            var textOverlay = thisRecord._textOverlay;
            if (textOverlay) map.addOverlay(textOverlay);
            
            // add vector overlay, if any
            var vectorOverlay = thisRecord._vectorOverlay;
            if (vectorOverlay) map.addOverlay(vectorOverlay);
            
            // listen for mouseover event
            
            GEvent.addListener(thisMarker, "mouseover", function()
            {
                setMapInfo(thisMarker);
            });
                    
            // listen for marker events
            
            switch (widget.map.showBalloonEvent)
            {
                case "load":
                    thisMarker.openInfoWindowHtml(thisMarker._SLI_infoHtml);

                    var inputFieldId = "fromAddress";
	            var inputField = document.getElementById(inputFieldId);

                    if (inputField) window.setTimeout("focusOnField('" + inputFieldId + "')", 2000);

                    GEvent.addListener(thisMarker, "click", function()
                    {
                        widget.map.clickedMarker = this;
                        complexClick(widget.map.clickedMarker);
                    });
                    break;
                    
                case "click":
                    GEvent.addListener(thisMarker, "click", function()
                    {
                        widget.map.clickedMarker = this;
                        simpleClick(widget.map.clickedMarker);
                    });
                    break;
                    
                default:
                    // same as click
                    GEvent.addListener(thisMarker, "click", function()
                    {
                        widget.map.clickedMarker = this;
                        simpleClick(widget.map.clickedMarker);
                    });
                    break;
            }
        }
    }
    catch (ex) {}
}

function simpleClick (marker)
{
    marker.openInfoWindowHtml(marker._SLI_infoHtml);

    var thisId = "fromAddress";
    var thisField = document.getElementById(thisId);

    if (thisField) window.setTimeout("focusOnField('" + thisId + "')", 2000);
}

function focusOnField (thisId)
{
    var thisField = document.getElementById(thisId);
    
    try
    {
        thisField.focus();
    }
    catch (ex) {}
}

function complexClick(marker, fromAddress)
{
	var index;
    if (marker) {index = marker._SLI_index;} else {index = 0;}
    
    if (hasData(fromAddress))
    {
        if (hasData(fromAddress))
        {
            window.open("http://maps.google.com/?q=from%20" + fromAddress + "%20to%20" + escape(widget.data.addresses[index]._fullAddress));
        } else {
            window.open("http://maps.google.com/?q=" + escape(widget.data.addresses[index]._fullAddress));
        }
    }
    else if (map.getZoom() <= widget.map.zoom)
    {
        // zoom in, but check country first
        var country = widget.data.addresses[index].country;
        
        if (marker) map.setCenter(marker.getPoint());
        
        if (!country || trim(country) == "united states" ||  trim(country) == "") var zoom = widget.map.zoom; else var zoom = widget.map.nonUsZoom;
        
        map.setZoom(zoom + 1);
    } else {
        // already zoomed in; open Google map
        window.open("http://maps.google.com/?q=" + escape(widget.data.addresses[index]._fullAddress));
    }
}

function setOpacity(element, percent)
{
    if (document.all)
    {
        element.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity="+ percent +");"
    } else{
        element.style.opacity = percent;
    }
}

function handleResponse(key, data)
{
    switch (key)
    {
        case "infoHtmlTemplate":
            applyInfoHtmlTemplate(data);
            break;
    }
}

function applyInfoHtmlTemplate(templateText)
{
    for (var i = 0; i < widget.data.addresses.length; i++)
    {
        var thisTemplate = templateText;
        
        thisTemplate = thisTemplate.replace("[name]", widget.data.addresses[i]._fullName);
        
        thisTemplate = thisTemplate.replace("[address]", widget.data.addresses[i]._balloonAddress);
        
        if (hasData(widget.data.addresses[i].description))
        {
            thisTemplate = thisTemplate.replace("[description]", "<p class='description'>" + widget.data.addresses[i].description + "</p>");
        } else {
            thisTemplate = thisTemplate.replace("[description]", "");
        }
    
        var fieldName = "fromAddress";

        var actionText1 = "doLinkAction(1)";
        var actionText2 = "doLinkAction(2, '" + fieldName + "')";

        thisTemplate = thisTemplate.replace("[fieldId]", fieldName);
        thisTemplate = thisTemplate.replace("[action1]", actionText1);
        thisTemplate = thisTemplate.replace("[action2]", actionText2);
        
        var photoString1;
        var photoString2;
        var thisImage1;
        var thisImage2;
        
        if (imageInitialized(widget.data.addresses[i]._photoImage))
        {
            thisImage2 = scaleImage(widget.data.addresses[i]._photoImage, widget.data.infoBarImageMaxHeight, widget.data.infoBarImageMaxWidth);
            photoString2 = "<img class='infoPhoto' src='" + widget.data.addresses[i].photo + "' style='width: " + thisImage2.width + "px; height: " + thisImage2.height + "px;' alt=''/>";
            
            thisImage1 = scaleImage(widget.data.addresses[i]._photoImage, widget.data.balloonImageMaxHeight, widget.data.balloonImageMaxWidth);
            photoString1 = "<img class='infoPhoto' src='" + widget.data.addresses[i].photo + "' style='width: " + thisImage1.width + "px; height: " + thisImage1.height + "px;' alt=''/>";
        } else {
            photoString1 = ""
            photoString2 = ""
        }
        
        widget.data.addresses[i]._infoHtml = thisTemplate.replace("[photo]", photoString1);
        widget.data.addresses[i]._infoHtml2 = thisTemplate.replace("[photo]", photoString2);
    }
}

function doLinkAction (i, fieldId)
{
    switch (i)
    {
        case 1:
            complexClick(widget.map.clickedMarker);
            window.setTimeout("setInnerHTML('balloonLink1', 'bigger map')", standardTimeout);
            break;
        case 2:
            var field = document.getElementById(fieldId);
            var fromAddressText = (field) ? escape(field.value) : '';
			complexClick(widget.map.clickedMarker, fromAddressText);
            break;
    }
}

function setInnerHTML(name, text)
{
    var elements = document.getElementsByName(name);

    for (var i = 0; i < elements.length; i++)
    {
        elements[i].innerHTML = text;
    }
}

function getHtml(url, key)
{
    xmlhttp = getXmlHttpObject();
    
    xmlhttp.open("GET", url, true);
    xmlhttp.onreadystatechange = function()
    {
        if (xmlhttp.readyState == 4)
        {
            if (xmlhttp.status == 200) handleResponse(key, xmlhttp.responseText);
        }
    }
    
    xmlhttp.send(null)
}

function getXmlHttpObject()
{
    var xmlhttp=false;
    
    /*@cc_on @*/
    /*@if (@_jscript_version >= 5)
    // JScript gives us Conditional compilation, we can cope with old IE versions.
    // and security blocked creation of the objects.
     try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
     } catch (e) {
      try {
       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
       xmlhttp = false;
      }
     }
    @end @*/
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
	    try {
		    xmlhttp = new XMLHttpRequest();
	    } catch (e) {
		    xmlhttp=false;
	    }
    }
    if (!xmlhttp && window.createRequest) {
	    try {
		    xmlhttp = window.createRequest();
	    } catch (e) {
		    xmlhttp=false;
	    }
    }
    
    return xmlhttp;
}

function getTopLeftPixels(map, geoLatLng, height, width, anchor)
{
    var objectPixels = new Array();
    
    if (isNaN(height)) height = 0;
    if (isNaN(width)) width = 0;
    
    if (geoLatLng)
    {
        // convert GLatLng to GPoint
        var geoPixels = map.fromLatLngToDivPixel(geoLatLng);
        
        // calculate initial top, left
        switch (anchor.toLowerCase())
        {
            case "topleft":
                objectPixels.top = geoPixels.y;
                objectPixels.left = geoPixels.x;
                break;

            case "topright":
                objectPixels.top = geoPixels.y;
                objectPixels.left = geoPixels.x - width;
                break;

            case "center":
                objectPixels.top = geoPixels.y - Math.round(height / 2);
                objectPixels.left = geoPixels.x - Math.round(width / 2);
                break;

             case "bottomleft":
                objectPixels.top = geoPixels.y - height;
                objectPixels.left = geoPixels.x;
                break;

            case "bottomright":
                objectPixels.top = geoPixels.y - height;
                objectPixels.left = geoPixels.x - width;
                break;

           default:
                objectPixels.top = geoPixels.y - Math.round(height / 2);
                objectPixels.left = geoPixels.x - Math.round(width / 2);
                break;
        }
    }
    else
    {
        objectPixels.top = 0;
        objectPixels.left = 0;
    }
    
    return objectPixels;
}

function overlayDiv (map, div, latLngPoint, anchor, lockToMap, fixedSize)
{
    // preserve original parameters
    this.map_ = map;
    this.div_ = div;
    this.latLngPoint_ = (latLngPoint != null && latLngPoint != "") ? latLngPoint : null; // GLatLng or empty
    this.anchor_ = anchor;
    this.lockToMap_ = lockToMap;
    this.fixedSize_ = fixedSize;
    
    // preserve original dimensions
    if (this.div_.style.borderWidth) this.weight_ = parseFloat(this.div_.style.borderWidth); else this.weight_ = 0;
    this.height_ = parseFloat(div.style.height) + (2 * this.weight_);
    this.width_ = parseFloat(div.style.width) + (2 * this.weight_);
    
    if (isNaN(this.height_)) this.height_ = 0;
    if (isNaN(this.width_)) this.width_ = 0;
}

overlayDiv.prototype = new GOverlay();

overlayDiv.prototype.initialize = function()
{
    this.map_.getPane(G_MAP_MAP_PANE).appendChild(this.div_);
    
    var pixels = getTopLeftPixels(this.map_, this.latLngPoint_, this.height_, this.width_, this.anchor_); //getTopLeftPixels(map, geoLatLng, height, width, anchor)
    
    // set div top, left
    this.div_.style.top = pixels.top + "px";
    this.div_.style.left = pixels.left + "px";
    
    // preserve original bounds (note: based on zoom level when function is called)
    var topLeft = new GPoint(pixels.left, pixels.top);
    var bottomRight = new GPoint(pixels.left + this.width_, pixels.top + this.height_);
    
    this.initialBounds_ = new GLatLngBounds();
    this.initialBounds_.extend(this.map_.fromDivPixelToLatLng(topLeft));
    this.initialBounds_.extend(this.map_.fromDivPixelToLatLng(bottomRight));
}

overlayDiv.prototype.remove = function()
{
    this.div_.parentNode.removeChild(this.div_);
}

overlayDiv.prototype.copy = function()
{
    return new overlayDiv(this.div_, this.latLngPoint_, this.anchor_, this.lockToMap_, this.fixedSize_);
}

overlayDiv.prototype.redraw = function(force)
{
    if (!force || !this.lockToMap_) return;

    if (this.fixedSize_)
    {
        // maintain a fixed screen pixel size
        var southWestPoint = this.map_.fromLatLngToDivPixel(this.initialBounds_.getSouthWest());
        var northEastPoint = this.map_.fromLatLngToDivPixel(this.initialBounds_.getNorthEast());
        
        var height = Math.abs(southWestPoint.y - northEastPoint.y);
        var width = Math.abs(southWestPoint.x - northEastPoint.x);
    } else {
        // maintain a fixed size relative to original map area
        var height = this.height_;
        var width = this.width_;
    }

    var pixels = getTopLeftPixels(this.map_, this.latLngPoint_, height, width, this.anchor_);
    
    if (height == 0 && width == 0)
    {
        switch (this.anchor_.toLowerCase())
        {
            case "topleft":
                this.div_.style.top = pixels.top + "px";
                this.div_.style.left = pixels.left + "px";
                break;

            case "topright":
                this.div_.style.top = pixels.top + "px";
                this.div_.style.right = pixels.left + "px";
                break;

             case "bottomleft":
                this.div_.style.bottom = pixels.top + "px";
                this.div_.style.left = pixels.left + "px";
                break;

            case "bottomright":
                this.div_.style.bottom = pixels.top + "px";
                this.div_.style.right = pixels.left + "px";
                break;

            case "center":
                // default to topleft
                this.div_.style.top = pixels.top + "px";
                this.div_.style.left = pixels.left + "px";
                break;

           default:
                break;
                // default to topleft
                this.div_.style.top = pixels.top + "px";
                this.div_.style.left = pixels.left + "px";
        }
    }
    else
    {
        this.div_.style.top = pixels.top + "px";
        this.div_.style.left = pixels.left + "px";
        this.div_.style.height = height + "px";
        this.div_.style.width = width + "px";
    }
}

overlayDiv.prototype.borderColor = function(color)
{
    this.div_.style.borderColor = color;
}

function ControlOverlay (logo)
{
    this.logo_ = logo;
}

ControlOverlay.prototype = new GControl();

ControlOverlay.prototype.initialize = function(map) {
    if (this.logo_)
    {
        var container = document.createElement("DIV");

        GEvent.addDomListener(this.logo_, "click", function() {
            // add here
        });

        container.appendChild(this.logo_);
    }

    map.getContainer().appendChild(container);
    return container;
}

ControlOverlay.prototype.getDefaultPosition = function() {
  return new GControlPosition(widget.map.logoPosition, new GSize(7, 7));
}

function isEmpty (variable)
{
    if (variable == null) return true;
    
    variable = trim(variable);
    return (variable == "") ? true : false;
}

function hasData (variable)
{
    return !isEmpty(variable);
}

function trim(value) {
    if (value != true && value != false && value != null && isNaN(parseInt(value)))
    {
        var temp = value;
        var obj = /^(\s*)([\W\w]*)(\b\s*$)/;

        if (obj.test(temp)) { temp = temp.replace(obj, '$2'); }

        var obj = /  /g;

        while (temp.match(obj)) { temp = temp.replace(obj, " "); }

        return temp;
    } else {
        return value;
    }
}

function blockEnterKey (e, id)
{
    if (!e) e = window.event;
    
    key = e.keyCode ? e.keyCode : e.which;
    var enterKey = 13;
    e.returnValue = (key != enterKey);
    if (key == enterKey) doLinkAction(2, id);
}

function scaleImage (image, maxHeight, maxWidth)
{
    if (image.height > 0 && image.width > 0)
    {
        var imageHeight = image.height;
        var imageWidth =  image.width;
        
        var imageAspectRatio = imageHeight/imageWidth;
        
        if (imageAspectRatio >= 1)
        {
            if (imageHeight > maxHeight)
            {
                imageHeight = maxHeight;
                imageWidth = Math.round(imageHeight / imageAspectRatio);
            }
        }
        else
        {
            if (imageWidth > maxWidth)
            {
                imageWidth = maxWidth;
                imageHeight = Math.round(imageWidth * imageAspectRatio);
            }
        }
        
        image.height = imageHeight;
        image.width = imageWidth;
    }
    
    return image;
}

function imageInitialized(image)
{
    // override this function; not working consistently
    return true;

    // During the onload event, IE correctly identifies any images
    // that weren't downloaded as not complete. Others should too.
    // Gecko-based browsers act like NS4 in that they report this
    // incorrectly: they always return true.
    if (!image.complete) {
        return false;
    }

    // However, they do have two very useful properties: naturalWidth
    // and naturalHeight. These give the true size of the image. If
    // it failed to load, either of these should be zero.
    if (typeof image.naturalWidth != "undefined" && image.naturalWidth == 0) {
        return false;
    }

    // No other way of checking: assume it's ok.
    return true;
}

function getStyles (className)
{
    var thisStyle = null;
    
    if (document.styleSheets[0])
    {
        for (var i = 0; i < document.styleSheets.length; i++)
        {
            var styles;

            try
            {
                if (document.styleSheets[i])
                {
                    if (document.styleSheets[i].rules) styles = (document.styleSheets[i].rules); else if (document.styleSheets[i].cssRules) styles = document.styleSheets[i].cssRules;
                }
            }
            catch (ex) {window.status = ex.description;}

            if (styles)
            {
                for (var j = 0; j < styles.length; j++)
                {
                    if (styles[j].selectorText == "." + className)
                    {
                        thisStyle = styles[j].style;
                    }
                }
            }
        }
    }
    
    return thisStyle;
}

function getQuerystringValue(name)
{
    var query = window.location.search.substring(1);
    var vars = query.split("&");

    for (var i = 0; i < vars.length; i++)
    {
        var pair = vars[i].split("=");
        
        if (pair[0] == name)
        {
            return pair[1];
        }
    }
    
    return null;
}

