// Javascript included in the head of the page
// run jsmin.py <head.js >headmin.js after updating this file.
// (C) 2009 DMSBT 

var gMap;
var gGeocoder;
var gDirections;
var gYouAreHereMarker = null;
var gYouAreHereHtml = "set me";
var gYouAreHereIcons = Array();
var gMarkers = Array();
var gCurrentPolygonOverlayArray = Array();
//var gMarkerWithVisibleInfoWindow = null;  // we need to re-show after map move
var gMarkerWithVisibleInfoWindowPoint = null;
var gVisibleInfoWindowHtml = null;
var gMessageBox = null;
// for link and send modal windows
// TODO: get rid of this hack
var MAX_LAYERS = 50;
// some reasonable maximum
var gLoadHelpText = true;

// put a function in here to call after loading markers or polygons
var gPostMarkerReadCall = null;
var gPostPolygonReadCall = null;

// called when the window first opens to build the Google Map
//function load(start_lat, start_lng, start_zoom, baseCountryCode, markerJson) {
function initialise()
 {
    try {
        if (GBrowserIsCompatible()) {

            gMap = new google.maps.Map2(document.getElementById("map"));
            //GLog.write(G_API_VERSION);	// 2.165c
            gMap.setUIToDefault();
            gMap.setMapType(gMapType);
            gGeocoder = new google.maps.ClientGeocoder();
            gGeocoder.setBaseCountryCode(gBaseCountryCode);

            gMap.setCenter(new google.maps.LatLng(gStartLat, gStartLng), gStartZoom);

            //gMap.addControl(new google.maps.LargeMapControl());
            //getIconsJson();
            loadInitialIcons(gInitialIcons);

			if(gInitialMarkersJson && gInitialEncodedPolygonsJson)
			{
            	readMarkers(gInitialMarkersJson);
            	readEncodedPolygons(gInitialEncodedPolygonsJson);
            }
            else
            {
            	updateDisplay();
            }
            // scan the layer checkboxes
            // Call getMarkersJson if the map is moved or zoomed
            GEvent.addListener(gMap, 'moveend', updateDisplay);
            //window.onresize = updateDisplay;

            GEvent.addListener(gMap.getInfoWindow(), "closeclick", infoWindowCloseClick);

            directionsPanel = document.getElementById("listDisplay");
            gDirections = new google.maps.Directions(gMap, directionsPanel);

            /*
	  GEvent.addListener(gMap, "mousemove", function(latlng) 
	  {
	      $('message').update(latlng);
	  });
	  */
            //GEvent.addListener(gMap, "removeoverlay", overlayRemoved);

            // an optional argument
            if (gInitialMarker) 
            {
                // add a you are here marker
                addInitialMarker(gInitialMarker);
                //var jsonMarker = decodeURIComponent(gInitialMarkerJson);
                //addMarkerFromJson(jsonMarker);
            }
            searchAddressField = $('searchAddress');
            // serviceView doesn't have the search field
            if (searchAddressField)
            {
                // If we arrive via resolveLink, the searchAddress is populated
                if ($('searchAddress').value.length > 0) 
                {
                    $('search').click();
                    searchAddressField.focus();
                }
                else
                {
                    searchAddressField.focus();
                }
            }

        }
    } catch(e) {
        showError("Exception in load(): " + e);
    }
    updateLinks();
}

function showError(message) {
    // friendly message
    //message = "Sorry, something went wrong. Please refresh and try again."
    /*
    if($('errormessage'))
	    $('errormessage').update(message);
	*/
	if($('listDisplay'))
    	$('listDisplay').update('');
}

function overlayRemoved() {
    GLog.write("overlayRemoved successfully.");
}

function loadInitialIcons(icons)
 {
    if (icons)
    {
        try {
            for (var i = 0; i < icons.length; i++) {
                // take this opportunity to make the you are here icons
                var name = icons[i].name;
                //console.log("got icon name: " + name);
                var google_icon = new google.maps.Icon();
                google_icon.name = name;
                google_icon.image = icons[i].image;
                google_icon.iconSize = new google.maps.Size(icons[i].width, icons[i].height);
                google_icon.iconAnchor = new google.maps.Point(icons[i].anchorX, icons[i].anchorY);
                google_icon.infoWindowAnchor = new google.maps.Point(icons[i].infoWindowAnchorX, icons[i].infoWindowAnchorY);

                //GLog.write("icon " + name + " width = " + icons[i].width);
                //console.log("adding icon name: " + name);
                gYouAreHereIcons[name] = google_icon;
            }
        } catch(e) {
            showError("Exception in loadInitialIcons(): " + e);
        }
    }
}

// called when the map is zoomed or moved
// requests the markers that are visible
function getMarkersJson(visibleLayers) {
    try {
        //console.log("getMarkersJson(" + iconname + ")");
        // get the visible rectangle
        var bounds = gMap.getBounds();
        var southWest = bounds.getSouthWest();
        var northEast = bounds.getNorthEast();
        var zoom = gMap.getZoom();
        new Ajax.Request('/ajax/getmarkersJson/' + visibleLayers + '/' + northEast.lat() + '/' + northEast.lng() + '/' + southWest.lat() + '/' + southWest.lng() + '/' + zoom, {
            method: 'get',
            asynchronous: true,
            onSuccess: function(request) {
                readMarkersJson(request);
            }
        });
        var loadingDiv = $('loading');
        if(loadingDiv)
        {
        	loadingDiv.show();
        }        
    } catch(e) {
        showError("Exception in getMarkersJson(): " + e);
    }

}

// called back when new markers come back
function readMarkersJson(request) {
    try {
        var jsonMarkers = request.responseText;
        var markers = jsonMarkers.evalJSON();
        // thanks prototype!;
        //console.log("readMarkersJson() got " + markers.length + " markers");
        readMarkers(markers);
    } catch(e) {
        showError("Exception in readMarkersJson(): " + e);
    }
}

// Read the markers from the supplied list
// if a marker with the given pk is already visible, skip it
// if a new marker has arrived, add it to the map and a list
// remove the markers that are no longer visible
function readMarkers(markers) {
	try {
		//GLog.write("readMarkers got markers.length = " + markers.length);
		//GLog.write("gMarkers.length = " + gMarkers.length);
	    var newVisibleMarkers = Array();
	    for (var i = 0, len = markers.length; i < len; ++i) {
	        var marker = markers[i];
	        var pk = marker.pk;
	        var whereInCurrentList = indexOfByPk(gMarkers, pk);
	        if(whereInCurrentList == -1){
	        	// it's a new marker
	        	//GLog.write("adding marker pk = " + pk);
		        var lat = marker.lat;
		        var lng = marker.lng;
		        var name = marker.name + ": " + pk;
		        var point = new google.maps.LatLng(lat, lng);
		        var cluster = marker.cluster;
		        var icon = readIconJson(marker.icon, (cluster > 1));
		        var html = marker.infowindowhtml;
		        var markerOptions = {
		            icon: icon,
		            title: name,
		            draggable: true
		        };
		        google_marker = createMarker(point, name, pk, html, markerOptions);
		        google_marker.disableDragging();
		        gMap.addOverlay(google_marker);
		        newVisibleMarkers.push(google_marker);
	        } else {
	        	// it's a marker that's aready displayed, so skip it
		        // remove from the current list
		        newVisibleMarkers.push(gMarkers[whereInCurrentList]);
		        //gMarkers.slice(whereInCurrentList,1);
		        gMarkers[whereInCurrentList] = null;
		        //GLog.write("keeping marker pk = " + pk);
	        }
	    }
	    // now remove any remaining markers from the old list
	    for (var i = 0, len = gMarkers.length; i < len; ++i) {
	    	var marker = gMarkers[i];
	    	if(marker){
	    		//GLog.write("removing marker pk = " + marker.pk);
	    		gMap.removeOverlay(marker);
	    	}
	    }
	    //GLog.write("After newVisibleMarkers.length = " + gMarkers.length);
	    gMarkers = newVisibleMarkers.slice();
	    //GLog.write("After gMarkers.length = " + gMarkers.length);
	    if (gPostMarkerReadCall)
	    {
	        gPostMarkerReadCall();
	    }
	    var loadingDiv = $('loading');
	    if(loadingDiv)
	    {
	    	loadingDiv.hide();
	    }
	    /*
	    if (!window.location.pathname.startsWith("/ServiceView/")){
	        if (gYouAreHereMarker != null) {
	            newVisibleMarkers.push(gYouAreHereMarker);
	        }            
	    }
	    */
	    if(gYouAreHereMarker)
	    {
    		gMap.addOverlay(gYouAreHereMarker);
	    }
	    
	} catch(e) {
		showError("Exception in readMarkers = " + e);
	}
} // end of readMarkers


// scan the array of objects with a pk field
// return the position where the given pk was found
// or -1 if not found
function indexOfByPk(array, pk) {
	for (var index = 0, len = array.length; index < len; ++index) {
		var currentMarker = array[index];
		if(currentMarker){
			var currentPk = currentMarker.pk;
			//GLog.write("comparing " + currentPk + " = " + pk);
			if(currentPk == pk) {
				return index;
			} 
		}
	}
	return -1;
}

// used for adding a you are here marker
function addInitialMarker(marker) {
    //GLog.write("addInitialMarker()");
    try {
        var lat = marker.lat;
        var lng = marker.lng;
        var name = marker.name;
        var point = new google.maps.LatLng(lat, lng);
        var cluster = marker.cluster;
        var icon = new google.maps.Icon();
        icon.name = marker.icon.name;
        icon.image = marker.icon.image;
        icon.transparent = marker.icon.image;
        icon.iconSize = new google.maps.Size(marker.icon.width, marker.icon.height);

        icon.iconAnchor = new google.maps.Point(marker.icon.anchorX, marker.icon.anchorY);
        icon.infoWindowAnchor = new google.maps.Point(marker.icon.infoWindowAnchorX, marker.icon.infoWindowAnchorY);

        var html = decodeURIComponent(marker.infowindowhtml);
        var markerOptions = {
            icon: icon,
            title: name,
            draggable: true
        };

        gYouAreHereMarker = new google.maps.Marker(point, markerOptions);
        GEvent.addListener(gYouAreHereMarker, 'click',
        function() {
            var opts = {
                maxWidth: 100
            };
            gYouAreHereMarker.openInfoWindowHtml(html, opts);
            //gMarkerWithVisibleInfoWindowPoint = marker.getLatLng();
        });

        //GLog.write("addMarkerFromJson created marker");
        // gYouAreHereMarker = createMarker(point, name, pk, html, markerOptions);
        GEvent.addListener(gYouAreHereMarker, "dragend", gYouAreHereMarkerDragEnd);
        gMap.addOverlay(gYouAreHereMarker);
        var opts = new Object();
        opts.maxWidth = 100;
        gYouAreHereHtml = html;
        gYouAreHereMarker.openInfoWindowHtml(html, opts);
    } catch(e) {
        showError("Exception in addMarkerFromJson(): " + e);
    }
}

function createMarker(point, name, pk, html, markeroptions) {
    try {
        //console.log(markeroptions);
        //GLog.write("createMarker() " + name + " draggable = " + markeroptions.draggable);
        var marker = new google.maps.Marker(point, markeroptions);
        //marker.name = name;
        marker.pk = pk;
        // marker.disableDragging(); // edit may turn it back on
        google.maps.Event.addListener(marker, 'click',
        function() {
            var opts = new Object();
            opts.maxWidth = 100;
            marker.openInfoWindowHtml(html, opts);
            //gMarkerWithVisibleInfoWindow = marker;  // save for re-open after move
            gMarkerWithVisibleInfoWindowPoint = marker.getLatLng();
            //gVisibleInfoWindowHtml = html;
        });

        /*
       // TODO: There's a bug here
      if (gMarkerWithVisibleInfoWindowPoint != null)
      {
	  var newPoint = marker.getLatLng();
	  if(newPoint.equals(gMarkerWithVisibleInfoWindowPoint))
	  {
	    console.log("re-opening info window");
	    var opts = new Object();
	    opts.maxWidth = 100;
	    marker.openInfoWindowHtml(html, opts);
	  }
      }
      */
        return marker;
    } catch(e) {
        showError("Exception in createMarker(): " + e);
        //console.log("Exception in createMarker(): " + e);
    }
    return null;
}

/*
function createMarkerSimpler(point, name, html, markeroptions) {
    GLog.write("createMarkerSimpler() " + name);
  try {
    var marker = new google.maps.Marker(point, markeroptions);
    marker.name = name;
    google.maps.Event.addListener(marker, 'click',
    function() {
      var opts = new Object();
      opts.maxWidth = 100;
      marker.openInfoWindowHtml(html, opts);
    });

    return marker;
  } catch(e) {
    showError("Exception in createMarker(): " + e);
    //console.log("Exception in createMarker(): " + e);
  }
  return null;
}
*/

// take an icon object in json and create a google icon from it
function readIconJson(jsonIcon, isClustered) {
    try {
        var icon = new google.maps.Icon();
        var javaIcon = jsonIcon.evalJSON();
        icon.name = javaIcon.name;
        icon.image = javaIcon.image;
        icon.transparent = javaIcon.image;
        var cluster_magnify = 0.7;
        if (isClustered) {
            icon.iconSize = new google.maps.Size(javaIcon.width * cluster_magnify, javaIcon.height * cluster_magnify);
        } else {
            icon.iconSize = new google.maps.Size(javaIcon.width, javaIcon.height);
        }
        icon.iconAnchor = new google.maps.Point(javaIcon.anchorX, javaIcon.anchorY);
        icon.infoWindowAnchor = new google.maps.Point(javaIcon.infoWindowAnchorX, javaIcon.infoWindowAnchorY);
        //console.log(icon);
        return icon;
    } catch(e) {
        showError("Exception in readIconJson(): " + e);
    }
    return null;
}

function infoWindowCloseClick() {
    //gMarkerWithVisibleInfoWindow = null;
    gVisibleInfoWindowHtml = null;
    gMarkerWithVisibleInfoWindowPoint = null;
}

// retrieve HTML out for displaying in InfoWindow
// Checking of coverage will be done server side
function getInfoWindowDisplay(place, markerLat, markerLng, accuracy) {
    try {
        // get the visible rectangle
        var bounds = gMap.getBounds();
        var southWest = bounds.getSouthWest();
        var northEast = bounds.getNorthEast();
        var coverageLayer = gVisibleLayers;
        //var getVars = northEast.toUrlValue() + "/" + southWest.toUrlValue();
        //var accuracy = place.AddressDetails.Accuracy;
        new Ajax.Request('/ajax/getInfoWindowDisplay/' + place.address + '/' + coverageLayer + ",/" + markerLat + '/' + markerLng + '/' + northEast.lat() + '/' + northEast.lng() + '/' + southWest.lat() + '/' + southWest.lng() + '/' + accuracy, {
            method: 'get',
            asynchronous: true,
            onSuccess: getInfoWindowDisplaySuccess
        });
    } catch(e) {
        showError("Exception in getInfoWindowDisplay(): " + e);
    }

}

function getInfoWindowDisplaySuccess(request) {
    markerFromJson(request.responseText);
}

function markerFromJson(markerJson) {
    try {
        var markerInfo = markerJson.evalJSON();
        var iconName = markerInfo['iconName'];
        var infoWindowHtml = markerInfo['infoWindowHtml'];

        var google_icon = gYouAreHereIcons[iconName];
        var point = gYouAreHereMarker.getLatLng();

        gMap.removeOverlay(gYouAreHereMarker);
        var markerOptions = {
            icon: google_icon,
            draggable: true
        };
        gYouAreHereMarker = new google.maps.Marker(point, markerOptions);
        GEvent.addListener(gYouAreHereMarker, 'click',
        function() {
            var opts = {
                maxWidth: 100
            };
            gYouAreHereMarker.openInfoWindowHtml(infoWindowHtml, opts);
            //gMarkerWithVisibleInfoWindowPoint = marker.getLatLng();
        });
        GEvent.addListener(gYouAreHereMarker, "dragend", gYouAreHereMarkerDragEnd);
        gMap.addOverlay(gYouAreHereMarker);
        gYouAreHereHtml = infoWindowHtml;
        gYouAreHereMarker.openInfoWindowHtml(infoWindowHtml);
        listDisplayDiv = $('listDisplay');
        if (listDisplayDiv)
        {
            listDisplayDiv.innerHTML = "";
        }

        //GLog.write(markerInfo.address);
        if (markerInfo.inCoverage != true) {
            // check to see if we are close enough to coverage to move there
            var accuracy = markerInfo['accuracy'];
            var lat = point.lat();
            var lng = point.lng();
            var address = markerInfo['address'];
            address = address.replace("/", "_");
            var url = '/ajax/checkNearCoverage/' + lat + '/' + lng + '/' + accuracy + '/' + URLEncode(address);
            new Ajax.Request(url, {
                method: 'get',
                asynchronous: false,
                onSuccess: function(request) {
                    checkNearCoverageResult(request);
                }
            });
        }
    } catch(e) {
        showError("Exception in markerFromJson(): " + e);
    }
}


/////////////////////////////////////////////////////////////////////////////////////
// called when the map is zoomed or moved
// requests the polygon markers that are visible
function getPolygonsJson(visibleLayers) {
    try {
        // get the visible rectangle
        var bounds = gMap.getBounds();
        var southWest = bounds.getSouthWest();
        var northEast = bounds.getNorthEast();
        var getVars = northEast.toUrlValue() + "/" + southWest.toUrlValue();
        new Ajax.Request('/ajax/getpolygonsJson/' + visibleLayers + '/' + northEast.lat() + '/' + northEast.lng() + '/' + southWest.lat() + '/' + southWest.lng() + '/' + gMap.getZoom(), {
            method: 'get',
            asynchronous: true,
            onSuccess: function(request) {
                readPolygonsJson(request);
            }
        });
        var loadingDiv = $('loading');
        if(loadingDiv)
        {
        	loadingDiv.show();
        }
    } catch(e) {
        showError("Exception in getPolygonsJson(): " + e);
    }
}

function readPolygonsJson(request) {
    try {
        // we get back a list of polygons with polygon_points within them
        var jsonMarkers = request.responseText;
        var polygons = jsonMarkers.evalJSON();
        // thanks prototype!;
        readPolygons(polygons);
    } catch(e) {
        showError("Exception in readPolygonsJson(): " + e);
    }
}
    
function readPolygons(polygons) {
	try {
		//GLog.write("Received polygons.length =" + polygons.length);
		//GLog.write("Received gCurrentPolygonOverlayArray.length =" + gCurrentPolygonOverlayArray.length);
	    var polygon_list = Array();
	    for (var i = 0, len = polygons.length; i < len; ++i) {
	    	var aPolygon = polygons[i];
	        var pk = aPolygon.pk;
	        var whereInCurrentList = indexOfByPk(gCurrentPolygonOverlayArray, pk);
	        if(whereInCurrentList == -1) {
		        var layer = aPolygon.layer;
		        var name = aPolygon.name;
		        var strokeColor = aPolygon.strokeColor;
		        var strokeWeight = aPolygon.strokeWeight;
		        var strokeOpacity = aPolygon.strokeOpacity;
		        var fillColor = aPolygon.fillColor;
		        var fillOpacity = aPolygon.fillOpacity;
		        var polygon_points = aPolygon.polygon_points;
		        var latLngList = new Array();
		        //console.log("found " + polygon_points.length + " points");
		        for (var j = 0; j < polygon_points.length; j++) {
		            var lat = polygon_points[j].lat;
		            var lng = polygon_points[j].lng;
		            latLngList.push(latLng = new google.maps.LatLng(lat, lng));
		        }
		        latLngList.push(latLngList[0]);
		        // close the polygon
		        polygon = new google.maps.Polygon(latLngList, strokeColor, strokeWeight, strokeOpacity, fillColor, fillOpacity);
		        polygon.name = name;
		        polygon.pk = pk;
		        //GLog.write("adding polygon.pk = " + pk);
		        gMap.addOverlay(polygon);
		        polygon_list.push(polygon);
	        } else {
	        	polygon_list.push(gCurrentPolygonOverlayArray[whereInCurrentList]);
	        	gCurrentPolygonOverlayArray[whereInCurrentList] = null;
	        }
	    }
		// now remove any remaining markers from the old list
	    for (var i = 0, len = gCurrentPolygonOverlayArray.length; i < len; ++i) {
	    	var polygon = gCurrentPolygonOverlayArray[i];
	    	if(polygon){
	    		//GLog.write("removing polygon pk = " + polygon.pk);
	    		gMap.removeOverlay(polygon);
	    	}
	    }
	    gCurrentPolygonOverlayArray = polygon_list.slice();
	    //GLog.write("After gCurrentPolygonOverlayArray.length =" + gCurrentPolygonOverlayArray.length);
	    var loadingDiv = $('loading');
	    if(loadingDiv)
	    {
	        loadingDiv.hide();
	    }
	    
	    // if we are in basestation view, restore the you are here basestation marker
	    if(window.location.pathname.startsWith("/ServiceView/basestation/"))
	    {
	    	if(gYouAreHereMarker)
	    	{
	            gMap.removeOverlay(gYouAreHereMarker);
	    		gMap.addOverlay(gYouAreHereMarker);
	    		gYouAreHereMarker.openInfoWindowHtml(gYouAreHereHtml);
	    		// open the info window again?
	    	}
	    }
	    if (gPostPolygonReadCall)
	    {
	        gPostPolygonReadCall();
	    }
	} catch(e) {
		showError("Exception in readPolygons: " + e);
	}
}

// Version of the above that uses encoded polygons for speed
function getEncodedPolygonsJson(visibleLayers) {
    try {
        // get the visible rectangle
        var bounds = gMap.getBounds();
        var southWest = bounds.getSouthWest();
        var northEast = bounds.getNorthEast();
        var getVars = northEast.toUrlValue() + "/" + southWest.toUrlValue();
        new Ajax.Request('/ajax/getEncodedPolygonsJson/' + visibleLayers + '/' + northEast.lat() + '/' + northEast.lng() + '/' + southWest.lat() + '/' + southWest.lng() + '/' + gMap.getZoom(), {
            method: 'get',
            asynchronous: true,
            onSuccess: function(request) {
                readEncodedPolygonsJson(request);
            }
        });
        var loadingDiv = $('loading');
        if(loadingDiv)
        {
        	loadingDiv.show();
        }
    } catch(e) {
        showError("Exception in getPolygonsJson(): " + e);
    }
}

function readEncodedPolygonsJson(request) {
    try {
        // we get back a list of polygons with polygon_points within them
        var jsonMarkers = request.responseText;
        var polygons = jsonMarkers.evalJSON();
        // thanks prototype!;
        readEncodedPolygons(polygons);
    } catch(e) {
        showError("Exception in readEncodedPolygons(): " + e);
    }
}

function readEncodedPolygons(polygons) {
	try {
		//GLog.write("Received polygons.length =" + polygons.length);
		//GLog.write("Received gCurrentPolygonOverlayArray.length =" + gCurrentPolygonOverlayArray.length);
	    var polygon_list = Array();
	    for (var i = 0, len = polygons.length; i < len; ++i) {
	    	var aPolygon = polygons[i];
	        var pk = aPolygon.pk;
	        var whereInCurrentList = indexOfByPk(gCurrentPolygonOverlayArray, pk);
	        if(whereInCurrentList == -1) {
		        var layer = aPolygon.layer;
		        var name = aPolygon.name;
		        var strokeColor = aPolygon.strokeColor;
		        var strokeWeight = aPolygon.strokeWeight;
		        var strokeOpacity = aPolygon.strokeOpacity;
		        var fillColor = aPolygon.fillColor;
		        var fillOpacity = aPolygon.fillOpacity;
		        var encoded_points_str = aPolygon.encoded_points_str;
		        var encoded_levels_str = aPolygon.encoded_levels_str;
		        var zoomFactor = 32;
		        var numLevels = 4;
		        //GLog.write(encoded_points_str);
		        polygon = new google.maps.Polygon.fromEncoded({ polylines: 
		        												[{color: strokeColor, 
		        												weight: strokeWeight, 
		        												opacity: strokeOpacity, 
		        												points: encoded_points_str, 
		        												zoomFactor: zoomFactor, 
		        												levels: encoded_levels_str, 
		        												numLevels: numLevels}],
		        												fill: true,
																color: fillColor,
																opacity: fillOpacity,
																outline: true })
		        
		        polygon.name = name;
		        polygon.pk = pk;
		        //GLog.write("adding polygon.pk = " + pk);
		        gMap.addOverlay(polygon);
		        polygon_list.push(polygon);
	        } else {
	        	polygon_list.push(gCurrentPolygonOverlayArray[whereInCurrentList]);
	        	gCurrentPolygonOverlayArray[whereInCurrentList] = null;
	        }
	    }
		// now remove any remaining markers from the old list
	    for (var i = 0, len = gCurrentPolygonOverlayArray.length; i < len; ++i) {
	    	var polygon = gCurrentPolygonOverlayArray[i];
	    	if(polygon){
	    		//GLog.write("removing polygon pk = " + polygon.pk);
	    		gMap.removeOverlay(polygon);
	    	}
	    }
	    gCurrentPolygonOverlayArray = polygon_list.slice();
	    //GLog.write("After gCurrentPolygonOverlayArray.length =" + gCurrentPolygonOverlayArray.length);
	    var loadingDiv = $('loading');
	    if(loadingDiv)
	    {
	        loadingDiv.hide();
	    }
	    
	    // if we are in basestation view, restore the you are here basestation marker
	    if(window.location.pathname.startsWith("/ServiceView/basestation/"))
	    {
	    	if(gYouAreHereMarker)
	    	{
	            gMap.removeOverlay(gYouAreHereMarker);
	    		gMap.addOverlay(gYouAreHereMarker);
	    		gYouAreHereMarker.openInfoWindowHtml(gYouAreHereHtml);
	    		// open the info window again?
	    	}
	    }
	    if (gPostPolygonReadCall)
	    {
	        gPostPolygonReadCall();
	    }
	} catch(e) {
		showError("Exception in readPolygons: " + e);
	}
}

// clicked a checkbox in a layer
function layerCheckChange() {
    updateDisplay();
}

// look at the layer checkboxes and request markers and polygons
// for enabled layers
function updateDisplay() {
    try {
        var visibleLayers = Array();
        for (var i = 0; i < MAX_LAYERS; i++) {
            var checkBoxId = "layerCheck_" + i;
            //console.log("checkBoxId = " + checkBoxId);
            try {
                if ($(checkBoxId).checked == true) {
                    visibleLayers.push(i);
                }
            } catch(TypeError) {
                //console.log("no checkbox id" + i);
                }
        }
        gVisibleLayers = visibleLayers;
		if(visibleLayers == "")
        	visibleLayers = ",";
		
        getMarkersJson(visibleLayers);
        // getPolygonsJson(visibleLayers);
        getEncodedPolygonsJson(visibleLayers);

    } catch(e) {
        showError("Exception in updateDisplay(): " + e);
    }
    updateLinks();
}

// update the urls in the map and edit links
function updateLinks() {
	if ($('editLink'))
    {
        $('editLink').href = "/edit/" + gMap.getCenter().lat() + "/" + gMap.getCenter().lng() + "/" + gMap.getZoom();
    }
    if ($('mapLink'))
    {
        $('mapLink').href = "/" + gMap.getCenter().lat() + "/" + gMap.getCenter().lng() + "/" + gMap.getZoom();
    }
}
// this is called when the user stops dragging the I am here marker
// It receives the GLatLng object
function gYouAreHereMarkerDragEnd(latlng) {
    try {
        if (gDirections != null) {
            gDirections.clear();
        }
        gGeocoder.getLocations(latlng, showDraggedAddress);
    } catch(e) {
        showError("Exception in gYouAreHereMarkerDragEnd(): " + e);
    }

}

// Called after a reverse geocode
function showDraggedAddress(response) {
    try {
        if (!response || response.Status.code != 200) {
            showError("Error reverse geocoding: " + response.Status.code);
            //alert("Status Code:" + response.Status.code);
        } else {
            place = response.Placemark[0];
            var searchAddressField = $('searchAddress');
            if (searchAddressField)
            {
                searchAddressField.value = place.address;
            }
            var latlng = gYouAreHereMarker.getLatLng();
            lat = latlng.lat();
            lng = latlng.lng();
            //GLog.write("showDraggedAddress latlng = " + lat + ", " + lng);
            var address = place.address;
            address = address.replace("/", "_");
            address = URLEncode(address);
            var accuracy = 11;
            // we dragged so it's accurate
            getInfoWindowDisplay(place, lat, lng, accuracy);
            listDisplayDiv = $('listDisplay');
            if (listDisplayDiv)
            {
                listDisplayDiv.update('<p align=\'center\'>Checking coverage...</p><br/><br/><br/><br/><p align=\'center\'><img src=\'/site_media/img/loading.gif\'></p>');
            }
        }
    } catch(e) {
        showError("Exception in showDraggedAddress(): " + e);
    }

}

function URLEncode(clearString) {
    try {
        var output = '';
        var x = 0;
        clearString = clearString.toString();
        var regex = /(^[a-zA-Z0-9_.]*)/;
        while (x < clearString.length) {
            var match = regex.exec(clearString.substr(x));
            if (match != null && match.length > 1 && match[1] != '') {
                output += match[1];
                x += match[1].length;
            } else {
                if (clearString[x] == ' ') output += '+';
                else {
                    var charCode = clearString.charCodeAt(x);
                    var hexVal = charCode.toString(16);
                    output += '%' + (hexVal.length < 2 ? '0': '') + hexVal.toUpperCase();
                }
                x++;
            }
        }
        return output;
    } catch(e) {
        showError("Exception in URLEncode(): " + e);
    }
    return "Error";
}

// Called when user searches for an address
function searchAddress(address) {
    try {
        //console.log("searchAddress(" + address + ")");
        checkWellKnownPlace(address);
    } catch(e) {
        showError("Exception in searchAddress(): " + e);
    }
}

function askGoogle(address) {
    try {
        //console.log("searchAddress(" + address + ")");
        if (address.toLowerCase().indexOf("malaysia") == -1) address += ", Malaysia";
        gGeocoder.getLocations(address, getLocationHandler);
        statusMessage = '<p align=\'center\'>Searching for "';
        statusMessage += address;
        statusMessage += '"...</p><br/><br/><br/><br/><p align=\'center\'><img src=\'/site_media/img/loading.gif\'></p>';
        if($('listDisplay'))
        {
        	$('listDisplay').update(statusMessage);
        }
    } catch(e) {
        showError("Exception in askGoogle(): " + e);
    }
}

function checkWellKnownPlace(address) {
    new Ajax.Request('/ajax/checkWellKnownPlace/' + address, {
        method: 'get',
        asynchronous: false,
        onSuccess: function(request) {
            result = request.responseText.evalJSON();
            if (result.found)
            {
                showWellKnownPlace(result.lat, result.lng, result.address, result.accuracy);
            }
            else
            {
                askGoogle(address);
            }
        }
    });
}

function showWellKnownPlace(lat, lng, address, accuracy)
 {
    try {
        gDirections.clear();
        if (gYouAreHereMarker != null) {
            gMap.removeOverlay(gYouAreHereMarker);
            gYouAreHereMarker = null;
        }
        var point = new google.maps.LatLng(lat, lng);

        var boundsSpan = gMap.getBounds().toSpan();
        var mapCentreLatLng = new google.maps.LatLng(point.lat() + (boundsSpan.lat() / 3.0), point.lng());

        gMap.setCenter(mapCentreLatLng);
        gMap.setZoom(16);
        var iconName = "person";
        var markerOptions = {
            icon: gYouAreHereIcons[iconName],
            draggable: true
        };
        gYouAreHereMarker = new google.maps.Marker(point, markerOptions);
        GEvent.addListener(gYouAreHereMarker, "dragend", gYouAreHereMarkerDragEnd);
        gMap.addOverlay(gYouAreHereMarker);
        if($('listDisplay'))
        {
        	$('listDisplay').update('<p align=\'center\'>Checking coverage...</p><br/><br/><br/><br/><p align=\'center\'><img src=\'/site_media/img/loading.gif\'></p>');
        }
        var place = {
            "address": address
        };
        getInfoWindowDisplay(place, lat, lng, accuracy);
        if($('searchAddress'))
        	$('searchAddress').value = address;
        
        if($('searchLatlng'))
        	$('searchLatlng').innerHTML = lat + "," + lng;
        	
        if($('listDisplay'))
	        $('listDisplay').innerHTML = "";
        //$("latlng").innerHTML = lat + "," + lng;
    }
    catch(e)
    {
        showError("Exception in showWellKnownPlace(): " + e);
    }
}

// Called back after google geocodes the searched address
function getLocationHandler(response) {
    try {
        // GLog.write("getLocationHandler()");
        if (!response || response.Status.code != 200) {
            $("listDisplay").innerHTML = "Error: " + response.Status.code + " Address not found";
        } else {
            gDirections.clear();
            if (gYouAreHereMarker != null) {
                gMap.removeOverlay(gYouAreHereMarker);
                gYouAreHereMarker = null;
            }
            if (response.Placemark.length == 1) {
                var place = response.Placemark[0];
                var accuracy = place.AddressDetails.Accuracy;
                var point = new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]);

                var boundsSpan = gMap.getBounds().toSpan();
                var mapCentreLatLng = new google.maps.LatLng(point.lat() + (boundsSpan.lat() / 3.0), point.lng());

                gMap.setCenter(mapCentreLatLng);
                gMap.setZoom(16);
                var iconName = "person";
                var markerOptions = {
                    icon: gYouAreHereIcons[iconName],
                    draggable: true
                };
                gYouAreHereMarker = new google.maps.Marker(point, markerOptions);
                GEvent.addListener(gYouAreHereMarker, "dragend", gYouAreHereMarkerDragEnd);
                gMap.addOverlay(gYouAreHereMarker);
                if($('listDisplay'))
	                $('listDisplay').update('<p align=\'center\'>Checking coverage...</p><br/><br/><br/><br/><p align=\'center\'><img src=\'/site_media/img/loading.gif\'></p>');
                getInfoWindowDisplay(place, place.Point.coordinates[1], place.Point.coordinates[0], accuracy);
                if($('searchAddress'))
	                $('searchAddress').value = place.address;
	                
	            if($('listDisplay'))
                	$('listDisplay').innerHTML = "";
            } else {
                // more than one came back, show the did you mean
                var html = "<div id='sideTopBar'>Did you mean:</div>";
                html += "<table class=\"listtable\"><tr class=\"listtable\" onmouseover=\"style.backgroundColor='#bbcbff';\" onmouseout=\"style.backgroundColor='#FFFFFF'\">";
                for (var i = 0; i < response.Placemark.length; i++) {
                    anAddress = response.Placemark[i].address;

                    html += "<td class=\"listicon\"><img src=\"/site_media/img/didyoumeanicon.gif\"/></td>";
                    html += "<td class=\"listtext\">";
                    html += "<a href='javascript:void(0);' onclick=handleDidYouMeanClick(\"";
                    // I don't know why I need to urlencode this but I do
                    html += URLEncode(anAddress);
                    html += "\");>";
                    html += anAddress;
                    html += "</a></td></tr>";
                }
                html += "</table>";
                $('listDisplay').innerHTML = html;
            }
        }
    } catch(e) {
        showError("Exception in getLocationHandler(): " + e);
    }
    if($('searchAddress'))
    {
    	$('searchAddress').focus();
    	$('searchAddress').select();
    }
}

// If we were outside coverage but close enough and the search
// accuracy was below the threshold, we can move to coverage
function checkNearCoverageResult(request) {
    try {
        var closeInfo = request.responseText.evalJSON();
        if (closeInfo.shouldMove == 1) {
            point = new google.maps.LatLng(closeInfo.lat, closeInfo.lng);
            var google_icon = gYouAreHereIcons[closeInfo.iconName];
            //var point = gYouAreHereMarker.getLatLng();
            gMap.removeOverlay(gYouAreHereMarker);
            var markerOptions = {
                icon: google_icon,
                draggable: true
            };
            gYouAreHereMarker = new google.maps.Marker(point, markerOptions);
            GEvent.addListener(gYouAreHereMarker, "dragend", gYouAreHereMarkerDragEnd);
            gMap.addOverlay(gYouAreHereMarker);
            gYouAreHereMarker.openInfoWindowHtml(closeInfo.infoWindowHtml);
        }

        //console.log("checkNearCoverageResult()");
    } catch(e) {
        showError("Exception in checkNearCoverageResult(): " + e);
    }

}

function handleDidYouMeanClick(address) {
    try {
        $('searchAddress').value = urldecode(address);
        $('search').click();
    } catch(e) {
        showError("Exception in handlDidYouMeanClick(): " + e);
    }
}

function urldecode(str) {
    return unescape(str);
}

function checkReturnKey(e) {
    try {
        //console.log("checkReturnKey()");
        var keynum;
        if (window.event)
        // IE
        {
            keynum = e.keyCode;
        } else if (e.which)
        // Netscape/Firefox/Opera
        {
            keynum = e.which;
        }
        if (keynum == 13) {
            var Button1 = document.getElementById("search");
            Button1.click();
        }
    } catch(e) {
        showError("Exception in checkReturnKey(): " + e);
    }

}

// show a modal window for send or copy link to the current map
function showLinkBox() {
    try {
        var center = gMap.getCenter();
        var portString = "";
        if(window.location.port != "")
        	portString = ":" + window.location.port;
        var link = window.location.hostname + portString;
        link += '/locations/resolveLink/' + center.lat() + '/' + center.lng() + '/' + gMap.getZoom();
        link += '/' + URLEncode($('searchAddress').value);
        Modalbox.show('/ajax/getLinkCopyBox/' + link, {
            title: 'Copy link and paste into <b >email</b> or <b>IM</b>:'
        });
    } catch(e) {
        showError("Exception in showLinkBox(): " + e);
    }
}

// show a modal window for send or copy link to the current map
function showLinkSendBox() {
    try {
        var center = gMap.getCenter();
        var portString = "";
        if(window.location.port != "")
        	portString = ":" + window.location.port;
        var link = window.location.hostname + portString;
        link += '/locations/resolveLink/' + center.lat() + '/' + center.lng() + '/' + gMap.getZoom();
        link += '/' + URLEncode($('searchAddress').value);
        Modalbox.show('/ajax/getLinkSendBox/' + link, {
            title: 'Send a link to this page by email',
            width: 380
        });
    } catch(e) {
        showError("Exception in showLinkSendBox(): " + e);
    }

}

// Functions used for directions
function askFromDirections(populateFrom) {
    try {
        // this is called from the initial you are here infowindow
        // and also the reseller window
        // user clicked get directions to here, so we need to ask where from
        $('offerDirections').hide();
        $('directions').show();
        // if the reseller window, pre-populate with the original search address
        if (populateFrom) {
            $('fromaddr').value = $("searchAddress").value;
        }
        $('fromaddr').focus();
        // put the cursor in the field
        $('fromaddr').select();
        // select all
    } catch(e) {
        showError("Exception in askFromDirections(): " + e);
    }
}

// called when google directions returns
// I use this to clear the loading animation
function onGDirectionsLoad() {
    try {
        //alert("onGDirectionsLoad2()");
        // Use this function to access information about the latest load()
        // results.
        // remove the loading and replace it with our header
        //$("listDisplay").innerHTML = gDirections.getStatus().code;
        gMap.closeInfoWindow();
        $("listDisplay").update("<div class=\"listTopBar\">Driving Directions:</div>");
    } catch(e) {
        showError("Exception in onGDirectionsLoad(): " + e);
    }

}

// handle and display google directions error.
function onDirectionsError() {
    //alert("directionsError()");
    var errorString = '';
    if (gDirections.getStatus().code == G_GEO_UNKNOWN_ADDRESS) errorString = "Error, no corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + gDirections.getStatus().code;
    else if (gDirections.getStatus().code == G_GEO_SERVER_ERROR) errorString = "Error: geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + gDirections.getStatus().code;

    else if (gDirections.getStatus().code == G_GEO_MISSING_QUERY) errorString = "The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + gDirections.getStatus().code;

    //   else if (gDirections.getStatus().code == G_UNAVAILABLE_ADDRESS)  <--- Doc bug... this is either not defined, or Doc is wrong
    //     alert("The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.\n Error code: " + gDirections.getStatus().code);
    else if (gDirections.getStatus().code == G_GEO_BAD_KEY) errorString = "The given key is either invalid or does not match the domain for which it was given. \n Error code: " + gDirections.getStatus().code;

    else if (gDirections.getStatus().code == G_GEO_BAD_REQUEST) errorString = "A directions request could not be successfully parsed.\n Error code: " + gDirections.getStatus().code;

    else errorString = "An unknown error occurred getting directions.";
    $('listDisplay').update(errorString);
}

function showDirections() {
    try {
        //toaddr = document.getElementById("currentAddress").innerHTML;
        //var toaddr = $('resellerAddress').value;
        var toaddr = "";
        if ($("currentAddress"))
        {
            toaddr = $("currentAddress").innerHTML;
            if (toaddr.toLowerCase().indexOf("malaysia") == -1)
            toaddr += ", Malaysia";
        }

        // the from field in the infowindow
        var fromaddr = "";
        if ($("searchAddress"))
        {
            fromaddr = $("searchAddress").value;
            if (fromaddr.toLowerCase().indexOf("malaysia") == -1)
            fromaddr += ", Malaysia";
            //GLog.write("fromaddr = " + fromaddr);
        }

        if ($("searchLatlng"))
        {
            if ($("searchLatlng").innerHTML.length > 0)
            {
                fromaddr = $("searchLatlng").innerHTML;
            }
        }
        try {
            // if there's a lat lng use that
            toaddr = $("latlng").innerHTML;
        } catch(e) {}
        //GLog.write("FromAddr = " + fromaddr + " ToAddr = " + toaddr);
        if (fromaddr.length > 0) {
            var directionsPanel = $("listDisplay");
            gDirections.clear();
            gDirections = new GDirections(gMap, directionsPanel);
            // don't add the overlay
            GEvent.addListener(gDirections, "error", onDirectionsError);
            GEvent.addListener(gDirections, "load", onGDirectionsLoad);
            var directionsString = "from: " + fromaddr + " to: " + toaddr;
            gDirections.load(directionsString);
            var html = '<p align=center>Getting directions from "';
            html += fromaddr;
            html += '" to "';
            html += toaddr;
            html += '"...<br/><br/><br/><br/><p align=center><img src=/site_media/img/loading.gif></p>';
            $('listDisplay').update(html);
        }
        // put the infowindow directions div back the way it was
        $('offerDirections').show();
        $('directions').hide();
    } catch(e) {
        showError("Exception in showDirections(): " + e);
    }

}

// if they press return in the field, submit
function directionsFromKeyPress(e) {
    try {
        var characterCode;
        // literal character code will be stored in this variable
        if (e && e.which) {
            e = e;
            characterCode = e.which;
            //character code is contained in NN4's which property
        } else {
            e = event;
            characterCode = e.keyCode;
            //character code is contained in IE's keyCode property
        }

        if (characterCode == 13) {
            //if generated character code is equal to ascii 13 (if enter key)
            //document.forms[0].submit() //submit the form
            showDirections();
            return false
        } else {
            return true
        }
    } catch(e) {
        showError("Exception in directionsFromKeyPress(): " + e);
    }
    return false;
}

// pan the map to show a reseller marker
function showMarker(lat, lng, zoom, markerId) {
    try {
        // console.log("showMarker(" + lat, + ", " + lng + ", " + zoom + ", " + markerName);
        var latLng = new google.maps.LatLng(lat, lng);
        var boundsSpan = gMap.getBounds().toSpan();
        var mapCentreLatLng = new google.maps.LatLng(latLng.lat() + (boundsSpan.lat() / 3.0), latLng.lng());

        //gMap.panTo(mapCentreLatLng, zoom);
        gMap.setCenter(mapCentreLatLng);
        gMap.setZoom(zoom);
        new Ajax.Request('/ajax/getResellerInfoWindowHtml/' + markerId, {
            method: 'get',
            asynchronous: true,
            onSuccess: function(request) {
                gMap.closeInfoWindow();
                gMap.openInfoWindowHtml(latLng, request.responseText);
            }
        });
        //gMap.openInfoWindowHtml(new google.maps.LatLng(lat, lng), markerTitle);
    } catch(e) {
        showError("Exception in showMarker(): " + e);
    }

}

