(function($){
	$.fn.mapView = function(options) {

		var j_map;
		var id;
		var map;
		var geocoder;
		var pin = null;
		var markers = [];

		var opts = {};
		$.extend (opts, $.fn.mapView.defaults);
		$.extend (opts, options);
		
/************************************************/
/*	Plugin Methods								*/
/************************************************/	

		arguments.callee.showMarker = function (id, minz, maxz) {
        	showMarker (id, minz, maxz);
    	};
    	
		arguments.callee.showArea = function (id) {
        	showArea (id);
    	};


		function validateParams() 
		{
		    if ( isNaN (parseInt(opts.zoom)) || !(opts.zoom >=0 && opts.zoom <= 20) )
		    {
		    	opts.zoom = 2;
		    }
		    if ( isNaN (parseFloat(opts.latitude)) )
		    {
		    	opts.latitude = 0;
		    }
		    if ( isNaN (parseFloat(opts.longitude)) )
		    {
		    	opts.longitude = 0;
		    }
		};

    	function unloadG ()
    	{
    		GUnload();
    	};

		// convert address to lng/lat
		// parameters : address
		// return latitude x longitude
		function addressToCoordinates (address)
		{
			if ( address == '') return;

			var z = '';
			if (arguments.length > 1) z = parseInt(arguments[1]);
			
			if (geocoder) 
			{
				geocoder.getLatLng( address,  function(point) 
				{
					if (!point) 
					{
						alert("'" + address + "' " + opts.err_notfound);
					} 
					else 
					{
						drawPin (point);
					    centerMap (point, z);
					    showPinCoordinates (point);
					}
				});
			}
			else
			{
				alert (opts.err_geocoder_unavailable);
			}
		};
		
		function drawPin (point)
		{
			if ( opts.useCoordinates || opts.useAddress )
			{
				if (pin) { 
					map.removeOverlay(pin); 
					pin = null; 
				}
				pin = new GMarker(point); 
				map.addOverlay(pin); 
			}
		};
		
		function centerMap (point, z)
		{
		    if ( isNaN (parseInt(z)) || !(z >=0 && z <= 20) )
		    {
				map.setCenter(point);
		    }
		    else
	    	{
				map.setCenter(point, parseInt(z));
	    	}
		};
		
		function showPinCoordinates (point)
		{
			if ( opts.useCoordinates && opts.latitude_id && opts.longitude_id )
			{
				$('#'+opts.longitude_id).val( point.x );
				$('#'+opts.latitude_id).val( point.y ); 
			}
			getZoom();
		};

		function getZoom()
		{
			$('#'+opts.zoom_id).val( map.getZoom() );
		};

		function requestAddress (response)
		{
			if (!response || response.Status.code != 200) 
			{
				alert(opts.err_addr_notfound);
			}
			else
			{
				$('#'+opts.address_id).val(response.Placemark[0].address);
			}
		};

		function coordinatesToAddress (point)
		{
			geocoder.getLocations( point, requestAddress );
		};


		// gestion des areas
		function showArea (p)
		{
			if ( parseInt(p) < opts.areas.length )
			{
				var point = new GLatLng(parseFloat(opts.areas[p].latitude), parseFloat(opts.areas[p].longitude));
				if ( opts.areas[p].zoom )
				{
					centerMap (point, opts.areas[p].zoom);
				}
				else
				{
					centerMap (point);
				}
			}
		};


		// gestion des markers
		function showMarker (p, minz, maxz)
		{
			if ( parseInt(p) < opts.markers.length )
			{
				// 0 = far , 20 = near
				var nz='';
				if (minz!='')
				{
					minz = parseInt(minz);
					if (map.getZoom() > minz) nz = minz;
				}
				if (maxz!='')
				{
					maxz = parseInt(maxz);
					if (map.getZoom() < maxz) nz = maxz;
				}
				if (nz=='') nz = map.getZoom();
				var point = new GLatLng(parseFloat(opts.markers[p].latitude), parseFloat(opts.markers[p].longitude));
				centerMap (point, nz);
				showPinCoordinates (point);
				if ( opts.autoClick )
				{
					if ( opts.autoClickUrl || (opts.markers[p].aurl && !opts.markers[p].url) )
					{
						GEvent.trigger(markers[p],"click"); 
					}
				}
				map.getZoom()
			}
		};

		function showMarkers(bounds)
		{
			if ( !opts.markers || opts.markers.length == 0 ) return;
			
        	var bounds = new GLatLngBounds();
			for (var i=0; i < opts.markers.length; i++ )
			{
				var point = new GLatLng(parseFloat(opts.markers[i].latitude), parseFloat(opts.markers[i].longitude));
				var icon = new GIcon(G_DEFAULT_ICON);
				if ( opts.markers[i].icon )
				{
					icon.image = opts.markers[i].icon;
				}
				if ( opts.markers[i].label )
				{
					var marker = new GMarker(point, {icon: icon, title:opts.markers[i].label});
				}
				else
				{
					var marker = new GMarker(point, {icon: icon});
				}
				var fn = markerClickFn(i, point);
				GEvent.addListener(marker, "click", fn);
				markers.push(marker);
	            bounds.extend(point);
			}
			if ( opts.clusterMarkers == true )
			{
				var gsize = (opts.clusterMarkersGrid == -1) ? null : parseInt (opts.clusterMarkersGrid);
		        markerClusterer = new MarkerClusterer(map, markers, {maxZoom: null, gridSize: gsize, styles: mc_styles[opts.clusterMarkersStyle]});
			}
			else
			{
				for (i = 0; i < markers.length; i++) {
					map.addOverlay(markers[i]);
				}
			}
			if ( opts.autoZoom == true )
			{
				map.setZoom(map.getBoundsZoomLevel(bounds));
				map.setCenter(bounds.getCenter());
			}
		};

		function markerClickFn(i, point) {
			return function() {
				if ( opts.markers[i].aurl )
				{
					
					/*
					var infoHtml = '';
					infoHtml+= '<script type="text/JavaScript">';
					//infoHtml+= '$(document).ready(function(){';
					infoHtml+= '$jQ(function() {';
					infoHtml+= '$("#gmapinfo'+i+'").load("'+opts.markers[i].url+'");';
					infoHtml+= '});';
					infoHtml+= '</script>';
					infoHtml+= "<div id='gmapinfo"+i+"'></div>";
					map.openInfoWindowHtml(point, infoHtml);
					*/
					
					
					var xmlhttp = new XMLHttpRequest();
					if ( xmlhttp )
					{
						xmlhttp.onreadystatechange=function()
						{
							// readyState  	Returns the state of the object:
							// 0 = uninitialized
							// 1 = loading
							// 2 = loaded
							// 3 = interactive
							// 4 = complete
							// 
							// responseText 	Returns the response as a string
							// responseXML 	Returns the response as XML. This property returns an XML document object, which can be examined and parsed using W3C DOM node tree methods and properties
							// status 	Returns the status as a number (e.g. 404 for "Not Found" or 200 for "OK")
							// statusText 	Returns the status as a string (e.g. "Not Found" or "OK")

							try
							{
								if (xmlhttp.readyState == 4)
								{
									if (xmlhttp.status == 200)
									{
										var infoHtml = xmlhttp.responseText;
										if ( infoHtml != '' )
										{
											map.openInfoWindowHtml(point, infoHtml);
										}
									}
									else
									{
										//alert (xmlhttp.statusText);
									}
								}
							}
							catch(e) {}
						};
						var params = "";
						xmlhttp.open("GET", opts.markers[i].aurl, true);
						xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
						xmlhttp.setRequestHeader("Content-length", params.length);
						xmlhttp.setRequestHeader("Connection", "close");
						xmlhttp.send(params);
					}
					
				}
				else if ( opts.markers[i].url )
				{
					if ( opts.markers[i].urlt == 1 )
					{
						window.open(opts.markers[i].url);
					}
					else
					{
						document.location.href = opts.markers[i].url; 
					}
				}
			};
		};
		
		
		
/************************************************/
/*	Main Plugin Code							*/
/************************************************/
		return this.each(function() {
			j_map = $(this);
			id = j_map.attr('id');

			if(GBrowserIsCompatible()) {
				
				if (window.addEventListener) 
				{
					window.addEventListener('unload',unloadG,false);
				}
				else if (document.addEventListener) 
				{
					document.addEventListener('unload',unloadG,false);
				}
				else if (window.attachEvent) 
				{
					window.attachEvent('onunload',unloadG);
				}
				else 
				{	//Older browsers only
					if (typeof window.onunload=='function') 
					{
						var oldonunload=window.onunload;
						window.onunload=function()
						{
							oldonunload();
							unloadG();
						}
					} 
					else 
					{
						window.onunload=unloadG;
					}
				} 
				
				validateParams();
				
				map = new GMap2(document.getElementById(id));
				map.addControl(new GLargeMapControl());
				map.addControl(new GMapTypeControl());
	        	geocoder = new GClientGeocoder();

				switch (opts.terrainType)
				{
					case 'satellite' :
						map.setMapType(G_SATELLITE_MAP);
						break;
					case 'hybrid' :
						map.setMapType(G_HYBRID_MAP);
						break;
					case 'normal' :
					default :
						map.setMapType(G_NORMAL_MAP);
						break;
				}

				if ( opts.useScale )
				{
					map.addControl(new GScaleControl());
				}
				
				if ( opts.useScaleZone )
				{
	                map.addControl(new GOverviewMapControl());
				}

				var point = new GLatLng(opts.latitude, opts.longitude); 
				drawPin (point);
			    centerMap (point, opts.zoom);

				if ( opts.useCoordinates )
				{
					GEvent.addListener(map, 'click', function(overlay, point) { 
						drawPin (point);
						showPinCoordinates (point);
						if ( opts.autoCenter )
						{
							centerMap (point);
						}
						if ( opts.autoAddress && opts.address_id )
						{
							coordinatesToAddress (point);
						}
					});

					if (opts.find == 'address' && opts.address_id && opts.latitude != 0 && opts.longitude != 0) {
						var point = new GLatLng(opts.latitude, opts.longitude); 
						coordinatesToAddress (point);
						centerMap (point, opts.zoom);
					}

				}
				GEvent.addListener(map, 'zoomend', function(o, n) { 
					$('#'+opts.zoom_id).val( n );
				});
				


				// ajouter le handle au bouton "trouver coordonnées"
				if ( opts.address_btn && opts.address_id )
				{
					$('#'+opts.address_btn).bind('click', function (e) {
						addressToCoordinates ($('#'+opts.address_id).val());
					});
					
					if (opts.find == 'coordinates' && opts.useCoordinates && (opts.latitude == 0 || opts.longitude == 0) ) {
						addressToCoordinates ($('#'+opts.address_id).val());
					}
				}

				// ajouter le handle au bouton "trouver adresse"
				if ( opts.coordinates_btn && opts.latitude_id && opts.longitude_id && opts.address_id)
				{
					$('#'+opts.coordinates_btn).bind('click', function (e) {
						var point = new GLatLng(parseFloat($('#'+opts.latitude_id).val()), parseFloat($('#'+opts.longitude_id).val()));
						coordinatesToAddress (point);
					});
				}
				
				showMarkers();			
			}
		});
		return this;
	};

	$.fn.mapView.defaults = {
		width: 700,
		height: 500,
		zoom_id: 'zoom',
		zoom: 2,					// 0 - 20
		autoZoom: false,
		clusterMarkers: false,
		clusterMarkersGrid: -1,
		clusterMarkersStyle: 0,
		find: 'coordinates',		// 'coordinates' | 'address'
		latitude_id: 'latitude',
		longitude_id: 'longitude',
		latitude: 0,
		longitude: 0,
		coordinates_btn: '',
		address_id: 'fulladdress',
		address_btn: '',
		useCoordinates: true,
		useAddress: true,
		useScale: true,
		useScaleZone: false,
		autoAddress:false,
		autoCenter:false,
		autoClick:false,			// sur choix de la list, simuler le click
		autoClickUrl:false,			// sur choix de la list, simuler le click si le target est un url
		terrainType: 'hybrid',		// 'normal'|'hybrid'|'satellite'
		markers : new Array(),
		areas : new Array(),
		err_notfound: "not found",
		err_addr_notfound: "Cannot find an address at this location",
		err_geocoder_unavailable: "Geocoder is unavailable"
	};
	
})(jQuery);