function GoogleMap()
{
	var baseObject = this;
	var googleMapArray = new Object();


	this._SetPoint = function(pointJSON, mapName, position)
	{
		// Verify location was found
		if (pointJSON.Placemark)
		{
			googleMapArray[mapName].points[position].latitude = pointJSON.Placemark[0].Point.coordinates[1];
			googleMapArray[mapName].points[position].longitude = pointJSON.Placemark[0].Point.coordinates[0];
	
	
			if (googleMapArray[mapName].points[position].onGeocode != null)
			{
				googleMapArray[mapName].points[position].onGeocode(googleMapArray[mapName].points[position]);
			}
		}

		// This is the only point to load on the map
		else if (googleMapArray[mapName].points.length == 1)
		{
			var originalAddress = googleMapArray[mapName].points[0].address;
			var address = googleMapArray[mapName].points[0].city + " " + googleMapArray[mapName].points[0].state;
			var geocoder = new GClientGeocoder();
			var centerMap = function(ptJSON)
			{
				var msg = "Address (" + originalAddress + ") could not be located.";
				
				// Verify location was found
				if (ptJSON.Placemark)
				{
					googleMapArray[mapName].points[0].altLatitude = ptJSON.Placemark[0].Point.coordinates[1];
					googleMapArray[mapName].points[0].altLongitude = ptJSON.Placemark[0].Point.coordinates[0];
					
					msg += " Instead the map has attempted to center on the city the address is located in.";
				}

				alert(msg);
			};

			geocoder.getLocations(address, centerMap);
		}
	}


	this.AddMapPoint = function(attributes)
	{
		// Create map object and add it to the array
		if (!googleMapArray[attributes.mapName])
		{
			var mapObj = new Object();
			mapObj.points = new Array();
	
			googleMapArray[attributes.mapName] = mapObj;
		}


		var pointInfo = new Object();
		pointInfo.address = attributes.address;
		pointInfo.city = attributes.city;
		pointInfo.state = attributes.state;
		pointInfo.country = attributes.country;
		pointInfo.latitude = attributes.latitude;
		pointInfo.longitude = attributes.longitude;
		pointInfo._loaded = false;
		pointInfo.title = attributes.title;
		pointInfo.infoWindowID = attributes.infoWindowID;
		pointInfo.marker = null;
		pointInfo.center = attributes.center;
		pointInfo.initShow = attributes.show;
		pointInfo.zoomLevel = attributes.zoomLevel;
		pointInfo.customIcon = attributes.customIcon;
		pointInfo.onGeocode = attributes.onGeocode;


		position = googleMapArray[attributes.mapName].points.push(pointInfo);
		position--;


		if ((attributes.latitude == null || attributes.longitude == null) && attributes.address != null)
		{
			// Position Reference Fix
			var runGeocoder = function(position)
			{
				var pos = position;
				var geocoder = new GClientGeocoder();
				geocoder.getLocations(attributes.address, function(pointJSON) {baseObject._SetPoint(pointJSON, attributes.mapName, pos);});
			}

			runGeocoder(position);
		}
	}


	this.AddMap = function(mapName, bgColor, mapTypes, panZoomType, showMapType, showOverview, showPanZoom, showScale, pointCount, latitude, longitude)
	{
		var mTypes = GetMapTypes(mapTypes);
		var pzType = GetPanZoomType(panZoomType);

		var map = new GMap2(document.getElementById(mapName), {backgroundColor: bgColor, mapTypes: eval(mTypes)});

		map.enableContinuousZoom();
		map.enableScrollWheelZoom();

		if (showMapType)
		{
			map.addControl(new GMapTypeControl());
		}
		if (showOverview)
		{
			map.addControl(new GOverviewMapControl());
		}
		if (showPanZoom)
		{
			map.addControl(eval("new " + pzType));
		}
		if (showScale)
		{
			map.addControl(new GScaleControl());
		}
		if (latitude != null && longitude != null)
		{
			map.setCenter(new GLatLng(latitude, longitude), 0);
		}


		// Create map object and add it to the array
		if (!googleMapArray[mapName])
		{
			var mapObj = new Object();
			mapObj._loaded = false;
			mapObj.map = map;
			mapObj.points = new Array();
			mapObj.pointCount = pointCount;
			mapObj.pointLoadAttempts = 0;
	
			googleMapArray[mapName] = mapObj;
		}
		else
		{
			googleMapArray[mapName]._loaded = false;
			googleMapArray[mapName].map = map;
			googleMapArray[mapName].pointCount = pointCount;
			googleMapArray[mapName].pointLoadAttempts = 0;
		}


		LoadPoints(mapName);
	}


	this.GetMap = function(mapName)
	{
		var map = null;

		if (googleMapArray[mapName])
		{
			map = googleMapArray[mapName].map;
		}

		return map;	
	}


	this.GetMapObject = function(mapName)
	{
		var mapObject = null;

		if (googleMapArray[mapName])
		{
			mapObject = googleMapArray[mapName];
		}

		return mapObject;	
	}


	this.GetMapPoint = function(mapName, pointPosition)
	{
		var point = null

		if (googleMapArray[mapName])
		{
			if (pointPosition >= 0 && pointPosition < googleMapArray[mapName].points.length)
			{
				point = googleMapArray[mapName].points[pointPosition].marker;
			}
		}

		return point;
	}


	this.GetMapPoints = function(mapName)
	{
		var points = new Array();

		if (googleMapArray[mapName])
		{
			for (var i = 0; i < googleMapArray[mapName].points.length; i++)
			{
				points.push(googleMapArray[mapName].points[i].marker);
			}
		}

		return points;
	}


	this.GetMapPointObject = function(mapName, pointPosition)
	{
		var pointObject = null

		if (googleMapArray[mapName])
		{
			if (pointPosition >= 0 && pointPosition < googleMapArray[mapName].points.length)
			{
				pointObject = googleMapArray[mapName].points[pointPosition];
			}
		}

		return pointObject;
	}


	function GetMapTypes(mapTypes)
	{
		mapTypes = mapTypes.toLowerCase();
		var mTypes = "";


		if (mapTypes.search(/normal/) > -1)
		{
			mTypes = "G_NORMAL_MAP";
		}


		if (mapTypes.search(/satellite/) > -1)
		{
			if (mTypes.length > 0)
			{
				mTypes += ",";
			}
			mTypes += "G_SATELLITE_MAP";
		}


		if (mapTypes.search(/hybrid/) > -1)
		{
			if (mTypes.length > 0)
			{
				mTypes += ",";
			}
			mTypes += "G_HYBRID_MAP";
		}


		if (mapTypes.search(/physical/) > -1)
		{
			if (mTypes.length > 0)
			{
				mTypes += ",";
			}
			mTypes += "G_PHYSICAL_MAP";
		}


		mTypes = "[" + mTypes + "]";


		if (mapTypes.search(/default/) > -1)
		{
			mTypes = "G_DEFAULT_MAP_TYPES";
		}

		return mTypes;
	}


	function GetPanZoomType(panZoomType)
	{
		var pzType = "";

		switch (panZoomType)
		{
			case "small":
				pzType = "GSmallMapControl()";

			case "smallZoom":
				pzType = "GSmallZoomControl()";

			case "smallZoom3D":
				pzType = "GSmallZoomControl3D()";

			case "large":
				pzType = "GLargeMapControl()";

			default:
				pzType = "GLargeMapControl3D()";
		}

		return pzType;
	}


	function LoadPoints(mapName)
	{
		googleMapArray[mapName].pointLoadAttempts++;

		var point = null;
		var marker = null;
		var markerOptions = null;
		var pointsLoaded = true;
		var infoWindow = null;
		var opener = null;


		for (var i = 0; i < googleMapArray[mapName].points.length; i++)
		{
			if (!googleMapArray[mapName].points[i]._loaded && googleMapArray[mapName].points[i].latitude != null)
			{
				googleMapArray[mapName].points[i]._loaded = true;

				point = new GLatLng(googleMapArray[mapName].points[i].latitude, googleMapArray[mapName].points[i].longitude);

				// Load Marker options
				if (googleMapArray[mapName].points[i].title.length > 0 || googleMapArray[mapName].points[i].customIcon != null)
				{
					markerOptions = {title: "", icon: null};
					if (googleMapArray[mapName].points[i].customIcon != null)
					{
						markerOptions.icon = googleMapArray[mapName].points[i].customIcon();
						googleMapArray[mapName].points[i].customIcon = null;
					}
					
					markerOptions.title = googleMapArray[mapName].points[i].title;
				}

				googleMapArray[mapName].points[i].marker = new GMarker(point, markerOptions);

				// Bind info window
				if (googleMapArray[mapName].points[i].infoWindowID != null && googleMapArray[mapName].points[i].infoWindowID != "")
				{
					infoWindow = document.getElementById(googleMapArray[mapName].points[i].infoWindowID);

					googleMapArray[mapName].points[i].marker.bindInfoWindowHtml(infoWindow.innerHTML);
					infoWindow.parentNode.removeChild(infoWindow);
				}

				googleMapArray[mapName].map.addOverlay(googleMapArray[mapName].points[i].marker);

				// Hide if not init shown
				if (!googleMapArray[mapName].points[i].initShow)
				{
					googleMapArray[mapName].points[i].marker.hide();
				}
			}
			else if (!googleMapArray[mapName].points[i]._loaded)
			{
				pointsLoaded = false;
			}
		}


		// Attempt a reload
		if (
				googleMapArray[mapName].pointLoadAttempts <= 5 && 
				(
					googleMapArray[mapName].points.length != googleMapArray[mapName].pointCount ||
					!pointsLoaded
				)
			)
		{
			var caller = function() {LoadPoints(mapName);};
			setTimeout(caller, 500);
			return;
		}


		// Set Loaded property and center map
		if (
				(
				 	googleMapArray[mapName].points.length == googleMapArray[mapName].pointCount || 
					googleMapArray[mapName].pointCount == 0
				) &&
				pointsLoaded
			)
		{
			googleMapArray[mapName]._loaded = true;
			ResizeAndCenterMap(mapName);
		}

		if (
				(
				 	googleMapArray[mapName].points.length == googleMapArray[mapName].pointCount || 
					googleMapArray[mapName].pointCount == 0
				) &&
				!pointsLoaded && 
				googleMapArray[mapName].pointLoadAttempts > 5				
			)
		{
			ResizeAndCenterMap(mapName);
		}
	}


	function ResizeAndCenterMap(mapName)
	{
		if (googleMapArray[mapName].points.length == 1)
		{
			if (googleMapArray[mapName].points[0]._loaded)
			{
				if (googleMapArray[mapName].points[0].zoomLevel != null)
				{
					var zoomLevel = googleMapArray[mapName].points[0].zoomLevel;
				}
				else
				{
					var zoomLevel = 14;
				}
	
				googleMapArray[mapName].map.setCenter(new GLatLng(googleMapArray[mapName].points[0].latitude, googleMapArray[mapName].points[0].longitude), zoomLevel);
			}
			else if (googleMapArray[mapName].points[0].altLatitude)
			{
				if (googleMapArray[mapName].points[0].zoomLevel != null)
				{
					var zoomLevel = googleMapArray[mapName].points[0].zoomLevel;
				}
				else
				{
					var zoomLevel = 14;
				}
	
				googleMapArray[mapName].map.setCenter(new GLatLng(googleMapArray[mapName].points[0].altLatitude, googleMapArray[mapName].points[0].altLongitude), zoomLevel);
			}
		}
		else if (googleMapArray[mapName].points.length > 1)
		{
			var minLatitude = null;
			var maxLatitude = null;
			var minLongitude = null;
			var maxLongitude = null;

			var centerLatitude = null;
			var centerLongitude = null;


			for (var i = 0; i < googleMapArray[mapName].points.length; i++)
			{
				if (minLatitude == null || googleMapArray[mapName].points[i].latitude < minLatitude)
				{
					minLatitude = googleMapArray[mapName].points[i].latitude;
				}


				if (maxLatitude == null || googleMapArray[mapName].points[i].latitude > maxLatitude)
				{
					maxLatitude = googleMapArray[mapName].points[i].latitude;
				}


				if (minLongitude == null || googleMapArray[mapName].points[i].longitude < minLongitude)
				{
					minLongitude = googleMapArray[mapName].points[i].longitude;
				}


				if (maxLongitude == null || googleMapArray[mapName].points[i].longitude > maxLongitude)
				{
					maxLongitude = googleMapArray[mapName].points[i].longitude;
				}

				if (centerLatitude == null && googleMapArray[mapName].points[i].center)
				{
					centerLatitude = googleMapArray[mapName].points[i].latitude;
					centerLongitude = googleMapArray[mapName].points[i].longitude;
				}
			}


			var southWestCorner = new GLatLng(minLatitude, minLongitude);
			var northEastCorner = new GLatLng(maxLatitude, maxLongitude);
			var bounds = new GLatLngBounds(southWestCorner, northEastCorner);
			var zoomLevel = googleMapArray[mapName].map.getBoundsZoomLevel(bounds);

			googleMapArray[mapName].map.setCenter(bounds.getCenter(), zoomLevel);

			if (centerLatitude != null)
			{
				googleMapArray[mapName].map.setCenter(new GLatLng(centerLatitude, centerLongitude), zoomLevel);
			}
		}
	}
}
