/**
 * jQuery gMap - Google Maps API V3
 *
 * @license MIT License; http://www.opensource.org/licenses/mit-license.php
 * @url		http://github.com/marioestrada/jQuery-gMap
 * @author	Mario Estrada <me@mario.ec> based on original plugin by Cedric Kastner <cedric@nur-text.de>
 * @version	2.1.4
 */
(function($)
{
	// Main plugin function
	$.fn.gMap = function(options, methods_options)
	{
		// Optional methods
		switch(options)
		{
		case 'addMarker':
			return $(this).trigger('gMap.addMarker', [methods_options.latitude, methods_options.longitude, methods_options.content, methods_options.icon, methods_options.popup]);
		case 'centerAt':
			return $(this).trigger('gMap.centerAt', [methods_options.latitude, methods_options.longitude, methods_options.zoom]);
		case 'clearMarkers':
			return $(this).trigger('gMap.clearMarkers');
		}

		// Build main options before element iteration
		var opts = $.extend({}, $.fn.gMap.defaults, options);

		// Iterate through each element
		return this.each(function()
		{
			// Create map and set initial options
			var $gmap = new google.maps.Map(this);

			$(this).data('gMap.reference', $gmap);

			// Create new object to geocode addresses
			var $geocoder = new google.maps.Geocoder();

			// Check for address to center on
			if (opts.address)
			{
				// Get coordinates for given address and center the map
				$geocoder.geocode(
					{
						address: opts.address
					}, function(gresult, status)
					{
						if(gresult && gresult.length)
							$gmap.setCenter(gresult[0].geometry.location);
					}
				);
			}else{
				// Check for coordinates to center on
				if (opts.latitude && opts.longitude)
				{
					// Center map to coordinates given by option
					$gmap.setCenter(new google.maps.LatLng(opts.latitude, opts.longitude));
				}
				else
				{
					// Check for a marker to center on (if no coordinates given)
					if ($.isArray(opts.markers) && opts.markers.length > 0)
					{
						// Check if the marker has an address
						if (opts.markers[0].address)
						{
							// Get the coordinates for given marker address and center
							$geocoder.geocode(
								{
									address: opts.markers[0].address
								}, function(gresult, status)
								{
									if(gresult && gresult.length > 0)
										$gmap.setCenter(gresult[0].geometry.location);
								}
							);
						}else{
							// Center the map to coordinates given by marker
							$gmap.setCenter(new google.maps.LatLng(opts.markers[0].latitude, opts.markers[0].longitude));
						}
					}else{
						// Revert back to world view
						$gmap.setCenter(new google.maps.LatLng(34.885931, 9.84375));
					}
				}
			}
			$gmap.setZoom(opts.zoom);

			// Set the preferred map type
			$gmap.setMapTypeId(google.maps.MapTypeId[opts.maptype]);

			// Set scrollwheel option
			var map_options = { scrollwheel: opts.scrollwheel, disableDoubleClickZoom: !opts.doubleclickzoom };
			// Check for map controls
			if(opts.controls === false){
				$.extend(map_options, { disableDefaultUI: true });
			}else if (opts.controls.length != 0){
				$.extend(map_options, opts.controls, { disableDefaultUI: true });
			}

			$gmap.setOptions(map_options);

			// Create new icon
			var gicon = new google.maps.Marker();

			// Set icon properties from global options
			marker_icon = new google.maps.MarkerImage(opts.icon.image);
			marker_icon.size = new google.maps.Size(opts.icon.iconsize[0], opts.icon.iconsize[1]);
			marker_icon.anchor = new google.maps.Point(opts.icon.iconanchor[0], opts.icon.iconanchor[1]);
			gicon.setIcon(marker_icon);

			if(opts.icon.shadow)
			{
				marker_shadow = new google.maps.MarkerImage(opts.icon.shadow);
				marker_shadow.size = new google.maps.Size(opts.icon.shadowsize[0], opts.icon.shadowsize[1]);
				marker_shadow.anchor = new google.maps.Point(opts.icon.shadowanchor[0], opts.icon.shadowanchor[1]);
				gicon.setShadow(marker_shadow);
			}

			// Bind actions
			$(this).bind('gMap.centerAt', function(e, latitude, longitude, zoom)
			{
				if(zoom)
					$gmap.setZoom(zoom);

				$gmap.panTo(new google.maps.LatLng(parseFloat(latitude), parseFloat(longitude)));
			});

			// Clear Markers
			var overlays = [];
			$(this).bind('gMap.clearMarkers', function()
			{
				while(overlays[0]){
					overlays.pop().setMap(null);
				}
			});

			var last_infowindow;
			$(this).bind('gMap.addMarker', function(e, latitude, longitude, content, icon, popup)
			{
				var glatlng = new google.maps.LatLng(parseFloat(latitude), parseFloat(longitude));

				var gmarker = new google.maps.Marker({
					position: glatlng
				});

				if(icon)
				{
					marker_icon = new google.maps.MarkerImage(icon.image);
					marker_icon.size = new google.maps.Size(icon.iconsize[0], icon.iconsize[1]);
					marker_icon.anchor = new google.maps.Point(icon.iconanchor[0], icon.iconanchor[1]);
					gmarker.setIcon(marker_icon);

					if(icon.shadow)
					{
						marker_shadow = new google.maps.MarkerImage(icon.shadow);
						marker_shadow.size = new google.maps.Size(icon.shadowsize[0], icon.shadowsize[1]);
						marker_shadow.anchor = new google.maps.Point(icon.shadowanchor[0], icon.shadowanchor[1]);
						gicon.setShadow(marker_shadow);
					}
				}else{
					gmarker.setIcon(gicon.getIcon());
					gmarker.setShadow(gicon.getShadow());
				}

				if(content)
				{
					if(content == '_latlng')
						content = latitude + ', ' + longitude;

					var infowindow = new google.maps.InfoWindow({
						content: opts.html_prepend + content + opts.html_append
					});

					google.maps.event.addListener(gmarker, 'click', function()
					{
						last_infowindow && last_infowindow.close();
						infowindow.open($gmap, gmarker);
						last_infowindow = infowindow;
					});

					if(popup)
					{
						google.maps.event.addListenerOnce($gmap, 'tilesloaded', function()
						{
							infowindow.open($gmap, gmarker);
						});
					}
				}
				gmarker.setMap($gmap);
				overlays.push(gmarker);
			});

			// Loop through marker array
			for (var j = 0; j < opts.markers.length; j++)
			{
				// Get the options from current marker
				marker = opts.markers[j];

				// Check if address is available
				if (marker.address)
				{
					// Check for reference to the marker's address
					if (marker.html == '_address')
						marker.html = marker.address;

					// Get the point for given address
					var $this = this;
					$geocoder.geocode({
						address: marker.address
					}, (function(marker, $this){
						return function(gresult, status)
						{
							// Create marker
							if(gresult && gresult.length > 0)
							{
								$($this).trigger('gMap.addMarker', [gresult[0].geometry.location.lat(), gresult[0].geometry.location.lng(), marker.html, marker.icon, marker.popup]);
							}
						};
					})(marker, $this)
					);
				}else{
					$(this).trigger('gMap.addMarker', [marker.latitude, marker.longitude, marker.html, marker.icon, marker.popup]);
				}
			}
		});

	}

	// Default settings
	$.fn.gMap.defaults = {
		address: '',
		latitude: 0,
		longitude: 0,
		zoom: 1,
		markers: [],
		controls: [],
		scrollwheel: false,
		doubleclickzoom: true,
		maptype: 'ROADMAP',
		html_prepend: '<div class="gmap_marker">',
		html_append: '</div>',
		icon: {
			image: "http://www.google.com/mapfiles/marker.png",
			shadow: "http://www.google.com/mapfiles/shadow50.png",
			iconsize: [20, 34],
			shadowsize: [37, 34],
			iconanchor: [9, 34],
			shadowanchor: [6, 34]
		}
	}

})(jQuery);