var openImg = new Image();
openImg.src = "/database/geo_location/open.gif";
var closedImg = new Image();
closedImg.src = "/database/geo_location/closed.gif";

function showBranch(branch) {

	var objBranch = document.getElementById(branch).style;

	if(objBranch.display=="block") {

		objBranch.display="none";
	}
	else {

		objBranch.display="block";
	}
}
   
function swapFolder(img) {

	objImg = document.getElementById(img);

	if(objImg.src.indexOf('closed.gif') > -1) {

		objImg.src = openImg.src;
	}
	else {

		objImg.src = closedImg.src;
	}
}

/**
 * MapLayer Class Definition
 */
function mapLayer(disneyMap, label) {

	this.disneyMap = disneyMap;
	this.layerIndex = disneyMap.mapLayers.length;
	this.label = label;
	this.subLayers = [];
	this.markers = [];

	this.icon = null;
	this.mLocation = null;
	this.minZoom = null;
	this.maxZoom = null;
	this.points = null;
	this.levels = null;
	this.color = null;
	this.bColor = null;
	this.polygon = null;
	this.marker = null;
	this.polygonDisplayed = false;
	this.layerHidden = false;
}

// Update the display of the layer based upon the setting of the corresponding checkbox.
mapLayer.prototype.updateDisplay = function() {

	var elt;

	if((elt = document.getElementById('display_overlay[' + this.layerIndex + ']')) == null) {

		return;
	}

	if(this.subLayers.length > 0) {

		for(var i in this.subLayers) {

			var subLayerIndex = this.subLayers[i].layerIndex;
			var subLayerElt;

			if((subLayerElt = document.getElementById('display_overlay[' + subLayerIndex + ']')) == null) {

				continue;
			}

			subLayerElt.checked = elt.checked;
			this.subLayers[i].updateDisplay();
		}
	}

	this.layerHidden = (!elt.checked);
	this.setMarkersVisibility();
}

mapLayer.prototype.setMarkersVisibility = function() {

	if(!this.layerHidden) {

		for(var i = 0; this.markers[i] != null; i++) {

			if(this.markers[i].isHidden()) {

				this.markers[i].show();
			}
		}
	}
	else {

		for(var i = 0; this.markers[i] != null; i++) {

			if(!this.markers[i].isHidden()) {

				this.markers[i].hide();
			}
		}
	}
}

mapLayer.prototype.hideLayer = function() {

	if(this.polygon != null && this.polygonDisplayed) {

		this.polygonDisplayed = false;
		this.disneyMap.map.removeOverlay(this.polygon);
	}
}

mapLayer.prototype.createPolygon = function() {

	if(this.points == null) {

		return;
	}

	var polygon = new GPolygon.fromEncoded({
		polylines: [{
				color: this.bColor,
				weight: 3,
				points: this.points,
				levels: this.levels,
				zoomFactor: 32,
				numLevels: 4,
				opacity: 0.5
			}],
		fill: true,
		color: this.color,
		opacity: 0.15,
		outline: true
	});

	this.polygon = polygon;
	this.polygonDisplayed = false;
}

mapLayer.prototype.displayLayer = function(showMarker) {

	var markersAdded = false;

	if(this.polygon == null) {

		this.createPolygon();
	}

	if(this.polygon != null && !this.polygonDisplayed) {

		this.polygonDisplayed = true;
		this.disneyMap.map.addOverlay(this.polygon);
	}

	if(showMarker) {

		markersAdded = this.displayMarker();
	}

	return markersAdded;
}

mapLayer.prototype.createMarker = function(point, label, icon) {

	var marker = new GMarker(point, {icon: icon, title: label});

	GEvent.addListener(marker, "click", function() {

		marker.openInfoWindowHtml(label);
	});

	return marker;
}

mapLayer.prototype.displayMarker = function() {

	var markersAdded = false;

	if(this.marker == null && this.mLocation != null) {
/*
		if(this.icon != null) {

			var icon = new GIcon();
			icon.image = this.icon;
			icon.shadow = "http://maps.google.com/mapfiles/kml/pal2/icon40s.png";
			icon.iconSize = this.iconSize;
			icon.shadowSize = new GSize(59, 32);
			icon.iconAnchor = this.iconAnchor;
			icon.infoWindowAnchor = new GPoint(16, 16);
			this.marker = this.createMarker(this.mLocation, this.label, icon);
		}
		else {

			this.marker = this.createMarker(this.mLocation, this.label, null);
		}
*/
		this.marker = this.createMarker(this.mLocation, this.label, this.icon);
		this.disneyMap.mgr.addMarker(this.marker, this.minZoom, this.maxZoom);
		markersAdded = true;
	}

	return markersAdded;
}

mapLayer.prototype.displayBorder = function() {

	if(this.disneyMap.hoverPolyline != null) {

		this.disneyMap.map.removeOverlay(this.disneyMap.hoverPolyline);
		this.disneyMap.hoverPolyline = null;
	}

	if(!this.points) {

		return;
	}

	this.disneyMap.hoverPolyline = new GPolyline.fromEncoded({
		color: this.bColor,
		weight: 5,
		points: this.points,
		levels: this.levels,
		zoomFactor: 32,
		numLevels: 4,
		opacity: 1
	});

	this.disneyMap.map.addOverlay(this.disneyMap.hoverPolyline);
}

mapLayer.prototype.hideBorder = function() {

	if(this.disneyMap.hoverPolyline != null) {

		this.disneyMap.map.removeOverlay(this.disneyMap.hoverPolyline);
		this.disneyMap.hoverPolyline = null;
	}
}

mapLayer.prototype.addSubLayer = function(overlayIndex, label) {

	this.subLayers[overlayIndex] = new mapLayer(this.disneyMap, label);
	this.disneyMap.mapLayers.push(this.subLayers[overlayIndex]);
	return this.subLayers[overlayIndex];
}

mapLayer.prototype.createLayerBoxes = function() {

	var innerBox = "";

	for(var i in this.subLayers) {

		var l_idx = this.subLayers[i].layerIndex;

		if(this.subLayers[i].subLayers.length > 0) {

			innerBox += "<div><span class=\"map_layer_trigger\" onClick=\"showBranch('overlay_branch" + l_idx + "'); swapFolder('overlay_folder" + l_idx + "');\">";
			innerBox += "<img src=\"/database/geo_location/closed.gif\" id=\"overlay_folder" + l_idx + "\" />";
			innerBox += "</span>";
		}
		else {

			innerBox += "<div><img src=\"/database/geo_location/file.gif\" />";
		}

		if(this.subLayers[i].mLocation != null) {

			innerBox += "<label>";
			innerBox += "<input type=\"checkbox\" id=\"display_overlay[" + l_idx + "]\" onClick=\"dm.mapLayers[" + l_idx + "].updateDisplay();\" checked />";
			innerBox += "<a href=\"#\" onClick=\"dm.map.panTo(new GLatLng(" + this.subLayers[i].mLocation.lat() + ", " + this.subLayers[i].mLocation.lng() + ")); return false;\" onmouseover=\"dm.mapLayers[" + l_idx + "].displayBorder();\" onmouseout=\"dm.mapLayers[" + l_idx + "].hideBorder();\">";
			innerBox += this.subLayers[i].label;
			innerBox += "</a>";
			innerBox += "</label></div>\n";
		}
		else {

			innerBox += "<label for=\"display_overlay[" + l_idx + "]\">";
			innerBox += "<input type=\"checkbox\" id=\"display_overlay[" + l_idx + "]\" onClick=\"dm.mapLayers[" + l_idx + "].updateDisplay();\" checked />";
			innerBox += this.subLayers[i].label;
			innerBox += "</label></div>\n";
		}

		if(this.subLayers[i].subLayers.length > 0) {

			innerBox += "<div class=\"map_layer_branch\" id=\"overlay_branch" + l_idx + "\">\n";
			innerBox += this.subLayers[i].createLayerBoxes();
			innerBox += "</div>\n";
		}
	}

	return innerBox;
}


/**
 * DisneyMap Class Definition
 */
function disneyMap() {

	this.mapDiv = null;
	this.mapLayersDiv = null;
	this.map = null;
	this.mgr = null;

	this.icons = [];
	this.iconIndex = [];

	this.layerRanges = [[0,14],[15,16],[17,null]];

	this.hoverPolyline = null;
	this.overlayGroups = [];
	this.mapLayers = [];

	this.initLat = null; // Initial latitude
	this.initLon = null; // Initial longitude
	this.initZoom = null; // Initial zoom
	this.currentPid = null; // The page id of the current page so that it can be set as
	                        // a different marker if required.
	this.currentIcon = null; // The icon to use for the current page, if required.

	this.showSearch = true; // Whether to show the local search box.

	this.showAttractions = true; // Whether to display an attractions layer.
	this.showLocations = true; // Whether to display the locations
	this.showLocationPolygons = true; // Whether to display the polygons associated with the locations
	this.showOverlays = true; // Whether to display the custom overlays

	this.locationsDownloaded = false; // Whether the location layer has been downloaded
	this.overlaysDownloaded = false; // Whether the overlays have been downloaded

	this.defaultMapType = G_HYBRID_MAP; // The default map type to load the map with.
	this.extraPadding = 0; // Any extra padding around the map that enables us to calculate
	                       // the available space for it to be resized into.
}

disneyMap.prototype.setCurrentPid = function(pid) {

	this.currentPid = pid;
	if(this.currentIcon == null) {

		this.currentIcon = new GIcon();
		this.currentIcon.image = "http://maps.google.com/mapfiles/kml/pal3/icon40.png";
		this.currentIcon.shadow = "http://maps.google.com/mapfiles/kml/pal3/icon40s.png";
		this.currentIcon.iconSize = new GSize(32, 32);
		this.currentIcon.shadowSize = new GSize(59, 32);
		this.currentIcon.iconAnchor = new GPoint(16, 16);
		this.currentIcon.infoWindowAnchor = new GPoint(16, 16);
	}
}

disneyMap.prototype.createMap = function(mapDivId, mapLayersDivId) {

	this.mapDiv = document.getElementById(mapDivId);
//	this.mapLayersDiv = document.getElementById(mapLayersDivId);
	this.map = new GMap2(this.mapDiv);
}

disneyMap.prototype.addMarkerManager = function() {

	this.mgr = new MarkerManager(this.map);
}

disneyMap.prototype.addOverlayGroup = function(groupIndex, groupName) {

	this.overlayGroups[groupIndex] = new mapLayer(this, groupName);
	this.mapLayers.push(this.overlayGroups[groupIndex]);
}

disneyMap.prototype.outputLayerBoxes = function() {

	var html = "";
	for(var i in this.overlayGroups) {

		html += "<fieldset style=\"padding: 2px 2px 4px 2px; border: 1px solid #8888AA; margin: 0px 0px 2px 2px;\"><legend style=\"color: #444488;\">" + this.overlayGroups[i].label + "</legend>";
		html += this.overlayGroups[i].createLayerBoxes();
		html += "</fieldset>";
	}

	return html;
}

disneyMap.prototype.resizeMap = function() {

	// Make sure the page is fully loaded
	if(this.mapDiv == null) {

		return;
	}

	this.setMapWidth();
	this.setMapHeight();
	this.map.checkResize();

	// Resize the sidebar in accordance with the new size map.
	this.layersControl.resizeLayer();
}

disneyMap.prototype.setMapWidth = function() {

	var photosCol;
	var linksCol;

	var photosW = 0;
	if((photosCol = document.getElementById("photos_box")) != null) {

		// Photos column width plus cellpadding of 2 and cellspacing of 2 (either side)
		photosW = parseInt(photosCol.offsetWidth) + 8;
	}

	var linksW = 0;
	if((linksCol = document.getElementById("links_box")) != null) {

		// Links column width plus cellpadding of 2 and cellspacing of 2 (either side)
		linksW = parseInt(linksCol.offsetWidth) + 8;
	}

	var mapLayersW = 0;
/*
	if(this.mapLayersDiv !== null) {

		// Add the width of the layers selection div plus the padding of 1px both sides.
		mapLayersW = parseInt(this.mapLayersDiv.offsetWidth) + 2;
	}
*/
	var topbar = document.getElementById("topbar");
	var topbarWidth = parseInt(topbar.offsetWidth);

	var winWidth = 0;
	if( typeof( window.innerWidth ) == 'number' ) {

		//Non-IE
		winWidth = window.innerWidth;
	} 
	else if( document.documentElement 
		&& ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {

		//IE 6+ in 'standards compliant mode'
		winWidth = document.documentElement.clientWidth;
	} 
	else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {

		//IE 4 compatible
		winWidth = document.body.clientWidth;
	}

	//var diff = topbarWidth - bodyWidth;
	var diff = topbarWidth - (photosW + linksW + this.extraPadding + mapLayersW) - 16;

//alert("Topbar: " + topbarWidth + " Photos: " + p + " Links: " + l + " Extra: " + this.extraPadding + "Layers: " + (parseInt(this.mapLayersDiv.offsetWidth) + 2) + " DIFFERENCE: " + diff);
	this.mapDiv.style.width = Math.max(diff, 400) + 'px';

	var mainCol = document.getElementById("main_column");
	mainCol.style.width = (Math.max(diff, 400) + mapLayersW + this.extraPadding) + 'px';
}

disneyMap.prototype.setMapHeight = function() {

	var mapW = parseInt(this.mapDiv.offsetWidth);
	var mapH = Math.round(mapW * 0.866);
	this.mapDiv.style.height = mapH + 'px';
}

// Go through all the map layers attached and update the display of the polygons/polylines for the
// current zoom level.  Useful to run this function after zooming in or out or after loading the
// map.
disneyMap.prototype.updateLayers = function() {

	var markersAdded = false;

	for(var i = 0; i < this.mapLayers.length; i++) {

		var layer = this.mapLayers[i];

		if((layer.maxZoom != null && this.map.getZoom() > layer.maxZoom)
			|| (layer.minZoom != null && this.map.getZoom() < layer.minZoom)) {

			layer.hideLayer();
			continue;
		}

		if(layer.displayLayer(true)) {

			markersAdded = true;
		}
	}

	if(markersAdded) {

		this.mgr.refresh();
	}
}

// Create a marker for an attraction on the map.
disneyMap.prototype.createAttractionMarker = function(point, pid, atid, type, name) {

	var marker;

	if(this.currentPid != null && pid == this.currentPid) {

		marker = new GMarker(point, {icon: this.currentIcon, title: name});
	}
	else if(this.overlayGroups[1].subLayers[type].icon != null) {

		marker = new GMarker(point, {icon: this.overlayGroups[1].subLayers[type].icon, title: name});
	}
	else {

		marker = new GMarker(point, {title: name});
	}

	this.overlayGroups[1].subLayers[type].markers.push(marker);

	// Add a reference to the disney map object to the marker as event functions need to be able to
	// refer back to it.
	marker.disneyMap = this;

	GEvent.addListener(marker, "click", function() {

		var request = GXmlHttp.create();
		request.open("GET", "/database/geo_location/fetch_xml.php?q=1&id=" + pid, true);
		request.onreadystatechange = function() {

			if (request.readyState == 4) {

				var xmlDoc = request.responseXML;
				var pages = xmlDoc.documentElement.getElementsByTagName("page");

				if(pages.length == 1) {

					marker.openInfoWindowHtml(marker.disneyMap.getAttractionHTML(pages[0]));
				}
			}
		}

		request.send(null);
	});

	return marker;
}


// Download the markers for attractions/restaurants/shops
disneyMap.prototype.downloadAttractions = function() {

	GDownloadUrl("/database/geo_location/fetch_xml.php", GEvent.callback(this, this.processAttractionXML));
}

// Callback function that processes the XML of the attraction markers
disneyMap.prototype.processAttractionXML = function(data) {

	var xml = GXml.parse(data);
	var markers = xml.documentElement.getElementsByTagName("marker");

	var markerList = [];

	for (var i = 0; i < markers.length; i++) {

		var name = markers[i].getAttribute("name");
		var type = markers[i].getAttribute("type");
		var point = new GLatLng(
			parseFloat(markers[i].getAttribute("lat")),
			parseFloat(markers[i].getAttribute("lng")));
		var pid = parseInt(markers[i].getAttribute("pid"));
		var atid = parseInt(markers[i].getAttribute("atid"));

		var marker = this.createAttractionMarker(point, pid, atid, type, name);
		markerList.push(marker);
	}

	this.mgr.addMarkers(markerList, 16);
	this.mgr.refresh();
}

// Decode the XML to return some HTML to be output when the attraction marker is clicked.
disneyMap.prototype.getAttractionHTML = function(pageXML) {

	var pageName = pageXML.getAttribute("name");
	var pageURL  = pageXML.getAttribute("url");

	var html = "<b>" + pageName + "</b>";
	var images = pageXML.getElementsByTagName("image");

	if(images.length > 0) {

		for(var i = 0; i < images.length; i++) {

			var imgL = images[i].getAttribute("location");
			var imgW = images[i].getAttribute("width");
			var imgH = images[i].getAttribute("height");
			var imgId = images[i].getAttribute("id");

			html += "<div id=\"layerImage" + imgId + "\" style=\"display: " + (i == 0 ? "block" : "none") + ";\">";
			html += "<center><table cellpadding=\"2\" cellspacing=\"0\" border=\"0\"><tr><td valign=\"middle\">";

			if(i > 0) {

				html += "<a href=\"#\" onClick=\"getElementById('layerImage" + imgId + "').style.display = 'none'; getElementById('layerImage" + images[(i - 1)].getAttribute("id") + "').style.display = 'block'; return false;\"><img src=\"/database/geo_location/prev.gif\" border=\"0\" width=\"25\" height=\"25\" alt=\"Prev\" /></a>";
			}
			else {

				html += "<img src=\"/images/pixel.gif\" height=\"1\" width=\"25\" />";
			}

			html += "</td><td><img src=\"" + imgL + "\" width=\"" + imgW + "\" height=\"" + imgH + "\" /></td><td valign=\"middle\">";
			if(i < images.length - 1) {

				html += "<a href=\"#\" onClick=\"getElementById('layerImage" + imgId + "').style.display = 'none'; getElementById('layerImage" + images[(i + 1)].getAttribute("id") + "').style.display = 'block'; return false;\"><img src=\"/database/geo_location/next.gif\" border=\"0\" width=\"25\" height=\"25\" alt=\"Next\" /></a>";
			}
			else {

				html += "<img src=\"/images/pixel.gif\" height=\"1\" width=\"25\" />";
			}

			html += "</td></tr></table></center></div>";
		}
	}

	html += "<br /><a href=\"" + pageURL + "\">Visit Page</a>";
	return html;
}

// Download the area location markers and polygons
disneyMap.prototype.downloadLocations = function() {

	GDownloadUrl("/database/geo_location/fetch_xml.php?q=2", GEvent.callback(this, this.processLocationXML));
}

// Download the overlays once we have downloaded all the icons
disneyMap.prototype.downloadOverlays = function() {

	GDownloadUrl("/database/geo_location/fetch_xml.php?q=3", GEvent.callback(this, this.processOverlayXML));
}

// Callback function that processes the XML of the location data
disneyMap.prototype.processLocationXML = function(data) {

	var xml = GXml.parse(data);
	this.processLocationXMLRecursive(xml.documentElement, null, 0);
	this.updateLayers();
	this.locationsDownloaded = true;

	// Create the overlay boxes and resize the map if all overlays are downloaded.
	this.createOverlayBoxes();
	this.resizeMapInit();
}

// Recursive function that goes through the XML and is able to deal with locations nested
// as sublocations of other locations to whatever nesting is required.
disneyMap.prototype.processLocationXMLRecursive = function(node, layerParent, nest) {

	if(node.childNodes.length == 0) {

		return;
	}

	for(var i = 0; i < node.childNodes.length; i++) {

		var pnode = node.childNodes[i];

		if(layerParent == null) {

			layerParent = this.overlayGroups[0];
		}

		var layerIndex = layerParent.subLayers.length;

		var layer = layerParent.addSubLayer(layerIndex, pnode.getAttribute("label"));
		layer.mLocation = new GLatLng(parseFloat(pnode.getAttribute("latitude")), parseFloat(pnode.getAttribute("longitude")));

		var oiconId = pnode.getAttribute("oicon");
		var intIcon = parseInt(oiconId);

		if(oiconId == intIcon) {

			layer.icon = this.getOIcon(intIcon);
		}


		layer.minZoom = (this.layerRanges[nest] != null ? this.layerRanges[nest][0] : 17);
		layer.maxZoom = (this.layerRanges[nest] != null ? this.layerRanges[nest][1] : null);

		if(this.showLocationPolygons) {

			layer.points  = pnode.getAttribute("encoded_polygon");
			layer.levels  = pnode.getAttribute("polygon_levels");
			layer.color   = pnode.getAttribute("fill_colour");
			layer.bColor  = pnode.getAttribute("border_colour");
		}

		this.processLocationXMLRecursive(pnode, layer, nest + 1);
	}
}

disneyMap.prototype.downloadIcons = function() {

	// Download the icons and overlays
	GDownloadUrl("/database/geo_location/fetch_xml.php?q=4", GEvent.callback(this, this.processIconXML));
}

// Callback function that processes the XML of the icon data
disneyMap.prototype.processIconXML = function(data) {

	var xml = GXml.parse(data);
	var oicons = xml.documentElement.getElementsByTagName("icon");

	for (var i = 0; i < oicons.length; i++) {

		var iconNo = this.icons.length;
		this.icons[iconNo] = new GIcon();
		this.icons[iconNo].image = oicons[i].getAttribute("image");
		this.icons[iconNo].shadow = oicons[i].getAttribute("shadow");
		this.icons[iconNo].iconSize = new GSize(parseInt(oicons[i].getAttribute("image_w")), parseInt(oicons[i].getAttribute("image_h")));
		this.icons[iconNo].shadowSize = new GSize(parseInt(oicons[i].getAttribute("shadow_w")), parseInt(oicons[i].getAttribute("shadow_h")));
		this.icons[iconNo].iconAnchor = new GPoint(parseInt(oicons[i].getAttribute("anchor_x")), parseInt(oicons[i].getAttribute("anchor_y")));
		this.icons[iconNo].infoWindowAnchor = new GPoint(parseInt(oicons[i].getAttribute("info_x")), parseInt(oicons[i].getAttribute("info_y")));
		this.iconIndex[parseInt(oicons[i].getAttribute("id"))] = iconNo;
	}

	if(this.showOverlays) {

		this.downloadOverlays();
	}

	if(this.showLocations) {

		this.downloadLocations();
	}
}

// Callback function that processes the XML of the overlay data
disneyMap.prototype.processOverlayXML = function(data) {

	var xml = GXml.parse(data);
	this.processOverlayXMLRecursive(xml.documentElement, null, 0);
	this.mgr.refresh();
	this.overlaysDownloaded = true;

	// Create the overlay boxes and resize the map if all overlays are downloaded.
	this.createOverlayBoxes();
	this.resizeMapInit();
}

// Recursive function that goes through the XML and is able to deal with overlays nested
// as sublayers of other overlays to whatever nesting is required.
disneyMap.prototype.processOverlayXMLRecursive = function(node, layerParent, nest) {

	if(node.childNodes.length == 0) {

		return;
	}

	for(var i = 0; i < node.childNodes.length; i++) {

		var pnode = node.childNodes[i];

		var layerId = pnode.getAttribute("id");
		var layerName = pnode.getAttribute("name");

		if(layerParent == null) {

			layerParent = this.overlayGroups[1];
		}

		var layerIdx = layerParent.subLayers.length;
		layerParent.addSubLayer(layerIdx, layerName);

		for(var j = 0; j < pnode.childNodes.length; j++) {

			var subnode = pnode.childNodes[j];
			if(subnode.nodeName == "sublayers") {

				this.processOverlayXMLRecursive(subnode, layerParent.subLayers[layerIdx], nest + 1)
				continue;
			}
			else if(subnode.nodeName != "overlay") {

				continue;
			}

			var oname = subnode.getAttribute("name");
			var minZoom = subnode.getAttribute("min_zoom");
			var maxZoom = subnode.getAttribute("max_zoom");
			var intMin = parseInt(minZoom);
			var intMax = parseInt(maxZoom);

			var pMinZ = (minZoom == intMin ? intMin : 0);
			var pMaxZ = (maxZoom == intMax ? intMax : null);

			var oiconId = subnode.getAttribute("oicon");
			var intIcon = parseInt(oiconId);
			var oicon;

			if(oiconId == intIcon) {

				oicon = this.getOIcon(intIcon);
			}
			else {

				oicon = null;
			}

			var imarkers = [];
			for(var k = 0; k < subnode.childNodes.length; k++) {

				var markerNode = subnode.childNodes[k];
				var point = new GLatLng(
					parseFloat(markerNode.getAttribute("lat")),
					parseFloat(markerNode.getAttribute("lng")));
				var marker = new GMarker(point, {icon: oicon, title: oname});

				imarkers.push(marker);
				layerParent.subLayers[layerIdx].markers.push(marker);
			}

			if(imarkers.length > 0) {

				this.mgr.addMarkers(imarkers, pMinZ, pMaxZ);
			}
		}
	}
}

disneyMap.prototype.getOIcon = function(oicon) {

	if(this.iconIndex[oicon] != null) {

		return this.icons[this.iconIndex[oicon]];
	}

	return null;
}

// Determines whether the various different layers have all been downloaded correctly and
// hence that we are able to output the boxes, etc.
disneyMap.prototype.layersComplete = function() {

	if(this.showOverlays && !this.overlaysDownloaded) {

		return false;
	}

	if(this.showLocations && !this.locationsDownloaded) {

		return false;
	}

	return true;
}

// If the layers have all been downloaded completely then print out the boxes.
disneyMap.prototype.createOverlayBoxes = function() {

	if(this.layersComplete()) {

		this.mapLayersDiv.innerHTML += this.outputLayerBoxes();
	}
}

disneyMap.prototype.resizeMapInit = function() {

	if(this.layersComplete()) {

		this.resizeMap();
	}
}

disneyMap.prototype.load = function(mapDivId, mapLayerDivId) {

	if (GBrowserIsCompatible()) {

		this.createMap(mapDivId, mapLayerDivId);
		this.map.setCenter(new GLatLng(this.initLat, this.initLon), this.initZoom);
		this.map.addControl(new GLargeMapControl());
		this.map.addControl(new GMapTypeControl());

		this.layersControl = new LayersControl();
		this.map.addControl(this.layersControl);

		var layer = this.layersControl.addLayer("Layers", "#FFCCCC", new TabImage("/images/map-layer-tab.png", 20, 62, "map_layer_tab"));
		this.mapLayersDiv = layer.contents;
		this.map.setMapType(this.defaultMapType);

		if(this.showSearch) {

			var searchLayer = this.layersControl.addLayer("Search", "#FFFFCC", new TabImage("/images/map-search-tab.png", 20, 62, "map_search_tab"));
//			this.map.addControl(new LocalSearch());
			var localSearch = new LocalSearch(searchLayer.contents);
			localSearch.initialize(this.map);
		}

//		this.map.enableScrollWheelZoom();
		this.addMarkerManager();

		if(this.showLocations) {

			this.addOverlayGroup(0, "Places");
		}

		if(this.showAttractions || this.showOverlays) {

			this.addOverlayGroup(1, "Layers");
		}

		if(this.showAttractions) {

			this.overlayGroups[1].addSubLayer(1, "Attractions");
			this.overlayGroups[1].addSubLayer(2, "Restaurants");
			this.overlayGroups[1].addSubLayer(3, "Shops");

			// Red attraction icon
			var icon = new GIcon();
			icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
			icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
			icon.iconSize = new GSize(12, 20);
			icon.shadowSize = new GSize(22, 20);
			icon.iconAnchor = new GPoint(6, 20);
			icon.infoWindowAnchor = new GPoint(5, 1);
			this.overlayGroups[1].subLayers[1].icon = icon;

			// Restaurant icon
			var icon = new GIcon();
			icon.image = "http://maps.google.com/mapfiles/kml/pal2/icon40.png";
			icon.shadow = "http://maps.google.com/mapfiles/kml/pal2/icon40s.png";
			icon.iconSize = new GSize(32, 32);
			icon.shadowSize = new GSize(59, 32);
			icon.iconAnchor = new GPoint(16, 16);
			icon.infoWindowAnchor = new GPoint(16, 16);
			this.overlayGroups[1].subLayers[2].icon = icon;

			// Shopping cart icon
			var icon = new GIcon();
			icon.image = "http://maps.google.com/mapfiles/kml/pal3/icon26.png";
			icon.shadow = "http://maps.google.com/mapfiles/kml/pal3/icon26s.png";
			icon.iconSize = new GSize(32, 32);
			icon.shadowSize = new GSize(59, 32);
			icon.iconAnchor = new GPoint(16, 16);
			icon.infoWindowAnchor = new GPoint(16, 16);
			this.overlayGroups[1].subLayers[3].icon = icon;

			this.downloadAttractions();
		}

		if(this.showOverlays || this.showLocations) {

			this.downloadIcons();
		}

		// Function to call once load is completed
		this.loadComplete();

		// Refresh the polylines/polygons when zooming in and out
		GEvent.bind(this.map, "zoomend", this, this.updateLayers);
	}
}

// Blank function that can be implemented by a page that wishes to perform extra commands
// once the map has loaded.
disneyMap.prototype.loadComplete = function() {

}

function TabImage(src, width, height, pngTransClass) {

	this.src = src;
	this.width = width;
	this.height = height;
	this.pngTransClass = pngTransClass;
	this.element = null;
}

TabImage.prototype.createImgElement = function() {

	if(!this.element) {

		if(this.pngTransClass == false) {

			this.element = document.createElement("img");
			this.element.src = this.src;
			this.element.height = this.height;
			this.element.width = this.width;
		}
		else {

			this.element = document.createElement("span");
			this.element.className = this.pngTransClass;

			var img = document.createElement("img");
			img.src = this.src;
			img.height = this.height;
			img.width = this.width;

			this.element.appendChild(img);
		}
	}

	return this.element;
}




// We define the function first
function LayersControl() {

	this.subLayers = [];
	this.layersOpen = true;
	this.selectedSubLayer;
	this.layerButtons = [];
	this.vOffset = 30; // Vertical offset of the layer from the top of the map
}

// To "subclass" the GControl, we set the prototype object to
// an instance of the GControl object
LayersControl.prototype = new GControl();

// Creates a one DIV for each of the buttons and places them in a container
// DIV which is returned as our control element. We add the control to
// to the map container and return the element for the map class to
// position properly.
LayersControl.prototype.initialize = function(map) {

	this.map = map;

	this.container = document.createElement("div");
	this.container.style.position = "relative";

	this.layersDiv = document.createElement("div");
	this.layersDiv.style.position = "relative";
	this.layersDiv.style.width = "250px";
	this.layersDiv.style.left = "1px";
	this.layersDiv.style.border = "1px solid black";
	this.layersDiv.style.padding = "2px";
	this.layersDiv.style.overflow = "auto";

/*
	this.layersDiv.style.opacity = "0.9";
	this.layersDiv.style.mozOpacity = "0.9";
	this.layersDiv.style.filter = "alpha(opacity=90)";
*/

	// Set an initial size for the layer
	this.resizeLayer();

	this.button = document.createElement("div");
	this.button.style.position = "absolute";
	this.button.style.backgroundColor = "white";
	this.button.style.borderLeft = "1px solid black";
	this.button.style.borderTop = "1px solid black";
	this.button.style.borderBottom = "1px solid black";
	this.button.style.left = "1px";
	this.button.style.top = "3px";

	this.link = document.createElement("a");
	this.link.onclick = methodClosure(this, LayersControl.prototype.closeLayer, []);
	this.link.innerHTML = "&gt;&gt;";
	this.link.style.cursor = "pointer";
	this.button.appendChild(this.link);

	this.buttonsLayer = document.createElement("div");
	this.buttonsLayer.style.position = "absolute";
	this.buttonsLayer.style.padding = "0px";
	this.buttonsLayer.style.margin = "0px";
	this.buttonsLayer.style.left = "-18px";
	this.buttonsLayer.style.width = "20px";
	this.buttonsLayer.style.top = "0px";
	this.buttonsLayer.style.zIndex = "2";
	this.buttonsLayer.appendChild(this.button);

	this.container.appendChild(this.buttonsLayer);
	this.container.appendChild(this.layersDiv);
	this.map.getContainer().appendChild(this.container);
	this.map.getContainer().style.overflow = "hidden";
//	this.map.getContainer().style.zIndex = "1";
	return this.container;
}

LayersControl.prototype.addLayer = function(layerName, bgColour, tabImage) {

	var idx = this.subLayers.length;
	this.subLayers[idx] = {
		layerName : layerName,
		bgColour: bgColour,
		button: null,
		contents: null
	}

	var yOffset = 30 + (62 * idx);

	var layerButton = document.createElement("div");
	layerButton.style.position = "absolute";
	layerButton.style.padding = "0px";
	layerButton.style.margin = "0px";
	layerButton.style.top = yOffset + "px";

	var layerButtonLink = document.createElement("a");
	layerButtonLink.onclick = methodClosure(this, LayersControl.prototype.showSubLayer, [idx]);
	layerButtonLink.style.cursor = "pointer";

	var layerButtonImage = tabImage.createImgElement();
	layerButtonImage.border = "0px";

	layerButtonLink.appendChild(layerButtonImage);
	layerButton.appendChild(layerButtonLink);
	this.subLayers[idx].button = layerButton;
	this.buttonsLayer.appendChild(layerButton);

	var contents = document.createElement("div");
	contents.style.textDecoration = "none";
	contents.style.color = "#000000";
	contents.style.backgroundColor = bgColour;
	contents.style.font = "small Arial";
	contents.style.textAlign = "left";
	contents.style.position = "absolute";
	contents.style.width = "98%";
	//contents.innerHTML = "<b>" + layerName + "</b>";
	this.subLayers[idx].contents = contents;

	if(this.selectedSubLayer == null) {

		this.layersDiv.appendChild(contents);
	//	this.subLayers[idx].contents.style.visibility = "visible";
		this.selectedSubLayer = idx;
		this.updateLayerColour();
	}
	else {

	//	this.subLayers[idx].contents.style.visibility = "hidden";
	}

	return this.subLayers[idx];
}

LayersControl.prototype.showSubLayer = function(idx) {

	if(this.selectedSubLayer != null) {

		this.layersDiv.removeChild(this.subLayers[this.selectedSubLayer].contents);
	}

	this.layersDiv.appendChild(this.subLayers[idx].contents);
/*
	for(var i = 0; i < this.subLayers.length; i++) {

		if(i == idx) {

			this.subLayers[i].contents.style.visibility = "visible";
		}
		else {

			this.subLayers[i].contents.style.visibility = "hidden";
		}
	}
*/
	this.selectedSubLayer = idx;
	this.updateLayerColour();

	if(this.layersOpen == false) {

		this.openLayer();
	}
}

LayersControl.prototype.resizeLayer = function() {

	this.layersDiv.style.height = (this.map.getSize().height - this.vOffset - 7) + 'px';
}

LayersControl.prototype.closeLayer = function() {

//	this.layersDiv.style.width = '0px';
	this.layersDiv.style.display = "none";

//	this.container.style.right = (2 - parseInt(this.container.offsetWidth)) + 'px';
	this.link.onclick = methodClosure(this, LayersControl.prototype.openLayer, []);
	this.link.innerHTML = "&lt;&lt;";
	this.layersDiv.style.zIndex = "-1";	
	this.layersOpen = false;
}

LayersControl.prototype.openLayer = function() {

//	this.layersDiv.style.width = '200px';
	this.layersDiv.style.display = "block";
	this.container.style.right = '0px';
	this.link.onclick = methodClosure(this, LayersControl.prototype.closeLayer, []);
	this.link.innerHTML = "&gt;&gt;";
	this.layersDiv.style.zIndex = "1";
	this.layersOpen = true;
}

LayersControl.prototype.updateLayerColour = function() {

	if(this.subLayers[this.selectedSubLayer] != null) {

		this.layersDiv.style.backgroundColor = this.subLayers[this.selectedSubLayer].bgColour;
	}
}

// By default, the control will appear at the top right of the map, vOffset 
// pixels below the top edge.
LayersControl.prototype.getDefaultPosition = function() {

	return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0, this.vOffset));
}



{
function LocalSearch(containerDiv, opt_options) {
  this.containerDiv = containerDiv;
  this.results = [];
  this.options = opt_options;
}
LocalSearch.RESULT_LIST_INLINE = "inline";
LocalSearch.RESULT_LIST_SUPPRESS = "suppress";

LocalSearch.prototype = new GControl(false,true);
LocalSearch.prototype.initialize = function(map) {

  this.gmap = map;
  this.parseOptions(this.options);

  var container = document.createElement("div");
  cssSetClass(container, css.control_root);
  this.buildControl(container);

  this.containerDiv.appendChild(container);
  return container;
}

LocalSearch.prototype.getDefaultPosition = function() {
  var x = 5;
  var y = 65;
  if (br_IsIE()) {
    x = 2;
  }
  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(y,x));
}

LocalSearch.prototype.parseOptions = function(options) {
  this.inlineResultList = true;
  if (options) {

    // result list style
    if (options.resultList) {
      if (options.resultList == LocalSearch.RESULT_LIST_INLINE) {
        this.inlineResultList = true;
      } else if (options.resultList == LocalSearch.RESULT_LIST_SUPPRESS) {
        this.inlineResultList = false;
      } else {
        this.inlineResultList = true;
      }
    }
  }

  // adjust css.app, .app_active, .app_idle, and .app_no_results to account
  // for cull or compact mode
  var browserAdd = "gmls-std-mode";
  if (br_IsIE()) {
    browserAdd = "gmls-ie-mode";
  }
  var classAddOn = " " + css.app_compact_mode + " " + browserAdd;
  if (this.inlineResultList == true) {
    classAddOn = " " + css.app_full_mode + " " + browserAdd;;
  }
  css.app += classAddOn;
  css.app_active += classAddOn;
  css.app_idle += classAddOn;
  css.app_no_results += classAddOn;
}

LocalSearch.prototype.buildControl = function(container, opt_options) {
  this.root = container;

  this.buildContainerGuts(opt_options);

  // result scroller
  this.currentResultIndex = 0;
  this.markers = new Array();
  this.idle = true;

  // bind up the controls
  this.input.onclick = methodClosure(this, LocalSearch.prototype.onPreActive, []);
  this.input.onfocus = methodClosure(this, LocalSearch.prototype.onPreActive, []);
//  this.searchForm.setOnSubmitCallback(this,LocalSearch.prototype.formSubmit);

  this.next.onclick = methodClosure(this, LocalSearch.prototype.onNext, []);
  this.prev.onclick = methodClosure(this, LocalSearch.prototype.onPrev, []);

  // build the icons
  var baseIcon = new GIcon();
  baseIcon.image = "http://www.google.com/mapfiles/gadget/markerSmall80.png";
  baseIcon.shadow = "http://www.google.com/mapfiles/gadget/shadow50Small80.png";
  baseIcon.iconSize = new GSize(16, 27);
  baseIcon.shadowSize = new GSize(30, 28);
  baseIcon.iconAnchor = new GPoint(8, 27);
  baseIcon.infoWindowAnchor = new GPoint(5, 1);
  this.letteredIcons = new Array();
  for ( var i=0; i < 16; i++ ) {
    var icon = new GIcon(baseIcon);
    var iconImageKey =
    icon.image = "http://www.google.com/mapfiles/gadget/letters/marker" +
                      String.fromCharCode(65+i) + ".png";
    this.letteredIcons[i] = icon;
  }
}

LocalSearch.prototype.buildContainerGuts = function(opt_options) {

  // build out the control including the form and results popup
  removeChildren(this.root);
  this.appContainer = createDiv(null, css.app_idle);

  // the search form
  this.searchFormDiv = createDiv(null, css.search_form_idle);
  this.searchFormDiv.id = "searchBox";
  this.searchFormDiv.style.display='block';

  this.form = document.createElement("form");
  this.form.className = "gsc-search-box";
  this.form.onsubmit = methodClosure(this, LocalSearch.prototype.formSubmit, []);

  this.input = document.createElement("input");
  this.input.type = "text";
  this.input.className = "gsc-input";
  this.input.value = "";

  this.button = document.createElement("input");
  this.button.type = "submit";
  this.button.className = "gsc-search-button";
  this.button.value = "Search";

  var table = createTable("gsc-search-box");
  var row   = createTableRow(table);
  var cell1 = createTableCell(row, "gsc-input");
  var cell2 = createTableCell(row, "gsc-search-button");
  this.form.appendChild(table);

  cell1.appendChild(this.input);
  cell2.appendChild(this.button);

  this.searchFormDiv.appendChild(this.form);
  this.buildPrevNextControl();

  /**
   * This is the basic structure we are building
   *  <resultsPopup>
   *    <resultsList>
   *      <resultsTable/>
   *      <resultsControls/>
   *    </resultsList>
   *  </resultsPopup>
   */
  this.resultsPopup = createDiv(null, css.results_popup);
  this.resultsList = createDiv(null, css.results_list);
  this.resultsTableDiv = createDiv(null, css.results_table);
  this.resultsTable = createTable(css.results_table);
  this.resultsTableDiv.appendChild(this.resultsTable);

  this.resultControls = createDiv(null, css.results_controls);

  // bind everything up
  this.resultsPopup.appendChild(this.resultsList);
  this.resultsList.appendChild(this.resultsTableDiv);
  this.resultsList.appendChild(this.resultControls);

  this.appContainer.appendChild(this.resultsPopup);

  this.appContainer.appendChild(this.searchFormDiv);
  this.root.appendChild(this.appContainer);
}

LocalSearch.prototype.resetResultsTable = function() {
  this.resultsTableDiv.innerHTML = "";
  this.resultsTable = createTable(css.results_table);
  this.resultsTableDiv.appendChild(this.resultsTable);
}

LocalSearch.prototype.buildPrevNextControl = function() {
  // controls
  this.prevNext = createDiv(null, css.prev_next_active);
  this.prev = createDiv(null, css.prev);
  this.next = createDiv(null, css.next);

  this.prev.innerHTML = "&nbsp;";
  this.next.innerHTML = "&nbsp;";
  this.prev.title = "Previous";
  this.next.title = "Next";

  var prevNextCenter = createDiv(null, css.prev_next_center);
  prevNextCenter.appendChild(this.prev);
  prevNextCenter.appendChild(this.next);

  this.prevNext.appendChild(prevNextCenter);
}

// clear the old markers off of the map
LocalSearch.prototype.clearMarkers = function() {
  cssSetClass(this.prevNext, css.prev_next_idle);

  this.gmap.closeInfoWindow();
  for (var i=0; i < this.markers.length; i++) {
    this.gmap.removeOverlay(this.markers[i].marker);
    if ( this.markers[i].resultsListItem &&
         this.markers[i].resultsListItem.onclick ) {
      this.markers[i].resultsListItem.onclick = null;
    }
    this.markers[i].resultsListItem = null;
  }
  this.resetResultsTable();

  // result scroller
  this.currentResultIndex = 0;
  this.markers = new Array();
}

LocalSearch.prototype.addResultsControl = function(bestResultUrl) {
  removeChildren(this.resultControls);

  // NOW, take the URL and nuke from &latlnt.*&near ->&near
  var newUrl = bestResultUrl.replace(/&latlng=.*&near/,"&near");
  var moreDiv = createDiv(null, css.more_results);
  var clearDiv = createDiv("Clear", css.clear_results);
  clearDiv.onclick = methodClosure(this, LocalSearch.prototype.goIdle, []);

  // create a table for these to sit within
  var prevNextTable = createTable(css.results_controls);
  var row = createTableRow(prevNextTable);
  var moreTd = createTableCell(row, css.more_results);
  var prevNextTd = createTableCell(row, css.prev_next);
  var clearTd = createTableCell(row, css.clear_results);

  moreTd.appendChild(moreDiv);
  prevNextTd.appendChild(this.prevNext);
  clearTd.appendChild(clearDiv);

  this.resultControls.appendChild(prevNextTable);
}

LocalSearch.prototype.showNoResultsMessage = function() {

  //todo(markl): Localize "No Results" text
  var row = createTableRow(this.resultsTable);
  var tdiv = createDiv("No Results", css.result_list_item_warning_text);
  var resultTd = createTableCell(row, null);
  var resultDiv = createDiv(null, css.result_list_item);
  var key = createDiv("!", css.result_list_item_warning_symbol);
  resultDiv.appendChild(key);
  resultDiv.appendChild(tdiv);
  resultTd.appendChild(resultDiv);

  removeChildren(this.resultControls);
  var moreDiv = createDiv("", css.more_results);
  var clearDiv = createDiv("close", css.clear_results);
  clearDiv.onclick = methodClosure(this,
                                      LocalSearch.prototype.goIdle,
                                      []);
  // create a table for these to sit within
  var prevNextTable = createTable(css.results_controls);
  var row = createTableRow(prevNextTable);
  var moreTd = createTableCell(row, css.more_results);
  var prevNextTd = createTableCell(row, css.prev_next);
  var clearTd = createTableCell(row, css.clear_results);

  moreTd.appendChild(moreDiv);
  prevNextTd.appendChild(this.prevNext);
  clearTd.appendChild(clearDiv);

  this.resultControls.appendChild(prevNextTable);
}

// light up the selected marker
LocalSearch.prototype.selectMarker = function(index) {

  // clear info window and reset icon on current marker
  this.gmap.closeInfoWindow();

  // if we have a results list, clear selected
  if (this.markers[this.currentResultIndex].resultsListItem) {
    cssSetClass(this.markers[this.currentResultIndex].resultsListItem,
                css.result_list_item);
  }

  // snap to current
  this.currentResultIndex = index;

  // light up current
  var result = this.markers[this.currentResultIndex];

  if (result.resultsListItem) {
    cssSetClass(result.resultsListItem, css.result_list_item_selected);
  }

  result.marker.openInfoWindow(result.getHtml(), {maxWidth:300});

  // set scroller
  if (index == 0) {
    cssSetClass(this.prev, css.prev_idle);
  } else {
    cssSetClass(this.prev, css.prev_active);
  }

  if (index == this.markers.length - 1) {
    cssSetClass(this.next, css.next_idle);
  } else {
    cssSetClass(this.next, css.next_active);
  }
}

// clear current markers and start a new search
LocalSearch.prototype.formSubmit = function() {

  if (this.input.value) {
    this.newSearch(this.input.value);
  }
  return false;
}

// clear current markers and start a new search
LocalSearch.prototype.execute = function(opt_query) {
  // hyperlink friendly...
  this.newSearch(opt_query);
}

LocalSearch.prototype.newSearch = function(opt_query) {
  this.setAppContainerClass(css.app_idle);
  if (opt_query) {
    this.input.value  = opt_query;
  }
  if (this.input.value) {

    // clear markers, set prev/next
    this.clearMarkers();
    this.performSearch(this.input.value);
  }
  return false;
}

LocalSearch.prototype.performSearch = function(searchStr) {

	var centre = this.gmap.getCenter();
	GDownloadUrl("/database/geo_location/fetch_xml.php?q=9&lat=" + centre.lat() + "&lng=" + centre.lng() + "&s=" + escape(searchStr), GEvent.callback(this, this.processSearchResultXML));
}

// Callback function that processes the XML of the search result
LocalSearch.prototype.processSearchResultXML = function(data) {

	var xml = GXml.parse(data);
	var markers = xml.documentElement.getElementsByTagName("marker");

	this.results = [];
	for (var i = 0; i < markers.length; i++) {

		this.results.push({
			lat: parseFloat(markers[i].getAttribute("lat")),
			lng: parseFloat(markers[i].getAttribute("lng")),
			title: markers[i].getAttribute("name"),
			type: markers[i].getAttribute("type"),
			pid: parseInt(markers[i].getAttribute("pid")),
			atid: parseInt(markers[i].getAttribute("atid")),
			html: "<big>" + markers[i].getAttribute("name") + "</big>",
			url: markers[i].getAttribute("url")
		});
	}

	this.searchComplete();
}

LocalSearch.prototype.searchComplete = function() {
  // result scroller
  this.currentResultIndex = 0;
  this.markers = new Array();
  var bestResultUrl = null;
  this.resetResultsTable();

  if ( this.results && this.results.length > 0) {
    for (var i = 0; i < this.results.length && i < 16; i++) {
      var result = this.results[i];
      var icon = this.letteredIcons[i];
      this.markers.push(new LocalResult(this, result, icon, i, this.inlineResultList));
    }
    bestResultUrl = this.results[0].url;

    this.idle = false;
    this.selectMarker(0);

    this.addResultsControl(bestResultUrl);

    cssSetClass(this.prevNext, css.prev_next_active);
    this.setAppContainerClass(css.app_active);
    return true;
  } else {
    this.showNoResultsMessage();
    this.setAppContainerClass(css.app_active);
    return false;
  }
}

// forwards through the search results
LocalSearch.prototype.onNext = function() {
  if (this.currentResultIndex < this.markers.length - 1) {
    this.selectMarker(this.currentResultIndex+1);
  }
}

// backwards through the search results
LocalSearch.prototype.onPrev = function() {
  if (this.currentResultIndex > 0) {
    this.selectMarker(this.currentResultIndex-1);
  }
}

// called onboot complete, and on cancel click
LocalSearch.prototype.goIdle = function() {
  this.clearMarkers();
  cssSetClass(this.searchFormDiv, css.search_form_idle);
  this.setAppContainerClass(css.app_idle);
  cssSetClass(this.prevNext, css.prev_next_idle);

  this.idle = true;
  this.resetResultsTable();
}

// call onfocus/onclick for search input cell
LocalSearch.prototype.onPreActive = function() {
  if (this.idle) {
    this.input.value = "";
    cssSetClass(this.searchFormDiv, css.search_form_active);
  }
}

LocalSearch.prototype.onMapClick = function(marker, point) {
  if (marker && marker.__ls__) {
    var localResult = marker.__ls__;
    localResult.onClick();
  }
}

LocalSearch.prototype.setAppContainerClass = function(className) {
  cssSetClass(this.appContainer, className);
}

// A class representing a single Local Search result returned by the
// Google AJAX Search API.
function LocalResult(gmls, result, icon, index, buildList) {
  this.gmls = gmls;
  this.result = result;
  this.latLng = new GLatLng(parseFloat(result.lat), parseFloat(result.lng));
  this.index = index;

  this.setMarker(icon);

  if (buildList) {
    var div = createDiv(null, css.result_list_item);
    var row = createTableRow(gmls.resultsTable);
    var tdiv = createDiv(result.title, css.gs_title);
    var resultTd = createTableCell(row, null);

    var resultDiv = createDiv(null, css.result_list_item);

    var key;
    var keyClass = css.result_list_item_key;
    var keyCode = String.fromCharCode(65+index);
    if (true) {
      // go with image based key key codes for now. make it an option later
      keyClass += " " + css.result_list_item_key + "-" + keyCode;
      keyClass += " " + css.result_list_item_key + "-" + "keymode";
      key = createDiv(null, keyClass);
      key.innerHTML = "&nbsp;";
    } else {
      key = createDiv("(" + keyCode + ")", keyClass);
    }

    resultDiv.appendChild(key);
    resultDiv.appendChild(tdiv);

    resultTd.appendChild(resultDiv);
    resultDiv.onclick = methodClosure(
                    gmls, LocalSearch.prototype.selectMarker, [index]);
    this.resultsListItem = resultDiv;
  }
}

LocalResult.prototype.getHtml = function() {
  var result = createDiv(null, css.result_wrapper);
  result.innerHTML = this.result.html;
  return result;
}

LocalResult.prototype.setMarker = function(icon) {
  this.marker = new GMarker(this.latLng, icon);
  this.marker.__ls__ = this;
  this.gmls.gmap.addOverlay(this.marker);
}

LocalResult.prototype.onClick = function() {
  this.gmls.selectMarker(this.index);
}


/**
 * Various Static DOM Wrappers.
*/
function methodClosure(object, method, opt_argArray) {
  return function() {
    return method.apply(object, opt_argArray);
  }
}

function methodCallback(object, method) {
  return function() {
    return method.apply(object, arguments);
  }
}

function createDiv(opt_text, opt_className) {
  var el = document.createElement("div");
  if (opt_text) {
    el.innerHTML = opt_text;
  }
  if (opt_className) { el.className = opt_className; }
  return el;
}

function removeChildren(parent) {
  while (parent.firstChild) {
    parent.removeChild(parent.firstChild);
  }
}

function cssSetClass(el, className) {
  el.className = className;
}

function createTable(opt_className) {
  var el = document.createElement("table");
  if (opt_className) { el.className = opt_className; }
  return el;
}

function createTableRow(table) {
  var tr = table.insertRow(-1);
  return tr;
}

function createTableCell(tr, opt_className) {
  var td = tr.insertCell(-1);
  if (opt_className) { td.className = opt_className; }
  return td;
}

// from common, user agent detector
function br_AgentContains_(str) {
  if (str in br_AgentContains_cache_) {
    return br_AgentContains_cache_[str];
  }

  return br_AgentContains_cache_[str] =
    (navigator.userAgent.toLowerCase().indexOf(str) != -1);
}
var br_AgentContains_cache_ = {};
function br_IsIE() {
  return br_AgentContains_('msie');
}

LocalSearch.selectedStyle = [];

// classes used throughout
css = {};

// major states are
// active: search results are visible
// idle: search results are not showing, control is idle
css.control_root = "gmls";
css.app = "gmls-app";
css.app_compact_mode = "gmls-app-compact-mode";
css.app_full_mode = "gmls-app-full-mode";
css.app_active = "gmls-app gmls-active";
css.app_no_results = "gmls-app gmls-active gmls-no-results";
css.app_idle = "gmls-app gmls-idle";

// search form contains input box, search button, and branding
css.search_form_active = "gmls-search-form gmls-search-form-active";
css.search_form_idle = "gmls-search-form gmls-search-form-idle";

// results
css.results_popup = "gmls-results-popup";
css.results_list = "gmls-results-list";
css.results_table = "gmls-results-table";
css.results_ads_box = "gmls-results-ads-box";
css.results_controls = "gmls-results-controls";

css.result_list_item = "gmls-result-list-item";
css.result_list_item_selected = "gmls-result-list-item gmls-selected";
css.result_list_item_key = "gmls-result-list-item-key";
css.result_wrapper = "gmls-result-wrapper";
css.gs_title = "gs-title";
css.gs_street = "gs-street";

css.result_list_item_warning_symbol = "gmls-result-list-item-warning-symbol";
css.result_list_item_warning_text = "gmls-result-list-item-warning-text";

// scroll controls
css.prev_next = "gmls-prev-next";
css.prev_next_active = "gmls-prev-next gmls-prev-next-active";
css.prev_next_idle = "gmls-prev-next gmls-prev-next-idle";
css.prev_next_center = "gmls-prev-next-center";
css.prev = "gmls-prev";
css.prev_active = "gmls-prev gmls-prev-active";
css.prev_idle = "gmls-prev gmls-prev-idle";
css.next = "gmls-next";
css.next_active = "gmls-next gmls-next-active";
css.next_idle = "gmls-next gmls-next-idle";

// more/clear
css.more_results = "gmls-more-results";
css.clear_results = "gmls-clear-results";

}

