(function($) {
	// Default center point is roughly in the center of the
	// United States (somewhere in Kansas). Default zoom
	// shows entire United States in a 4:3 element.
	var mapDefaults = {
		latitude: 38,
		longitude: -97,
		zoom: 4
	};

	// Default icon is the recognizable red push-pin.
	var iconDefaults = {
		image: "http://www.google.com/mapfiles/marker.png",
		shadow: "http://www.google.com/mapfiles/shadow50.png",
		iconSize: { width: 20, height: 34 },
		shadowSize: { width: 37, height: 34}
	};

	$.fn.setCenter = function(options) {
		return this.each(function() {
			// Return if map isn't found.

			var googleMap = $(this).data("googleMap");

			if (googleMap === undefined) {
				return;
			}

			googleMap.setCenter(
				new GLatLng(options.latitude, options.longitude),
				options.zoom
			);
		});
	};

	$.fn.clearMarkers = function() {
		return this.each(function() {
			// Return if map isn't found.

			var googleMap = $(this).data("googleMap");

			if (googleMap === undefined) {
				return;
			}

			googleMap.clearOverlays();
		});
	};

	$.fn.addMarkers = function(options) {
		return this.each(function() {
			// Return if map isn't found.

			var googleMap = $(this).data("googleMap");

			if (googleMap === undefined) {
				return;
			}

			var defaults = $.extend({}, iconDefaults, options.defaults);

			$.each(options.markers, function(n, marker) {
				// Extend defaults with specified options
				// and create and add the marker.

				marker.icon = $.extend({}, defaults, marker.icon);

				if (marker.icon.iconAnchor === undefined) {
					marker.icon.iconAnchor = {
						x: marker.icon.iconSize.width / 2,
						y: marker.icon.iconSize.height
					};
				}

				if (marker.icon.infoWindowAnchor === undefined) {
					marker.icon.infoWindowAnchor = {
						x: marker.icon.iconSize.width / 2,
						y: 0
					};
				}

				var gicon = new GIcon();

				gicon.image = marker.icon.image;
				gicon.shadow = marker.icon.shadow;
				gicon.iconSize = new GSize(
					marker.icon.iconSize.width,
					marker.icon.iconSize.height
				);
				gicon.shadowSize = new GSize(
					marker.icon.shadowSize.width,
					marker.icon.shadowSize.height
				);
				gicon.iconAnchor = new GPoint(
					marker.icon.iconAnchor.x,
					marker.icon.iconAnchor.y
				);
				gicon.infoWindowAnchor = new GPoint(
					marker.icon.infoWindowAnchor.x,
					marker.icon.infoWindowAnchor.y
				);

				var gmarker = new GMarker(
					new GPoint(marker.longitude, marker.latitude),
					{ icon: gicon }
				);

				googleMap.addOverlay(gmarker);

				// Setup event for clicking the icon to see tooltip.
				if (marker.information) {
					GEvent.addListener(gmarker, "click", function() {
						this.openInfoWindowHtml(
							"<div class='gmap_marker'>"
							+ marker.information
							+ "</div>"
						);
					});
				}
			});
		});
	};

	$.fn.googleMap = function(options) {
		if (!window.GBrowserIsCompatible || !GBrowserIsCompatible()) {
			return this;
		}

		options = $.extend({}, mapDefaults, options);

		return this.each(function() {
			googleMap = new GMap2(this);

			googleMap.setUIToDefault();
			googleMap.enableScrollWheelZoom();

			// It seems like the API should provide the new bounds
			// to the listener. The specified callback, if any, is
			// wrapped so that the bounds can be provided.
			if ($.isFunction(options.moveEnd)) {
				GEvent.addListener(
					googleMap,
					"moveend",
					function() {
						var bounds = this.getBounds();
						
						options.moveEnd({
							southWest: {
								latitude: bounds.getSouthWest().lat(),
								longitude: bounds.getSouthWest().lng()
							},
							northEast: {
								latitude: bounds.getNorthEast().lat(),
								longitude: bounds.getNorthEast().lng()
							}
						});
					}
				);
			}

			googleMap.setCenter(
				new GLatLng(options.latitude, options.longitude),
				options.zoom
			);

			// Save it for later.
			$(this).data("googleMap", googleMap);
		});
	};
})(jQuery);
