(function($) {
	$.extend($.fn, {
		googlemap: function(options) {
			/*
			 *		Set Defaults
			 */
			var defaults = {
				mapType: 'roadmap',
				zoom: 8,
				markers: [
					'center'
				],
				markerAnimation: 'none',
				markerIcon: 'none'
			}
			
			/*
			 *		Set Settings
			 */
			var settings = $.extend(defaults,options);
			switch(settings.mapType) {
				default:
				case "roadmap":
					settings.mapType = google.maps.MapTypeId.ROADMAP;
					break;
			}
			
			/*
			 *		Extend Prototypes
			 */
			google.maps.Marker.prototype.addBubble = function(options) {
				if (!this.hasBubble ) {
					this.hasBubble = true;
					var defaults = {
								map: this.getMap(),
								pixelOffset: new google.maps.Size(20, -30),
								position: this.getPosition()
							},
							settings = {},
							bubble, close;
					$.extend(settings,defaults,options);
					bubble = new google.maps.InfoWindow({
						map: settings.map,
						content: settings.content,
						pixelOffset: settings.pixelOffset,
						position: settings.position
					});
					close = bubble.close;
					bubble.close = function(clse, marker, options) {
						return function() {
							marker.hasBubble = false;
							google.maps.event.addListener(marker,'click',function(marker,options) {
								return function() {
									marker.addBubble(options);
								}
							}(marker,options));
							clse.apply(this);
						}
					}(close, this, settings);
					google.maps.event.addListener(bubble,'closeclick',function(marker,options) {
						return function() {
							marker.hasBubble = false;
							google.maps.event.addListener(marker,'click',function(marker,options) {
								return function() {
									marker.addBubble(options);
								}
							}(marker,options));
						}
					}(this, settings));
					google.maps.event.addListener(this,'mousedown',function(b,s) {
						return function(e) {
							this.mouseDown = true;
							setTimeout(function(m,b) {
								return function() {
									if (m.mouseDown) {
										b.close();
										m.hasBubble = false;
									}
								}
							}(this,b),150);
							
							google.maps.event.addListener(this,'mouseup',function(o,b) {
								return function(e) {
									this.mouseDown = false;
									options = $.extend(o,{position: new google.maps.LatLng(e.latLng.lat(),e.latLng.lng())})
									this.addBubble(options);
								}
							}(s,b))
						}
					} (bubble,settings));
					this.bubble = bubble;
				}
			}
			return this.each(function() {
				$(this).addClass('map');
				settings.mapTypeId = settings.mapType;
				settings.center = new google.maps.LatLng(settings.lat, settings.lng);
				var Map = new google.maps.Map(this, settings);
				$.extend(Map,{
					rad: function(x) {return x*Math.PI/180;},
					settings: settings,
					measure: function(p1, p2, r) {
					  if ( ! r ) r = 0.621371192;
					  var R = 6371; // earth's mean radius in km
					  var dLat  = this.rad(p2.lat() - p1.lat());
					  var dLong = this.rad(p2.lng() - p1.lng());
					
					  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
					          Math.cos(this.rad(p1.lat())) * Math.cos(this.rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
					  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
					  var d = R * c;
					
					  return ( d.toFixed(3) * r );
					}
				});
				$.extend(this,{
					getMap: function(m) {
						return function() {
							return m;
						}
					}(Map),
					markers: [],
					geocoders: [],
					markerImages: [],
					addMarker: function(options) {
						var defaults = {
							position: this.getMap().getCenter(),
							map: this.getMap(),
							animation: function(a) {
								switch(a) {
									case 'drop':
										return google.maps.Animation.DROP;
										break;
									default:
										return null;
										break;
								}
							} (this.getMap().settings.markerAnimation),
							icon: this.getMap().settings.markerIcon == 'none' ? null : this.getMap().settings.markerIcon
						}
						var settings = $.extend(defaults,options);
						this.markers.push(new google.maps.Marker({
							position: settings.position,
							map: settings.map,
							animation: settings.animation,
							icon: settings.icon
						}));
						return this.markers[this.markers.length - 1];
					},
					hideMarkers: function() {
						for(i in this.markers) {
							this.markers[i].setVisible(false);
						}
					},
					addMarkerType: function(options) {
						var defaults = {
							map: this.getMap(),
							name: null,
							icon: this.getMap().markerIcon == 'none' ? null : this.getMap().markerIcon
						},
							settings = $.extend(defaults,options);
						
						
					},
					closeBubbles: function() {
						for(i in this.markers) {
							if (this.markers[i].hasBubble) {
								this.markers[i].bubble.close();
							}
						}
					},
					fitBounds: function(options) {
						var defaults = {
							map: this.getMap(),
							positions: [],
							addMarkers: false
						}
						var settings = $.extend(defaults,options);
						if (typeof settings.positions[settings.positions.length-1] === 'undefined') return;
						var bounds = new google.maps.LatLngBounds(),
							current;
						for (i in settings.positions) {
							current = settings.positions[i].length == 2 ? new google.maps.LatLng(settings.positions[i][0],settings.positions[i][1]) : settings.positions[i];
							bounds.extend(current);
							if (settings.addMarkers) this.addMarker({position: current})
						}
						settings.map.fitBounds(bounds);
					},
					geocode: function(options) {
						/**
						 *	Set Defaults
						 */
						var defaults = {
							latlng: 0,
							sensor: false,
							dataType: 'json',
							cb: function() {}
						},
							settings = {},
							params = {};
						
						/**
						 *	Set Settings
						 */
						$.extend(settings, defaults, options);
						
						$.extend(params,function(a,b) {
							if (a) return {latlng: a};
							return {address: b};
						}(settings.latlng,settings.address));
						var geocoder = new google.maps.Geocoder();
						geocoder.geocode(params,settings.cb);
					}
				});
				if (settings.markers && settings.markers.length) {
					$.each(settings.markers, function(map, googlemap) {
						return function() {
							if (this == 'center') {
								map.addMarker();
							} else if ((typeof this[0] === 'number') && (typeof this[1] === 'number')) {
								map.addMarker({
									position: new google.maps.LatLng(this[0],this[1])
								})
							} else if ( typeof this == 'function' ) {
								var coords = this(googlemap);
								map.addMarker({
									position: new google.maps.LatLng(coords[0],coords[1])
								})
							}
						}
					}(this,Map));
				}
			});
		}
	});
})(jQuery);

