(function($)
{
	// Timer used in address search
	var smartTimer = 0;
	// Timer used in address search
	var searchMarker = null;
	// Map types
	var mapTypes =
	{
		'hybrid':G_HYBRID_MAP,
		'sat':G_SATELLITE_MAP,
		'map':G_NORMAL_MAP
	};
	/* function searchAddress(jmap, address, settings)
	 * This function is an internal plugin method that returns a marker
	 */
	function searchAddress(ret, address, jmap, settings)
	{
		var GGeocoder = new GClientGeocoder();
		GGeocoder.getLatLng(address, function(point)
		{
			if (!point)
			{
				//throw("Gmap: Adres bulunamadı: "+address);
				return false;
			}
			else if(ret)
			{
				return new GMarker(point);
			}
			else
			{
				jmap.setCenter(point,settings.zoom);
				if(searchMarker) jmap.removeOverlay(searchMarker);
				searchMarker = new GMarker(point, {draggable: true});
				jmap.addOverlay(searchMarker);
				var pointlocation = searchMarker.getPoint();
				$("#"+settings.map_lat).val(pointlocation.lat());
				$("#"+settings.map_lng).val(pointlocation.lng());
				GEvent.addListener(searchMarker, "dragend", function(latlng)
				{
					$("#"+settings.map_lat).val(latlng.lat());
					$("#"+settings.map_lng).val(latlng.lng());
					jmap.panTo(latlng);
				});
				return searchMarker;
			}
		});
	}

	/* directions: function(map,query, panel)
	 * Takes a Direction query and returns directions for map.  Optional panel for text information
	 */
	function searchDirections(jmap,query,panel)
	{
		var directions = new GDirections(jmap, $("#"+panel).get(0));
		directions.load(query);
	}

	function displayHtml(jmap,marker,html,messageo,mlistener)
	{
		var markerOffset = jmap.fromLatLngToDivPixel(marker.getLatLng());
		messageo
			.html(html)
			.css({ top:markerOffset.y, left:markerOffset.x })
			.fadeIn("fast");
		if(mlistener) GEvent.removeListener(mlistener);
	}

	function displayPoint(jmap,marker,html,messageo,tindex,zoom,list)
	{
		var ti = $("#gmap_list_title_"+tindex);
		if(ti.hasClass("active") && messageo.is(":visible"))
		{
			messageo.fadeOut("fast");
			return;
		}

		messageo.hide();
		zoom = zoom || false;
		if(zoom) jmap.setZoom(parseInt(zoom));
		$(".active",list).removeClass("active");
		ti.addClass("active");

		var moveEnd = GEvent.addListener(jmap, "moveend", function()
		{
			displayHtml(jmap,marker,html,messageo,moveEnd);
		});
		jmap.panTo(marker.getLatLng());

		if (messageo.is(":hidden"))
		{
			displayHtml(jmap,marker,html,messageo,moveEnd);
		}
	}

	$.fn.extend({
	/* jmap: function(settings)
	 * The constructor method
	 * Example: $().jmap();
	 */
	jmap: function(sett)
	{
		var version = "1.35";
		/* Default Settings */
		var settings = $.extend({
			maptype: "hybrid", // map || sat || hybrid
			center: [41.012379, 28.975926],
			setcenter: true,
			zoom: 13,
			delay: 750,
			controlsize: "small",
			showtype: true,
			showoverview: true,
			dragging: true,
			scrollzoom: true,
			smoothzoom: true,
			zoomfield: false, // element ID
			zoomfonk: false, // function
			searchfield: "gmap_adres", // element ID || function
			searchbutton: false, // element ID
			directionsto: "gmap_to", // element ID
			directionsfrom: "gmap_from", // element ID
			directionsfind: "gmap_yonbul", // element ID
			directionspanel: "gmap_yonler", // element ID
			map_lat: "gmap_lat", // element ID
			map_lng: "gmap_lng" // element ID
		}, sett || {});

		settings.loadmap = mapTypes[settings.maptype] || G_HYBRID_MAP;

		return this.each(function()
		{
			var jmap = this.jMap = new GMap2(this);
			$(this).data("settings", settings);
			if(settings.setcenter)
			{
				jmap.setCenter(new GLatLng(parseFloat(settings.center[0]),parseFloat(settings.center[1])),parseInt(settings.zoom),settings.loadmap);
			}
			if(settings.zoomfield)
			{
				var zmf=$("#"+settings.zoomfield);
				if(zmf.val()=="") zmf.val(settings.zoom);
				GEvent.addListener(jmap, "zoomend", function(oldzoom, newzoom)
				{
					if(typeof(settings.zoomfonk)=='function' && !settings.zoomfonk()) return;
					zmf.val(newzoom);
				});
			}
			switch(settings.controlsize)
			{
				case "small":
					jmap.addControl(new GSmallMapControl());
					break;
				case "large":
					jmap.addControl(new GLargeMapControl());
					break;
				case "none":
					break;
				default:
					jmap.addControl(new GSmallMapControl());
			}
			if (settings.showtype == true)
			{
				jmap.addControl(new GMapTypeControl());
			}
			if (settings.showoverview == true)
			{
				jmap.addControl(new GOverviewMapControl());
			}
			if (settings.scrollzoom == true)
			{
				/* Off by default */
				jmap.enableScrollWheelZoom();
			}
			if (settings.smoothzoom == true)
			{
				/* Off by default*/
				jmap.enableContinuousZoom();
			}
			if (settings.dragging == false)
			{
				/* On by default */
				jmap.disableDragging();
			}
			/* Seach for the lat & lng of our address*/
			if(settings.searchbutton)
			{
				$("#"+settings.searchbutton).bind('click', function()
				{
					var searchadr=typeof(settings.searchfield)=='function'?settings.searchfield:$("#"+settings.searchfield).val();
					searchAddress(false, searchadr, jmap, settings);
				});
			}
			/* Search for Directions */
			if(settings.directionsfind)
			{
				$("#"+settings.directionsfind).bind("click", function()
				{
					var from = $("#"+settings.directionsfrom).val();
					var to = $("#"+settings.directionsto).val();
					searchDirections(jmap, "from: " + from + " to: " + to, settings.directionspanel);
					$("#"+settings.directionsfrom).val(to);
					$("#"+settings.directionsto).val('');
					return false;
				});
			}
			/* On document unload, clean unload Google API*/
			$(document).unload(function(){ GUnload(); });
		});
	},
	/* getMap: function()
	 * Returns a map object from the API, so it's available to the user
	 * Example: $().getMap().setCenter(...) for Google;
	 */
	getMap: function()
	{
		return this[0].jMap;
	},
	/* function searchAddress(address_fields)
	 * This function that returns a marker
	 */
	searchAddress: function(fields)
	{
		if(!fields) return;
		if(smartTimer) clearTimeout(smartTimer);
		var self = $(this);
		var jmap = this[0].jMap;
		var settings = self.data("settings");
		if(settings.zoomfield)
		{
			settings.zoom=parseInt($("#"+settings.zoomfield).val()) || settings.zoom;
		}
		smartTimer = setTimeout(function()
		{
			var addressx = self.data("addressx");
			var address = "";
			if(typeof(fields) == 'object')
			{
				$.each(fields, function(i)
				{
					var el=$("#"+i+":visible");
					if(el.length)
					{
						address += " "+(this=="val"?el.val():el.children("option:selected").text());
					}
				});
			}
			else
			{
				address = fields;
			}
			address = $.trim(address.replace(/\s\s+/," "));
			if (address != "" && address.length >= 5 && address != addressx)
			{
				self.data("addressx", address);
				searchAddress(false, address, jmap, settings);
			}
		}, settings.delay);
	},
	/* addPoints: function()
	 * Overlays markers on the Google map with a list
	 * Example: $().addPoints(...);
	 * (array({lat:float, lng:float, zoom:int, title:txt, html:txt, css:obj, draggable:bool, removable:bool},...))
	 */
	addPoints: function(points, message, list)
	{
		var jmap = this[0].jMap;

		if(!points.length) return jmap;

		list = list || false;
		if(list) var listo = $('#' + list);
		message = message || false;
		if(message)
		{
			var messageo = $('#' + message);
			messageo.appendTo(jmap.getPane(G_MAP_FLOAT_SHADOW_PANE));
		}

		var defzoom=$(this).data("settings").zoom;
		var firstp={};

		$.each(points, function(i)
		{
			var point = $.extend({
				zoom: defzoom,
				title:"Adres " + i,
				html:"Adres " + i,
				css:{},
				draggable:false,
				removable:false
			},this);

			var mlatlng=new GLatLng(parseFloat(point.lat), parseFloat(point.lng));
			var marker = new GMarker(mlatlng, { draggable: point.draggable });
			if(i==0)
			{
				firstp.marker=marker;
				firstp.latlng=mlatlng;
				firstp.html=point.html;
			}
			jmap.addOverlay(marker);

			GEvent.addListener(marker, "click", function()
			{
				if(message)
				{
					displayPoint(jmap, marker, point.html, messageo, i);
				}
				else
				{
					jmap.panTo(marker.getLatLng());
					marker.openInfoWindowHtml(point.html);
				}
			});

			if (point.removable)
			{
				GEvent.addListener(marker, "dblclick", function()
				{
					return jmap.removeOverlay(marker);
				});
			}

			if (list)
			{
				$("<li />")
					.attr("id","gmap_list_title_"+i)
					.css(point.css)
					.html(point.title)
					.click(function()
					{
						displayPoint(jmap, marker, point.html, messageo, i, point.zoom, listo);
					})
					.appendTo(listo);
			}
		});
		if(list)
		{
			$("#gmap_list_title_0").addClass("active")
		}
		jmap.setCenter(firstp.latlng, parseInt(points[0].zoom));
		displayHtml(jmap,firstp.marker,firstp.html,messageo,false)

		return jmap;
	},
	/* addInitialPoint: function()
	 * Overlays a marker on the Google map
	 * Example: $().addInitialPoint(...);
	 * ({lat:float, lng:float, zoom:int, draggable:bool})
	 */
	addInitialPoint: function(point)
	{
		var jmap = this[0].jMap;
		var settings = $(this).data("settings");

		point = point || false;
		if(point)
		{
			point = 
			{
				lat: parseFloat(point.lat),
				lng: parseFloat(point.lng),
				zoom: parseInt((point.zoom || settings.zoom)),
				draggable: point.draggable || false,
				maptype: point.maptype || "hybrid"
			}
		}
		else
		{
			point =
			{
				lat: parseFloat(settings.center[0]),
				lng: parseFloat(settings.center[1]),
				zoom: parseInt(settings.zoom),
				draggable: true,
				maptype: "hybrid"
			}
		}
		
		var mlatlng = new GLatLng(point.lat, point.lng);
		var marker = new GMarker(mlatlng, { draggable: point.draggable });
		
		if(point.draggable)
		{
			if(searchMarker) jmap.removeOverlay(searchMarker);
			searchMarker = marker;
			jmap.addOverlay(searchMarker);
			$("#"+settings.map_lat).val(point.lat);
			$("#"+settings.map_lng).val(point.lng);
			GEvent.addListener(searchMarker, "dragend", function(latlng)
			{
				$("#"+settings.map_lat).val(latlng.lat());
				$("#"+settings.map_lng).val(latlng.lng());
				jmap.panTo(latlng);
			});
		}
		var loadmap = mapTypes[point.maptype] || G_HYBRID_MAP;
		jmap.setCenter(mlatlng, point.zoom, loadmap);

		return jmap;
	},
	/* addPoly: function(poly)
	 * Takes an array of GLatLng points, converts it to a vector Polyline to display on the map
	 * Example: $().addPoly(...);
	 */
	addPoly: function (poly)
	{
		var jmap = this[0].jMap;
		return jmap.addOverlay(poly);
	},
	/* addRss: function()
	 * Takes a KML file and renders it to the map.
	 * Example: $().addRss(...);
	 */
	addRss: function (rssfile)
	{
		var jmap = this[0].jMap;
		var geoXml = new GGeoXml(rssfile);
		return jmap.addOverlay(geoXml);
	}
	});
})(jQuery);