(function($) {
	jQuery.fn.sort = function() {
		return this.pushStack( jQuery.makeArray( [].sort.apply( this, arguments ) ) );
	};
	geoloc = $.fn.geoloc = function(options) {
		// build main options before element iteration
		var opts = $.extend({}, $.fn.geoloc.defaults, options);
		
		var cssLabelOff = {
			"text-decoration":"none",
			"cursor":"default"
		};
		var cssLabelOn = {
			"text-decoration":"underline",
			"cursor":"pointer"
		};
		
		var getXHR = null;
		
		function levelInit(level) {
			if(typeof level != "string") return false;
			$(eval("opts."+level+"Label"))
				.css(cssLabelOff)
				.unbind("click");
			$(eval("opts."+level+"InputId"))
				.show();
			$(eval("opts."+level+"Text"))
				.hide()
				.text("");
		};
		
		function levelClear(level){
			if( eval("opts."+level+"DivId") ) {
				levelInit(level);
				$(eval("opts."+level+"DivId")).hide();
				$(eval("opts."+level+"InputId")).val("");
				$(eval("opts."+level+"InputId")).html("");
			}
		};
		
		function levelDisp(level){
			var levelText = eval("opts."+level+"InputId");
			if(level == "zipcode"){
				levelText = $(levelText).val();
			}
			else{
				levelText = $(levelText+" option:selected").text();
			}
			
			if(level !== "city" || arguments[1] == undefined){
				$(eval("opts."+level+"Label"))
					.css(cssLabelOn)
					.click(function(){
						levelChoice(level);
					});
			};
			$(eval("opts."+level+"InputId")).hide();
			
			if (levelText != undefined){
				$(eval("opts."+level+"Text"))
					.text(levelText)
					.show();
			}
			
			if(level == "city") {
				$(eval("opts."+level+"InputId")).blur();
			}
		};
		
		function levelChoice(level){
			//if request pending return false
			if(getXHR != null) return false;
			levelInit(level);
			// level is define ( different of null )
			if( eval("opts."+level+"DivId") ) {
				$(eval("opts."+level+"DivId")).show();
				//clear
				switch(level){
					case "country" :
						levelClear("area");
						levelClear("zipcode");
						levelClear("city");
						break;
					case "zipcode" :
						$(opts.zipcodeInputId).val("");
						levelClear("area");
						levelClear("city");
						$(opts.zipcodeInputId).addClass('required');
						break;
					case "area" :
						levelClear("zipcode");
						levelClear("city");
						$(opts.zipcodeInputId).removeClass('required');
						break;
				}
				$(eval("opts."+level+"InputId")).focus();
			}
		};
		
		function fetchCountries() {
			var sURL = encodeURI( opts.serverURL + '/ajax/signupgetcountry');
			
			var handleSuccess = function(o){
				getXHR = null;
				$(opts.loadingDivId).hide();
				if(o !== undefined){
					var obj = eval(o);
					$(opts.countryInputId).html(""); //clear country options
					// Value par default
					if( opts.countryDefaultMessage != "" ) {
						var newOption = "<option value=\"\">" + opts.countryDefaultMessage + "</option>";
						$(opts.countryInputId).append(newOption);
					}
					var response = $(obj).find("geo");
					if(response != undefined) {
						
						// top countries
						var tRank = $(obj).find('countryRank').not($(obj).find('countryRank:contains(0)'));
						tRank.sort(function(a, b) {
							
							if (parseInt($(a).text()) < parseInt($(b).text())) return -1;
							
							if (parseInt($(a).text()) > parseInt($(b).text())) return 1;
							
							return 0;
							
						});
						
						$.each(tRank, function(index, rank) {
							var _this = $(obj).find('countryRank:contains("'+$(rank).text()+'")').parent();
							var currentCountryId = $(_this).find('countryId').text();
							var currentCountryLabel = $(_this).find('countryLabel').text();	
							var	newOption = "";
							// gestion du pays selectionne par defaut
							if( opts.defaultSelectedCountryId != 0 && opts.defaultSelectedCountryId == currentCountryId) {
								newOption = "<option value=\""+currentCountryId+"\" selected=\"selected\">"+currentCountryLabel+"</option>";
							} else {
								newOption = "<option value=\""+currentCountryId+"\">"+currentCountryLabel+"</option>";
							}
							$(opts.countryInputId).append(newOption);
						
						});
					}
					
					// separation 
					var newOption = "<option value=\"\">------------</option>";
					$(opts.countryInputId).append(newOption);
					// others countries
					var response = $(obj).find('geo');
					if(response != undefined) {
						$(response).each( function(){
							if( $(this).find('countryRank').text() == 0 ) {
								var currentCountryId = $(this).find('countryId').text();
								var currentCountryLabel = $(this).find('countryLabel').text();
								var newOption = "";
								// gestion du pays selectionne par defaut
								if( opts.defaultSelectedCountryId != 0 && opts.defaultSelectedCountryId == currentCountryId) {
									newOption = "<option value=\""+currentCountryId+"\" selected=\"selected\">"+currentCountryLabel+"</option>";
								} else {
									newOption = "<option value=\""+currentCountryId+"\">"+currentCountryLabel+"</option>";
								}
								$(opts.countryInputId).append(newOption);
							}
						});
						
					}
					levelChoice("country");
					
					// special pays preselect et region preselectionne : on valide le pays
					if( opts.defaultSelectedCountryId != 0) {
						countryWasChosen();
					}
					
				}
			}
			
			var handleFailure = function(){
				getXHR = null;
				$(opts.loadingDivId).hide();
			}
			
			// AJAX request
			getXHR = $.ajax({
				url: sURL,
				dataType: "xml",
				success: handleSuccess,
				error: handleFailure
			});
			
			$(opts.loadingDivId).show();
			return getXHR;
		}
		
		function fetchAreas(){
			var countryID = $(opts.countryInputId).val();
			var sURL = encodeURI( opts.serverURL + '/ajax/signupareasfromcountry/id_country/' + countryID );
			
			var handleSuccess = function(o){
				getXHR = null;
				$(opts.loadingDivId).hide();
				if(o !== undefined){
					var obj = eval(o);
					var response = $(obj).find('geo');
					if(response != undefined){
						$(opts.areaInputId).html(""); //clear area options
						var newOption = "<option value=\"-1\">" +$('#trad_selectionneuneregion').text()+"</option>";
						$(opts.areaInputId).append(newOption);
						if( opts.selectAllAreaMessage != null ) {
							var htmlSelected = '';
							if( opts.defaultSelectedAreaId != 0 && opts.defaultSelectedAreaId == -2) {
								htmlSelected = 'selected="selected"';
							}
							
							var newOption = "<option value=\"-2\" " + htmlSelected + ">" +opts.selectAllAreaMessage+"</option>";
							$(opts.areaInputId).append(newOption);
						}
						$(response).each( function(){
							var currentAreaId = $(this).find('areaId').text();
							var currentAreaLabel = $(this).find('areaLabel').text();
							var newOption = "";
							
							if( opts.defaultSelectedAreaId != 0 && opts.defaultSelectedAreaId == currentAreaId) {
								newOption = "<option value=\""+currentAreaId+"\" selected=\"selected\">"+currentAreaLabel+"</option>";
							} else {
								newOption = "<option value=\""+currentAreaId+"\">"+currentAreaLabel+"</option>";
							}
						
							$(opts.areaInputId).append(newOption);
						});
						levelChoice("area");
						levelDisp("country");
					}
					else{
						levelChoice("country");
					}
				}
			};
			
			var handleFailure = function(){
				getXHR = null;
				$(opts.loadingDivId).hide();
			};
			
			// AJAX request
			getXHR = $.ajax({
				url: sURL,
				dataType: "xml",
				success: handleSuccess,
				error: handleFailure
			});
			
			$(opts.loadingDivId).show();
			return getXHR;
		};
		
		function countryWasChosen(){
			//if request pending return false
			if(getXHR != null) return false;
			var countryID = $(opts.countryInputId).val();
			var sURL = encodeURI( opts.serverURL + '/ajax/signupusezipcode/id_country/' + countryID );
			
			//if invalid choice return false
			if(countryID == "" || countryID == -1) return false;
			
			var handleSuccess = function(o){
				getXHR = null;
				$(opts.loadingDivId).hide();
				if(o !== undefined){
					if($(o).find('response').text() == 1){
						levelChoice("zipcode");
						levelDisp("country");
					}
					else{
						fetchAreas();
					}
				}
			};
			
			var handleFailure = function(){
				//alert("AJAX error");
				getXHR = null;
				$(opts.loadingDivId).hide();
			};
			
			// si pas de verif sur l utilisation du zipcode 
			if( opts.useZipcodeVerification == false ) {
				fetchAreas();
			} else {
				// AJAX request
				getXHR = $.ajax({
					url: sURL,
					dataType: "xml",
					success: handleSuccess,
					error: handleFailure
				});
				
				$(opts.loadingDivId).show();
				return getXHR;
			}
		};
		
		function areaWasChosen(){
			//if request pending return false
			if(getXHR != null) return false;
			var areaID = $(opts.areaInputId).val();
			var sURL = encodeURI( opts.serverURL + '/ajax/signupcitiesfromarea/id_area/' + areaID );
			
			//if invalid choice return false
			if(areaID == "" || areaID == -1) return false;
			
			var handleSuccess = function(o){
				getXHR = null;
				$(opts.loadingDivId).hide();
				if(o !== undefined){
					var obj = eval(o);
					levelDisp("area");
					var response = $(obj).find('geo');
					if(response !== undefined){
						$(opts.cityInputId).html(""); //clear city options
						if(response == null) {
							//alert("code postal non valide");
						}
						else {
							$(response).each( function(){
								var newOption = "<option value=\""+$(this).find('cityId').text()+"\">"+$(this).find('cityLabel').text()+"</option>";
								$(opts.cityInputId).append(newOption);
							});
							levelChoice("city");
						}
					}
					else{
						levelChoice("area");
					}
				}
			};
			
			var handleFailure = function(){
				//alert("AJAX error");
				getXHR = null;
				$(opts.loadingDivId).hide();
				levelChoice("area");
			};
			
			// AJAX request
			getXHR = $.ajax({
				url: sURL,
				dataType: "xml",
				success: handleSuccess,
				error: handleFailure
			});
			
			$(opts.loadingDivId).show();
			return getXHR;
		};
		
		geoloc.publicZipcodeWasEntered = function(){
			zipcodeWasEntered();
		};
		
		function zipcodeWasEntered(){
			//if request pending return false
			if(getXHR != null) return false;

			var zipcodeID = $(opts.zipcodeInputId).val();
			var countryID = $(opts.countryInputId).val();
			var sURL = encodeURI( opts.serverURL + '/ajax/signupcitiesfromzipcode/id_zipcode/' + zipcodeID + '/id_country/' + countryID );
			
			//if invalid choice return false
			if(zipcodeID == "" || countryID== "") return false;
			
			var handleSuccess = function(o){
				getXHR = null;
				$(opts.loadingDivId).hide();
				if(o !== undefined){
					var obj = o;
					levelDisp("zipcode");
					var response = $(obj).find('geo');
					//if(response !== undefined){
						$(opts.cityInputId).html(""); //clear city options
						if( $(response).length == 0 ) {
							$('#error_your_zipcode_fb').show();
							//alert(opts.noCityFoundErrorMessage);
							levelChoice("zipcode");
						}
						else {

							$('#error_your_zipcode_fb').hide();
							
							if( $(response).length == 1 ) {
								var newOption = "<option value=\""+$(response).find('cityId').text()+"\">"+$(response).find('cityLabel').text()+"</option>";
								$(opts.cityInputId).append(newOption);
								var newOption = "<option value=\""+$(response).find('areaId').text()+"\" />";
								$(opts.areaInputId).html("");
								$(opts.areaInputId).append(newOption);
								$("#deptInputId").val($(response).find('deptId').text());
								levelChoice("city");
								cityWasChosen();
							}
							else {
								
								var newOption = "<option value=\"\">" +$('#trad_selectionneuneville').text()+"</option>";
								$(opts.cityInputId).append(newOption);
								
								$(response).each( function(){
									var newOption = "<option value=\""+$(this).find('cityId').text()+"\">"+$(this).find('cityLabel').text()+"</option>";
									$(opts.cityInputId).append(newOption);
									var newOption = "<option value=\""+$(this).find('areaId').text()+"\" />";
									$(opts.areaInputId).html("");
									$(opts.areaInputId).append(newOption);
									$("#deptInputId").val($(this).find('deptId').text());
								});
								
								levelChoice("city");
								
							}
						}
							/*}
					else{
						_this.levelChoice("zipcode");
					}*/
				}
			}
			
			var handleFailure = function(){
				//alert("AJAX error");
				getXHR = null;
				$(opts.loadingDivId).hide();
				alert(opts.noCityFoundErrorMessage);
				levelChoice("zipcode");
			};
			
			// AJAX request
			getXHR = $.ajax({
				url: sURL,
				dataType: "xml",
				success: handleSuccess,
				error: handleFailure
			});
			
			$(opts.loadingDivId).show();
			return getXHR;
		};
		
		function cityWasChosen(){
			
			var cityID = $(opts.cityInputId).val();
			
		//if invalid choice return false
			if(cityID == "" || cityID == -1) return false;
			
			if(arguments[0] != undefined){
				levelDisp("city", arguments[0]);
			}
			else {
				levelDisp("city");
			}
		};
		
		// iterate each matched element
		return this.each(function() {

			$this = $(this);
			
			//init display
			$(opts.countryText).hide();
			$(opts.areaDivId).hide();
			$(opts.areaText).hide();
			
			if( opts.zipcodeInputId ) {
				$(opts.zipcodeText).hide();
			};
			
			if( opts.cityInputId ) {
				$(opts.cityDivId).hide();
				$(opts.cityText).hide();
			};
			
			if( !opts.askCountryOnLoad  ) {
				levelDisp("country");
				if( opts.zipcodeInputId ) {
					$(opts.zipcodeText).hide();
					$(opts.zipcodeDivId).hide();
				};
				if( opts.cityInputId ) {
					$(opts.cityDivId).show();
					$(opts.cityInputId).hide();
					$(opts.cityText).show();
				};
			}else {
				levelDisp("country");
			};
			
			//init events
			$(opts.countryInputId).change( function(){
					$('#error_sel_country').hide();
					countryWasChosen();
				})/*.blur( function(){
					$('#error_sel_country').hide();
					countryWasChosen();
				})*/;
			
			if( opts.cityInputId ) {
				$(opts.areaInputId).change( function(){
						areaWasChosen();
					});
			};
			
			if( opts.zipcodeInputId ) {
				$(opts.zipcodeInputId).blur( function(){
						zipcodeWasEntered();
					});
			};
			
			if( opts.cityInputId ) {
				$(opts.cityInputId).change( function(){
						cityWasChosen();
					});
			};
			
			if( opts.getCountryOnLoad ) {
				fetchCountries();
			}
			
		});
	
	};
	//
	// plugin defaults
	//
	$.fn.geoloc.defaults = {
		serverURL					: '',
		getCountryOnLoad 			: false,
		askCountryOnLoad 			: true,
		countryDivId				: null,
		countryInputId				: null,
		countryLabel				: null,
		countryText					: null,
		areaDivId					: null,
		areaInputId					: null,
		areaLabel					: null,
		areaText					: null,
		zipcodeDivId				: null,
		zipcodeInputId				: null,
		zipcodeLabel				: null,
		zipcodeText					: null,
		cityDivId					: null,
		cityInputId					: null,
		cityLabel					: null,
		cityText					: null,
		loadingDivId				: null,
		countryDefaultMessage		: "",
		noCityFoundErrorMessage		: "",
		defaultSelectedCountryId	: 0,
		defaultSelectedAreaId		: 0,
		selectAllAreaMessage		: null
	};

})(jQuery);