function GMapInit() {
	if (GBrowserIsCompatible()) {
		map = new GMap2(document.getElementById("map"), {logoPassive:true});
		map.addControl(new GLargeMapControl());
		map.addControl(new GMapTypeControl());
//		map.addControl(new GScaleControl());
//		map.addControl(new GOverviewMapControl());
		map.enableDoubleClickZoom();
		// Get Data from External XML
		var url = "obf-data.xml";
		var request = GXmlHttp.create();
		request.open("GET", url, true);
		request.onreadystatechange = function() {
			if (request.readyState == 4) {
				var xmlDoc = request.responseXML;
				//
				// Set Map Extents and Zoom Level
				var lng, lat, zoom, slat, nlat, elng, wlng;
				try {
					var mapcenter = xmlDoc.getElementsByTagName("mapcenter");
					// Longitude
					lng = parseFloat(mapcenter[0].getAttribute("lng"));
					if (lng == null ) lng = -90;
					// Latitude
					lat = parseFloat(mapcenter[0].getAttribute("lat"));
					if (lat == null) lat = 35;
					// Zoom
					zoom = mapcenter[0].getAttribute("zoom");
					if (zoom == null) zoom = 5;
					// Test if Zoom is set to 'Auto'
					if (zoom == 'auto') {
						slat = parseFloat(mapcenter[0].getAttribute("slat"));
						nlat = parseFloat(mapcenter[0].getAttribute("nlat"));
						elng = parseFloat(mapcenter[0].getAttribute("elng"));
						wlng = parseFloat(mapcenter[0].getAttribute("wlng"));
						lat = (slat + nlat) / 2;
						lng = (elng + wlng) / 2;
						zoom = map.getBoundsZoomLevel(new GLatLngBounds(new GLatLng(slat,wlng), new GLatLng(nlat,elng)));
					}
					if (lng == 'NaN') lng = -90;
					if (lat == 'NaN') lat = 35;
					if (zoom == 'NaN') zoom = 5;
				} catch(e) {}
				map.setCenter(new GLatLng(lat,lng), zoom);
				//
				// Build Polygons
				var strokeColor, strokeWeight, strokeOpacity, fillColor, fillOpacity;
				var points, point_ary, group, range, tlat, tlng, tmp_point;
				var polygons = xmlDoc.getElementsByTagName("polygon");
				for (var i=0; i<polygons.length; i++) {
					// Get Group Name
					group = polygons[i].getAttribute("group");
					// Set Polygon Stroke Color
					strokeColor = polygons[i].getAttribute("strokeColor");
					if (strokeColor == null) strokeColor = "#FF00FF";
					// Set Polygon Stroke Weight
					strokeWeight = polygons[i].getAttribute("strokeWeight");
					if (strokeWeight == null) strokeWeight = 5;
					// Set Polygon Stroke Opacity
					strokeOpacity = polygons[i].getAttribute("strokeOpacity");
					if (strokeOpacity == null) strokeOpacity = 1.00;
					// Set Polygon Fill Color
					fillColor = polygons[i].getAttribute("fillColor");
					if (fillColor == null) fillColor = "#0000FF";
					// Set Polygon Fill Opacity
					fillOpacity = polygons[i].getAttribute("fillOpacity");
					if (fillOpacity == null) fillOpacity = 0.65;
					// Set Polygon Points
					point_ary = new Array();
					points = polygons[i].getElementsByTagName("point");
					for (var j=0; j<points.length; j++) {
						tlat = points[j].getAttribute("lat");
						tlng = points[j].getAttribute("lng");
						if (!isNaN(tlat) && !isNaN(tlng)) point_ary.push(new GLatLng(parseFloat(tlat),parseFloat(tlng)));
					}
					range = new GPolygon(point_ary, strokeColor, strokeWeight, strokeOpacity, fillColor, fillOpacity);
//					range = new GPolygon(point_ary, '#000000', 1, 1, '#000000', 0.65);
					if (!markerMgr[group]) markerMgr.add(group);
					markerMgr[group].markers.push(range);
					markerMgr[group].size++;
				}
				//
				// Build Icons
				var x, y, name, icon;
				var icons = xmlDoc.getElementsByTagName("icon");
				for (var i=0; i<icons.length; i++) {
					name = icons[i].getAttribute("name");
					icon = new GIcon();
					icon.image = icons[i].getElementsByTagName("image")[0].getAttribute("src");
					// Icon Anchor
					x = icons[i].getAttribute("xanchor");
					y = icons[i].getAttribute("yanchor");
					if (x!=null && y!=null && x && y) {
						icon.iconAnchor = new GPoint(parseInt(x),parseInt(y));
					}
					else icon.iconAnchor = new GPoint(0,0);
					// Icon Info Window Anchor
					x = icons[i].getAttribute("xiwanchor");
					y = icons[i].getAttribute("yiwanchor");
					if (x!=null && y!=null && x && y) {
						icon.infoWindowAnchor = new GPoint(parseInt(x),parseInt(y));
					}
					else icon.infoWindowAnchor = new GPoint(0,0);
					// Icon Info Window Shadow Anchor
					x = icons[i].getAttribute("xisanchor");
					y = icons[i].getAttribute("yisanchor");
					if (x!=null && y!=null && x && y) {
						icon.infoShadowAnchor = new GPoint(parseInt(x),parseInt(y));
					}
					else icon.infoShadowAnchor = new GPoint(0,0);
					// Icon Image Height and Width
					try {
						x = icons[i].getElementsByTagName("image")[0].getAttribute("width");
						y = icons[i].getElementsByTagName("image")[0].getAttribute("height");
						if (x!=null && y!=null && x && y) {
							icon.iconSize = new GSize(parseInt(x),parseInt(y));
						}
						else icon.iconSize = new GSize(16,16);
					} catch(e) {}
					// Shadow Image
					try {
						x = icons[i].getElementsByTagName("shadow")[0].getAttribute("src");
						if (x!=null && x) {
							icon.shadow = x;
						}
						else icon.shadow = null;
					} catch(e) {}
					// Icon Shadow Dimensions
					try {
						x = icons[i].getElementsByTagName("shadow")[0].getAttribute("width");
						y = icons[i].getElementsByTagName("shadow")[0].getAttribute("height");
						if (x!=null && y!=null && x && y) {
							icon.shadowSize = new GSize(parseInt(x),parseInt(y));
						}
						else icon.shadowSize = null;
					} catch(e) {}
					icon_ary[name] = icon;
				}
				//
				// Build Markers
				var point, iconname, html, marker;
				var markers = xmlDoc.getElementsByTagName("marker");
				for (var i=0; i<markers.length; i++) {
					point = new GLatLng( parseFloat(markers[i].getAttribute("lat")), parseFloat(markers[i].getAttribute("lng")));
					iconname = markers[i].getAttribute("iconname");
					if (iconname == null) iconname = "";
					try {
						html = markers[i].getElementsByTagName("infowindow")[0].firstChild.nodeValue;
					} catch(e) { html = null; }
					marker = createMarker(point,html,iconname);
					if (!markerMgr[iconname]) markerMgr.add(iconname);
					markerMgr[iconname].markers.push(marker);
					markerMgr[iconname].size++;
				}
				//
				// Add All Overlays
				var mObj;
				for (var i=0; i<markerMgr.keys.length; i++) {
					mObj = markerMgr[markerMgr.keys[i]];
					for (var j=0; j<mObj.markers.length; j++) {
						map.addOverlay(mObj.markers[j]);
					}
					createButton(mObj);
				}
			}
		}
		request.send(null);
	}
} // GMapInit()

function createMarker(p,h,i) {
	var m, isClickable, whichIcon;
	isClickable =  (h == null ? false : true);
	whichIcon = (i && icon_ary[i] ? icon_ary[i] : G_DEFAULT_ICON);
	var m = new GMarker(p, {icon:whichIcon, clickable:isClickable});
	if (h != null) {
		GEvent.addListener(m, "click", function() {
			m.openInfoWindowHtml(h);
		});
	}
	return m;
} // createMarker()

function createButton(o) {
	var controls, btn;
	controls = document.getElementById("controls");
	btn = document.createElement("button");
	btnImg = document.createElement("img");
	if (icon_ary[o.label] != undefined) {
		btnImg.setAttribute("src", icon_ary[o.label].image);
		btn.appendChild(btnImg);
	}
	btn.appendChild(document.createTextNode(o.label.replace("_", " ") + ": " + o.size));
	controls.appendChild(btn);
	btn.onclick = function() {
		o.active = (o.active ? false : true);
		for (var i=0; i<o.markers.length; i++){
			o.active ? map.addOverlay(o.markers[i]) : map.removeOverlay(o.markers[i]);
		}
	}
} // createButton()

function myObj(o) {
	this.active = true;
	this.markers = new Array();
	this.size = 0;
	this.label = "";
}

function myMarkerManager() {
	this.keys = new Array();
}

myMarkerManager.prototype.add = function(n) {
	this.keys.push(n);
	this[n] = new myObj;
	this[n].label = n;
} // myMarkerManager.add()

///// Variable Initialization
var map;
var icon_ary = new Array();
var markerMgr = new myMarkerManager();

///// addLoadEvents
addLoadEvent(GMapInit);
addUnloadEvent(GUnload);