///////////////////////////////////////////////////////////////////////////////////////////////////
//	DLib Google Maps functions - copyright davidviner.com 2009
//
//	21.12.2009	5.6.9	DJV		Added initEvent + some parseInts to force some nnumeric types.
//
///////////////////////////////////////////////////////////////////////////////////////////////////

//C////////////////////////////////////////////////////////////////////////////////////////////////
// Google Map functions.
// @DLibGMap
///////////////////////////////////////////////////////////////////////////////////////////////////

DLibGMap = function ()
{
	var	map,
		mapID,
		mapCtrlList,
		mapUseList,
		mapPos,
		mapDiv,
		mapInfoID,
		mapInfo = null,
		earth = null,
		iconDir = null,
		baseIcon,
		queue = [],
		setAbort = false,
		settings = new Object,
		overlays = new Object,
		olID = 0,
		gmready = false,
		ready = false,
		mX = 0,
		mY = 0,
		runFunc = "",
		streetView = "",
		svDiv = null,
		svClient = null,
		svPano,
		svNextPanoID,
		toggleButtons = [],
		toggleQty = 0;

	var dbTxt = "";

	function debug (txt)
	{
		dbTxt += " " + txt;
//alert ("GM: " + txt);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// Name popup functions
	///////////////////////////////////////////////////////////////////////////////////////////////

	function NamePopup (txt)
	{
		this.txt = txt.replace ("&amp;", "&");
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// Toggle button - button text, x/y position and width, function to call when clicked, initial
	// state (0=grey)
	///////////////////////////////////////////////////////////////////////////////////////////////

	function ToggleButton (txt, x, y, w, func, state, ind)
	{
		this.txt = txt;
		this.x = x;
		this.y = y;
		this.w = w;
		this.func = func;
		this.state = state;
		this.ind = ind;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////

	var _private =
	{
		colourConvert : function (c)
		{
			switch (c.toLowerCase ())
			{
				case "black" :	 c = "#000000"; break;
				case "silver" :	 c = "#c0c0c0"; break;
				case "grey" :
				case "gray" :	 c = "#808080"; break;
				case "white" :	 c = "#ffffff"; break;
				case "maroon" :	 c = "#800000"; break;
				case "red" :	 c = "#ff0000"; break;
				case "purple" :	 c = "#800080"; break;
				case "fuschia" :
				case "magenta" : c = "#ff00ff"; break;
				case "green" :	 c = "#008000"; break;
				case "lime" :	 c = "#00ff00"; break;
				case "olive" :	 c = "#808000"; break;
				case "yellow" :	 c = "#ffff00"; break;
				case "navy" :	 c = "#000080"; break;
				case "blue" :	 c = "#0000ff"; break;
				case "teal" :	 c = "#008080"; break;
				case "aqua" :
				case "cyan" :	 c = "#00ffff"; break;
				case "orange" :	 c = "#ffa500"; break;

				default:
					if (c.charAt (0) != '#') c = "#000000";
			}

			return c;
		},

		///////////////////////////////////////////////////////////////////////////////////////////
		// Process the queue of actions to be performed
		///////////////////////////////////////////////////////////////////////////////////////////

		processQueue : function ()
		{
			ready = false;

			while (queue.length > 0)
			{
				var q = queue.shift ();
debug ("Q:" + q[0]);

				switch (q[0])
				{
					case "abort" : // Manual abort
						if (q[1] > 0) queue.length = 0;
						ready = true;
						return;

					case "initEvent" :
debug ("initEvent " + q [1] + "/" + q[2]);
						google.maps.Event.addListener (map, q[1], function ()
						{
//alert (q[2]);
							eval (q[2]);
						});

						break;

					case "callback" :
						eval (q[1]);
						break;

					case "setCenter" :
						map.setCenter (new google.maps.LatLng (q[1], q[2]), parseInt (q[3]));
						break;

					case "setLevel" :
						map.setZoom (parseInt (q[1]));
						break;

					case "addMarker" :
						var mk = _private.createMarker (new google.maps.LatLng (q[1], q[2]), q[3], q[4], q[5], q[6]);
						overlays [q[7]] = mk;
						map.addOverlay (mk);
						break;

					case "addKmlOverlay" :
						var geoXml = new GGeoXml (q[1], function ()
						{
							if (geoXml.loadedCorrectly())
							{
								geoXml.gotoDefaultViewport (map);
				   				map.addOverlay (geoXml);
							}
						});

						overlays [q[2]] = geoXml;
						break;

					case "addToggleButton" :
						var tBtn = new ToggleButton (q[1], q[2], q[3], q[4], q[5], q[6], toggleQty++);
						toggleButtons [q[7]] = overlays [q[7]] = tBtn;
						map.addControl (tBtn);
						break;

					case "settings" :
						eval ('settings.' + q[1] + '= ' + q[2]);
						break;

					case "mapType" :
						var mt = G_NORMAL_MAP;
						var doGE = false;

						switch (q[1])
						{
							case 2 : mt = G_SATELLITE_MAP; break;
							case 3 : mt = G_HYBRID_MAP; break;
							case 4 : mt = G_PHYSICAL_MAP; break;
							case 5 : mt = G_SATELLITE_3D_MAP; doGE = true; break;
						}

						map.setMapType (mt);

						if (doGE) _private.geInit ();
						break;

					case "imgOverlay" :
						if (q[2] > q[4])
						{
							var qx = q[4];
							q[4] = q[2];
							q[2] = qx;
						}

						if (q[3] > q[5])
						{
							var qx = q[5];
							q[5] = q[3];
							q[3] = qx;
						}

						var boundaries = new google.maps.LatLngBounds
						(
							new google.maps.LatLng (q[2], q[3]),
							new google.maps.LatLng (q[4], q[5])
						);

						var img = new google.maps.GroundOverlay (q[1], boundaries);
						overlays [q[6]] = img;
						map.addOverlay (img);
						break;

					case "drawLine" :
						var polyOptions;

						if (q[8] == 1) polyOptions = {geodesic:true};

						q[5] = _private.colourConvert (q[5]);

						var polyline = new google.maps.Polyline ([new google.maps.LatLng (q[1], q[2]),
							new google.maps.LatLng (q[3], q[4])], q[5], q[6], q[7], polyOptions);
						overlays [q[9]] = polyline;
						map.addOverlay (polyline);
						break;

					case "angleLine" :
						var lat = q[1];
						var lng = q[2];
						var col = _private.colourConvert (q[3]);
						var width = q[4];
						var angle = q[5];
						var radius = q[6];
						var opac = q[7];

						var rad = angle * (Math.PI / 180);
						var pX = lat + radius * 1.3 * Math.cos (rad);
						var pY = lng + radius * 0.75 * Math.sin (rad);

						var points = [new google.maps.LatLng (lat, lng), new google.maps.LatLng (pX, pY)];
						var polyline = new google.maps.Polyline (points, col, width, opac);
						overlays [q[8]] = polyline;
						map.addOverlay (polyline);
						break;

					case "drawPolygon" :
						var lns = [];
						var ll = q[1];

						for (i = 0; i < ll.length; i += 2)
						{
							lns.push (new google.maps.LatLng (ll[i], ll[i + 1]));
						}

						lns.push (new google.maps.LatLng (ll[0], ll[1]));
						var polygon = new google.maps.Polygon (lns, _private.colourConvert (q[2]), q[3], q[4],
							_private.colourConvert (q[5]), q[6]);

						overlays [q[7]] = polygon;
						map.addOverlay (polygon);
						break;

					case "remove" :
						if (overlays [q[1]])
						{
							var obj = overlays [q[1]];
							map.removeOverlay (obj);
							overlays [q[1]] = null;
						}

						break;

					case "removeAll" :
						olID = 0;
						map.clearOverlays ();
						break;

					case "streetView" :
						if (q[1] == 1)
						{
							streetView = q[2];
							svDiv = document.getElementById (streetView);
							svDiv.style.width = (parseInt (q[3]) > 0 ? q[3] + "px" : null);
							svDiv.style.height = q[4] + "px";
							var pt = map.getCenter ();
							var pov = {yaw:370.64659986187695, pitch:-20};
							svClient = new google.maps.StreetviewClient ();

							google.maps.Event.addListener (map, "click", function (overlay, latlng)
							{
								svClient.getNearestPanorama (latlng, _private.showSVData);
							});

							svPano = new GStreetviewPanorama (svDiv);
							svPano.setLocationAndPOV (pt, pov);
//GEvent.addListener(myPano, "error", handleNoFlash);
							svClient.getNearestPanorama (pt, _private.showSVData);
						}
						else
						if (streetView != "")
						{
							svDiv.style.width = svDiv.style.height = 0;
							google.maps.Event.removeListener (map, "click");
						}

						break;
				}

				if (setAbort)
				{
					queue.length = 0;
					setAbort = false;
				}
			}
debug ("QE");

			ready = true;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		showSVData : function (dat)
		{
			if (dat.code != 200)
			{
				google.maps.Log.write('showPanoData: Server rejected with code: ' + dat.code);
				return;
			}

			svNextPanoID = dat.links[0].panoId;

			var displayString =
			[
				"Panorama ID: " + dat.location.panoId,
				"LatLng: " + dat.location.latlng,
				"Copyright: " + dat.copyright,
				"Description: " + dat.location.description,
				"Next Pano ID: " + dat.links[0].panoId
			].join ("<br/>");

			map.openInfoWindowHtml (dat.location.latlng, displayString);

			GLog.write('Viewer moved to' + dat.location.latlng);
			svPano.setLocationAndPOV (dat.location.latlng);
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		geInit : function ()
		{
			map.getEarthInstance (function (ge)
			{
				// Direct Earth API calls can go here

				ge.getLayerRoot ().enableLayerById (ge.LAYER_BORDERS, true);  // Turn on borders and labels
			});
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		createMarker : function (point, name, txt, icon, click)
		{
			var marker;

			if (icon != "")
			{
				if (iconDir == null)
				{
					alert ("Marker Image Directory has not been set");
				}
				else
				{
					var mkIcon = new google.maps.Icon (baseIcon);
					mkIcon.shadow = iconDir + "/shadow.png";
					mkIcon.image = iconDir + "/" + icon + ".png";
					marker = new google.maps.Marker (point, mkIcon);
				}
			}
			else
			{
				marker = new google.maps.Marker (point);
			}

			if (name != "" || txt != "")
			{
				if (settings.popupStyle == 0)
				{
					google.maps.Event.addListener (marker, "click", function ()
					{
						marker.openInfoWindowHtml ("<div class='gmtext'><b>" + name +
							"<\/b><br\/><br\/>" + txt + "<\/div>");
					});
				}
				else
				{
					google.maps.Event.addListener (marker, "mouseover", function ()
					{
						mapPos = DLibUtilities.findPos (mapDiv);

						if (settings.popupStyle == 1 || settings.popupStyle == 3)
						{
							namepop = new NamePopup (name);
							map.addControl (namepop);
						}

						if (settings.popupStyle > 1)
						{
							mapInfo.innerHTML = "<b>" + name + "<\/b> " + txt;
						}
					});

					google.maps.Event.addListener (marker, "mouseout", function ()
					{
						if (settings.popupStyle == 1 || settings.popupStyle == 3)
						{
							map.removeControl (namepop);
						}

						if (settings.popupStyle > 1)
						{
							mapInfo.innerHTML = "";
						}
					});
				}
			}

			if (click != "")
			{
			  	GEvent.addListener (marker, "click", function ()
				{
					if (settings.popupStyle == 1 || settings.popupStyle == 3)
					{
						map.removeControl (namepop);
					}

					eval (click);
				});
			}

			return marker;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		initNamePopups : function  ()
		{
			NamePopup.prototype = new google.maps.Control ();

			NamePopup.prototype.initialize = function (map)
			{
				var container = document.createElement ("div");

				this.setButtonStyle_ (container);

				var e = document.createElement ("div");
				e.innerHTML = this.txt;
				container.appendChild (document.createTextNode (e.innerHTML));
				map.getContainer ().appendChild (container);
				return container;
			}

			NamePopup.prototype.getDefaultPosition = function ()
			{
				return new google.maps.ControlPosition (G_ANCHOR_TOP_LEFT, new google.maps.Size (mX + 10, mY - 10));
			}

			NamePopup.prototype.setButtonStyle_ = function (button)
			{
				button.style.color = "black";
				button.style.backgroundColor = "#ffe";
				button.style.font = "small Arial";
				button.style.fontSize = "7pt";
				button.style.border = "1px solid black";
				button.style.padding = "1px";
				button.style.marginBottom = "2px";
				button.style.textAlign = "center";
				button.style.cursor = "pointer";
			}
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		initToggleButtons : function  ()
		{
			ToggleButton.prototype = new GControl ();

			ToggleButton.prototype.initialize = function (map)
			{
				var container = document.createElement ("div");

				var btn = document.createElement ("div");
				btn.id = "tglbtn" + this.ind;
				this.setButtonStyle_ (btn);
				container.appendChild (btn);
				btn.appendChild (document.createTextNode (this.txt));

				GEvent.addDomListener (btn, "click", function ()
				{
					_private.toggleChangeState (btn.id);
				});

				GEvent.addDomListener (btn, "mouseover", function ()
				{
					_private.toggleMouse (btn.id, 1);
				});

				GEvent.addDomListener (btn, "mouseout", function ()
				{
					_private.toggleMouse (btn.id, 0);
				});

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

			ToggleButton.prototype.getDefaultPosition = function ()
			{
				var x = this.x;
				var anchor = G_ANCHOR_TOP_LEFT;

				if (x < 0)
				{
					x = Math.abs (x);
					anchor = G_ANCHOR_TOP_RIGHT;
				}

				return new GControlPosition (anchor, new GSize (x, this.y));
			}

			ToggleButton.prototype.setButtonStyle_ = function (button)
			{
				button.style.font = "small Arial";
				button.style.border = "1px solid black";
				button.style.padding = "0";
				button.style.marginBottom = "3px";
				button.style.textAlign = "center";
				button.style.width = this.w + "px";
				button.style.height = "17px";
				button.style.cursor = "pointer";

				if (this.state == 1)
				{
					button.style.color = "black";
					button.style.backgroundColor = "white";
					button.style.fontWeight = "bold";
				}
				else
				{
					button.style.color = "#999";
					button.style.backgroundColor = "#ddd";
					button.style.fontWeight = "normal";
				}
			}
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		toggleChangeState : function (btn)
		{
			var i = parseInt (btn.substring (6));

			if (i > -1 && i < toggleQty)
			{
				var tb = toggleButtons [i];
				tb.state = 1 - tb.state;
				var btnc = document.getElementById (btn);

				if (tb.state == 1)
				{
					btnc.style.fontWeight = "bold";
					btnc.style.backgroundColor = "white";
					btnc.style.color = "black";
				}
				else
				{
					btnc.style.fontWeight = "normal";
					btnc.style.backgroundColor = "#ddd";
					btnc.style.color = "#999";
				}

				eval (tb.func + " (" + i + ", " + tb.state + ");");
			}
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		toggleMouse : function (btn, md)
		{
			var i = parseInt (btn.substring (6));

			if (i > -1 && i < toggleQty)
			{
				var tb = toggleButtons [i];
				var btnc = document.getElementById (btn);

				if (tb.state == 1)
				{
					btnc.style.fontWeight = "bold";
					btnc.style.backgroundColor = (md == 1 ? "#ffc" : "white");
					btnc.style.color = (md == 1 ? "red" : "black");
				}
				else
				{
					btnc.style.fontWeight = "normal";
					btnc.style.backgroundColor = (md == 1 ? "#eda" : "#ddd");
					btnc.style.color = (md == 1 ? "red" : "#999");
				}
			}
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		mapUses : function (ch)
		{
			return (mapUseList.indexOf (ch) > -1);
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		mapCtrls : function (ch)
		{
			return (mapCtrlList.indexOf (ch) > -1);
		}

		///////////////////////////////////////////////////////////////////////////////////////////
	}

	///////////////////////////////////////////////////////////////////////////////////////////////

	var _public =
	{
		//F////////////////////////////////////////////////////////////////////////////////////////
		// Initialise the maps connection.
		// @init
		///////////////////////////////////////////////////////////////////////////////////////////

		init : function (mapid, uses, ctrls, func, iDir)
		{
debug ("init");
map = null;
mapID;
mapCtrlList;
mapUseList;
mapPos;
mapDiv;
mapInfoID;
mapInfo = null;
earth = null;
iconDir = null;
baseIcon;
queue = [];
setAbort = false;
settings = new Object;
overlays = new Object;
olID = 0;
ready = false;
mX = 0;
mY = 0;
runFunc = "";
streetView = "";
svDiv = null;
svClient = null;
svPano;
svNextPanoID;
toggleButtons = [];
toggleQty = 0;

			if (iDir == undefined) iDir = "";
			if (func == undefined) func = "";

			runFunc = func;
			iconDir = iDir;

			// Initialise some default settings

			settings.popupStyle = 0;

			// Set and load the requested settings

			mapID = mapid;
			mapInfoID = mapid + "info";
			mapUseList = uses;
			mapCtrlList = ctrls;
			google.load ("maps", "2.x");

			if (_private.mapUses ("c")) google.load ("friendconnect", "1");
			if (_private.mapUses ("d")) google.load ("gdata", "1");
			if (_private.mapUses ("e")) google.load ("earth", "1");
			if (_private.mapUses ("f")) google.load ("feeds", "1");
			if (_private.mapUses ("l")) google.load ("language", "1");
			if (_private.mapUses ("s")) google.load ("search", "1");
			if (_private.mapUses ("v")) google.load ("virtualization", "1");

			google.setOnLoadCallback (DLibGMap.run);
debug ("init2");
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		reset : function ()
		{
			mapDiv = document.getElementById (mapID);
			mapPos = DLibUtilities.findPos (mapDiv);
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		run : function ()
		{
debug ("run1");
			_private.initNamePopups ();
			_private.initToggleButtons ();

			// Basic Marker Icon (only used for non-Google markers)

			baseIcon = new google.maps.Icon ();
			baseIcon.iconSize = new google.maps.Size (20, 34);
			baseIcon.shadowSize = new google.maps.Size (37, 34);
			baseIcon.iconAnchor = new google.maps.Point (9, 34);
			baseIcon.infoWindowAnchor = new google.maps.Point (9, 2);
			baseIcon.infoShadowAnchor = new google.maps.Point (18, 25);

			mapDiv = document.getElementById (mapID);

			if (document.getElementById (mapInfoID)) mapInfo = document.getElementById (mapInfoID);

			map = new google.maps.Map2 (mapDiv);

			mapPos = DLibUtilities.findPos (mapDiv);
			mapDiv.onmousemove = DLibGMap.mapMove;

			map.addMapType (G_PHYSICAL_MAP);

			if (_private.mapUses ("e"))
			{
				map.addMapType (G_SATELLITE_3D_MAP);
			}

			if (_private.mapCtrls ("Z1")) map.addControl (new google.maps.SmallZoomControl ());
			if (_private.mapCtrls ("Z2")) map.addControl (new google.maps.SmallZoomControl3D ());
			if (_private.mapCtrls ("Z3")) map.addControl (new google.maps.SmallMapControl ());
			if (_private.mapCtrls ("Z4")) map.addControl (new google.maps.SmallMapControl3D ());
			if (_private.mapCtrls ("Z5")) map.addControl (new google.maps.LargeMapControl ());
			if (_private.mapCtrls ("Z6")) map.addControl (new google.maps.LargeMapControl3D ());

//			if (_private.mapCtrls ("H")) map.addControl (new google.maps.HierarchicalMapTypeControl ());
			if (_private.mapCtrls ("O")) map.addControl (new google.maps.OverviewMapControl ());
			if (_private.mapCtrls ("M")) map.addControl (new google.maps.MenuMapTypeControl ());
			if (_private.mapCtrls ("N")) map.addControl (new google.maps.NavLabelControl ());
			if (_private.mapCtrls ("S")) map.addControl (new google.maps.ScaleControl ());
			if (_private.mapCtrls ("T")) map.addControl (new google.maps.MapTypeControl ());

			if (_private.mapCtrls ("W")) map.enableScrollWheelZoom ();

			map.setMapType (G_NORMAL_MAP);

			if (_private.mapUses ("s"))
			{
				var searchControl = new google.search.SearchControl();
				searchControl.addSearcher(new google.search.WebSearch());
				searchControl.addSearcher(new google.search.NewsSearch());
				searchControl.draw(document.getElementById("searchcontrol"));
			}

			google.maps.Event.addListener (map, "maptypechanged", function ()
			{
				var mt = map.getCurrentMapType ();

				if (mt == G_SATELLITE_3D_MAP) _private.geInit ();
			});

			if (runFunc != "") eval (runFunc);

			gmready = true;

debug ("run2");
			_private.processQueue ();
debug ("run3");
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		initEvent : function (event, f)
		{
			var id = olID++;
			queue.push (["initEvent", event, f, id]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		mapMove : function (eo)
		{
			if (mapPos < 0)
			{
				mapPos = DLibUtilities.findPos (mapDiv);
			}

			mX = null;
			mY = null;

			if (eo != null)
			{
				mX = eo.clientX;
				mY = eo.clientY;
			}
			else
			{
				mX = event.clientX;
				mY = event.clientY;
			}

			mX -= mapPos [0];
			mY -= mapPos [1];
			var off = DLibUtilities.scrollOffset ();
			mX += off [0];
			mY += off [1];
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		setIconDir : function (dir)
		{
			iconDir = dir;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		setLevel : function (level)
		{
			queue.push (["setLevel", level]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		setCenter : function (lat, lng, level)
		{
			queue.push (["setCenter", lat, lng, level]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		setting : function (name, val)
		{
			queue.push (["settings", name, val]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		addMarker : function (lat, lng, name, txt, icon, click)
		{
			if (icon == undefined) icon = "";
			var id = olID++;
			queue.push (["addMarker", lat, lng, name, txt, icon, click, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		imgOverlay : function (imgUrl, lat1, lng1, lat2, lng2)
		{
			var id = olID++;
			queue.push (["imgOverlay", imgUrl, lat1, lng1, lat2, lng2, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		drawLine : function (lat1, lng1, lat2, lng2, colour, width, opac)
		{
			if (opac == undefined) opac = 1;
			var id = olID++;
			queue.push (["drawLine", lat1, lng1, lat2, lng2, colour, width, opac, 0, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		angleLine : function (lat, lng, colour, width, angle, radius, opac)
		{
			if (opac == undefined) opac = 1;
			var id = olID++;
			queue.push (["angleLine", lat, lng, colour, width, angle, radius, opac, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		drawPolygon : function (ll, lcol, lwidth, lopac, fcol, fopac)
		{
			var id = olID++;
			queue.push (["drawPolygon", ll, lcol, lwidth, lopac, fcol, fopac, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		remove : function (id)
		{
			queue.push (["remove", id]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		removeAll : function ()
		{
			queue.push (["removeAll"]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		setMapType : function (mt)
		{
			queue.push (["mapType", mt]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		enableStreetView : function (name, width, height)
		{
			queue.push (["streetView", 1, name, width, height]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		disableStreetView : function ()
		{
			queue.push (["streetView", 0]);
			if (ready) _private.processQueue ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		addKmlOverlay : function (file)
		{
			var id = olID++;
			queue.push (["addKmlOverlay", file, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		addToggleButton : function (txt, x, y, w, func, state)
		{
			var id = olID++;
			queue.push (["addToggleButton", txt, x, y, w, func, state, id]);
			if (ready) _private.processQueue ();
			return id;
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		addMapGeoClick : function (func, key, ajaxVar)
		{
			google.maps.Event.addListener (map, "click", function (overlay, point)
			{
				var d = new Date ();
				var e = ajaxVar + ' = DLibUtilities.initAjax ("/dlib/php/gmgeo.php?lat=" + ' +
					'point.y + "&lng=" + point.x + "&key=" + key + "&tm=" + d.getTime(), func);';
				eval (e);
			});
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		setMapCursor : function (type)
		{
			map.getDragObject ().setDraggableCursor (type);
		},

		///////////////////////////////////////////////////////////////////////////////////////////
		//
		///////////////////////////////////////////////////////////////////////////////////////////

		mapReady : function (cb)
		{
			if (map == null)
			{
				if (!gmready) DLibGMap.run ();

				if (cb != "")
				{
					var id = olID++;
					queue.push (["callback", cb, id]);
					if (ready) _private.processQueue ();
				}

				return false;
			}

			return true;
		},

		///////////////////////////////////////////////////////////////////////////////////////////
		// Returns the current map bounds as an array of top, right, bottom, left, db where db is
		// true if the map crosses the 180 degree line.
		///////////////////////////////////////////////////////////////////////////////////////////

		getBounds : function ()
		{
			var	bounds = map.getBounds ();
			var	southWest = bounds.getSouthWest ();
			var	northEast = bounds.getNorthEast ();
			var db = (southWest.lng () > 0 && northEast.lng () < 0);

			return [northEast.lat (), northEast.lng (), southWest.lat (), southWest.lng (), db];
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		panTo : function (lat, lng)
		{
			map.panTo (new google.maps.LatLng (lat, lng));
		},

		///////////////////////////////////////////////////////////////////////////////////////////

		closeMap : function ()
		{
			if (ready)
			{
				queue.length = 0;
			}
			else
			{
				setAbort = true;
			}

			map.clearOverlays ();
		},

		///////////////////////////////////////////////////////////////////////////////////////////

showDebug : function ()
{
	alert (dbTxt);
	dbTxt = "";
},

getDebug : function ()
{
	var t = dbTxt;
	dbTxt = "";
	return t;
},

		///////////////////////////////////////////////////////////////////////////////////////////

		abortQueue : function ()
		{
			if (ready)
			{
				queue.length = 0;
			}
			else
			{
				setAbort = true;
			}
		}
	};

	return _public;
} ();

///////////////////////////////////////////////////////////////////////////////////////////////////


