;(function($) {
	$.fn.searchwidget = function(options){
		options = jQuery.extend({},options);
		this.each(
			function(){
				new $.SearchWidget(this, options);
			}
		);
		return this;
	};
	$.SearchWidget = function(input, options){
		var $input = $(input);
		widgetHelper.setInput($input); 
		$input.bind("change",function(){
			blockSubmit();
			setTimeout(function(){$('#'+input.id).trigger('checkflag');}, 10);
		})
		.bind("checkflag",function() {
			if(jQuery.trim($input.val()) == ''){
				setGeoreferenceValues({});
				return true;
			}
			if (widgetHelper.getFlag()
					&& widgetHelper.getTimer() < 10)
				setTimeout(function(){$('#'+input.id).trigger('checkflag');},200);
			else {
				$(this).trigger('checkvalue');
				return true;
			}
		})
		.bind("checkvalue",function() {
			if (lastAreaSelected){
				if (!areaChange(this) && lastAreaSelected.id != undefined && lastAreaSelected.id != '') {
					setGeoreferenceValues({
						area_id: lastAreaSelected.id,
						address: $(this).val(),
						path: lastAreaSelected.path,
						latitude_0: lastAreaSelected.latitude,
						longitude_0: lastAreaSelected.longitude,
						radius: lastAreaSelected.radius,
						region_bounds: lastAreaSelected.bounds,
						geo_reference: widgetHelper.getGeoTypes().AREA
					});
				}
			}
			$(this).trigger('checkarea');
		})
		.bind("checkarea",function(){
			toChange = false;
			if(!areas.length){
				toChange = true;
			}
			if ($('#area_id').val() == ''
				&& $(this).val() != '' || !lastAreaSelected) {
				toChange = true;
			}
			if (toChange) {
				if($('.ac_results').is(':visible')){
					return;
				}
				if (areas[0]){
					if(areas[0].value.substring(0,3).toLowerCase() == $(this).val().substring(0,3).toLowerCase()){
						setGeoreferenceValues({
							area_id: areas[0].id,
							address: areas[0].value,
							path: areas[0].path,
							latitude_0: areas[0].latitude,
							longitude_0: areas[0].longitude,
							radius: areas[0].radius,
							region_bounds: areas[0].bounds,
							geo_reference: widgetHelper.getGeoTypes().AREA
						});
						lastAreaSelected = areas[0];
					} else {
						areas = new Array();
					}
					enableSubmit();
				}
				if(!areas[0]){
					$(this).getLocations({resultCallback: geocoderResult});
				}
			} else {
				enableSubmit();
			}
		})
		.bind(($.browser.opera ? "keypress" : "keydown"), function(event) {
			var noSearch = new Array(9,13);
			if(!$.inArray(event.keyCode,noSearch)){
				widgetHelper.setFlag(true);
			}
			switch(event.keyCode) {
				case 13: //Enter or Return
					if(areaChange(this) || $("#geo_reference_type").val() == ''){
						$(this).trigger('checkflag');
					}
					$(":input:eq(" + $(":input").index(this) + 1 + ")").focus();
				break;
			}
		})
		.setOptions({
			autoFill: false,
			parse: filterParseAutocomplete			
		});
        $(".whereImGoing").live("click",function(){
        	var $this = $(this);
        	map.closeInfoWindow();
            setGeoreferenceValues({
                address: $this.attr('address'),
                latitude_0: $this.attr('latitude'),
                longitude_0: $this.attr('longitude'),
                path: $this.attr('path'),
                area_id: $this.attr('id'),
                radius: $this.attr('radius'),
                geo_reference: $this.attr('type'),
                region_bounds: $this.attr('bounds')
            });
        });
        
        function areaChange(element){
			if (($(element).val() != lastAreaSelected.value) || ($(element).val() != '' && !lastAreaSelected)) {
				setGeoreferenceValues({
					address: $(element).val()
				});
				return true;
			}
			return false;
        };
	};
})(jQuery);

var WidgetHelper = ( function() {
	var instance = null;
	var counter = 0;
	var flag = true;
	var matches = new Array();
	var input = null;
	var speeds = {};
	var slider = {};
	var georeferencesTypes = {};
	
	function PrivateConstructor() {
		this.getTimer = function() {
			return counter++;
		};
		this.getFlag = function() {
			return flag;
		};
		this.setHiddenValue = function(selector,value){
			$(selector).val(value);
			$(selector).trigger('change');
		}
		this.setFlag = function(pflag) {
			if(pflag){
				counter = 0
			}
			flag = pflag;
		};
		this.setMatches = function(pMatches) {
			matches = pMatches;
		};
		this.selectMatched = function(id) {
			for ( var i in matches) {
				if(matches[i].id == id){
					setGeoreferenceValues({
						address: matches[i].address,
						latitude_0: matches[i].Point.coordinates[1],
						longitude_0: matches[i].Point.coordinates[0],
						geo_reference: widgetHelper.getGeoTypes().GEO_CODED_STRING
					});
					break;
				}
			}
		};
		this.getHtmlMatches = function() {
			for ( var i in matches) {
				h = '<li><a href="#" id="'+matches[i].id+'" class="itemMatched">'+matches[i].address+'</a></li>'; 
				$("#listMatches").append(h);
			}
			return matches;
		};
		this.setSpeeds = function(pSpeeds) {
			this.speeds = $.extend(this.speeds,pSpeeds);				
		};
		this.getSpeeds = function(){
			return this.speeds;
		};
		this.setSlider = function(pSlider) {
			this.slider = $.extend(this.slider,pSlider);				
		};
		this.getSlider = function(){
			return this.slider;
		};
		this.setInput = function(pInput){
			input = pInput;
		};
		this.getInput = function(){
			return input;
		};
		this.setGeoTypes = function(pTypes) {
			this.georeferencesTypes = $.extend(this.georeferencesTypes,pTypes);				
		};
		this.getGeoTypes = function(){
			return this.georeferencesTypes;
		};
	}

	return new function() {
		this.getInstance = function() {
			if (instance == null) {
				instance = new PrivateConstructor();
				instance.constructor = null;
			}
			return instance;
		}
	};
})();

var widgetHelper = WidgetHelper.getInstance();
var lastAreaSelected = null;
var areas = new Array();

/**
* Callback result for select event in autocomplete area search field.
* @param e
* @param item
* @return
*/
function areaSelectedCallback(e, item) {
	if (item && item.id) {
		$("#area_id").val(item.id);
		lastAreaSelected = item;
	} else {
		if(window.console)
			console.log('Area not found!');
	}
	widgetHelper.setFlag(false);
};
function blockSubmit(){
	$('input[type="submit"]').attr('disabled', 'disabled');
};
function enableSubmit(){
	$('input[type="submit"]').removeAttr('disabled');
};
/**
 * 
 * @param data
 * @return
 */
function filterParseAutocomplete(data) {
	if(data)
		areas = eval(data);
	if (!areas.length)
		widgetHelper.setFlag(false);
	return $.map(eval(data), function(row) {
		return {
			data:row,
			value:row.value,
			result:row.value
		};
	});
};
/**
 * Callback result for called to google geocoder service, 
 * looking for a valid geo-reference based on data entried by user in area search input.
 *  
 * @param matches 
 * @return
 */
function geocoderResult(matches){
	if(matches.length > 1){
		widgetHelper.setMatches(matches);
		$('#MultipleMatchModal').jqmShow();
	} else if(matches.length == 1){
		place = matches[0];
		setGeoreferenceValues({
			address: place.address,
			latitude_0: place.Point.coordinates[1],
			longitude_0: place.Point.coordinates[0],
			geo_reference: widgetHelper.getGeoTypes().GEO_CODED_STRING
		});
	} else {
		$('#NoMatchModal').jqmShow();
		setGeoreferenceValues({
			address: (widgetHelper.getInput()).val()
		});
	}
	enableSubmit();
};

/**
 * Sets values for required objects related with a geo-reference
 * @param options
 * @return
 */
function setGeoreferenceValues(options){
	options = jQuery.extend({
		address: '',
		latitude_0: '',
		longitude_0: '',
		latitude_1: '',
		longitude_1: '',
		radius: '',
		geo_reference: '',
		area_id: '',
		path: '',
		region_bounds: ''
	},options);
	lastAreaSelected = {
        id: options.area_id,
        value: options.address,
        latitude: options.latitude_0,
        longitude: options.longitude_0,
        path: options.path,
        radius: options.radius,
        bounds: options.region_bounds
	};
	if(options.geo_reference == widgetHelper.getGeoTypes().BOUNDING_BOX){
		$("#trCloseness").hide();
	} else if(typeof map != 'undefined' && options.geo_reference != '') {
		$("#trCloseness").show();
		var newBoundingBox = determineBoundingBox({
			latitude: options.latitude_0,
			longitude: options.longitude_0,
			region_bounds: options.region_bounds
		});
	}
	(widgetHelper.getInput()).val(options.address);
	widgetHelper.setHiddenValue('#path',options.path);
	widgetHelper.setHiddenValue('#geo_reference_type',options.geo_reference);
	widgetHelper.setHiddenValue('#latitude_0',options.latitude_0);
	widgetHelper.setHiddenValue('#longitude_0',options.longitude_0);
	widgetHelper.setHiddenValue('#latitude_1',options.latitude_1);
	widgetHelper.setHiddenValue('#longitude_1',options.longitude_1);
	widgetHelper.setHiddenValue('#radius',options.radius);
	widgetHelper.setHiddenValue('#region_bounds',options.region_bounds);
	widgetHelper.setHiddenValue('#area_id',options.area_id);
	if($.isFunction("checkRemainingTimeToCheckIn")){
		checkRemainingTimeToCheckIn();
	}
};
function fixBoundBox(){
    if($("#geo_reference_type").val() == widgetHelper.getGeoTypes().BOUNDING_BOX){
    	$("#trCloseness").hide();
    	map.setBoundingBoxClean(
			new google.maps.LatLngBounds(	
				new google.maps.LatLng($('#latitude_1').val(),$('#longitude_1').val()),//sw
				new google.maps.LatLng($('#latitude_0').val(),$('#longitude_0').val()) // ne
		    )
    	);
    } else if($("#Search") && !$("#Search").val()){
        setDefaultMapBoundsAsCoordinates();
    } else {
    	var newBoundingBox = determineBoundingBox({
			latitude: $('#latitude_0').val(),
			longitude: $('#longitude_0').val(),
			region_bounds: $('#region_bounds').val()
		});
    }
};
function determineBoundingBox(options){
	options = jQuery.extend({
		latitude: '',
		longitude: '',
		region_bounds: null
	},options);
	var speeds = widgetHelper.getSpeeds();
	var factor = speeds[parseInt($("#ItineraryTransportation").val())]*parseInt($("#hi-slider_ItineraryCloseness").val());
	var calculate = function(lat,lng,sum){
		var res = new Array(2);
		if(sum){
			//latitude
			res[0] = parseFloat(lat)+factor/getMiPerLat();
			//longitude
			res[1] = parseFloat(lng)+factor/getMiPerLonAtLat(res[0]);
			if(res[1] > 180) res[1] -= 360;
		} else {
			//latitude
			res[0] = parseFloat(lat)-factor/getMiPerLat();
			//longitude
			res[1] = parseFloat(lng)-factor/getMiPerLonAtLat(res[0]);
			if(res[1] < -180) res[1] += 360;
		}
		return res;
	};
	var ne = new Array(2);
	var sw = new Array(2);
	if(options.region_bounds && options.region_bounds != "null"){
		var bounds = options.region_bounds.split(" ");
		ne = bounds[0].split(",");
		sw = bounds[1].split(",");
		ne = calculate(ne[0],ne[1],true);
		sw = calculate(sw[0],sw[1],false);
	} else if(options.latitude != '' && options.longitude != '') {
		ne = calculate(options.latitude,options.longitude,true);
		sw = calculate(options.latitude,options.longitude,false);
	} else {
		return;
	}
	if(typeof map != 'undefined'){
		map.setBoundingBoxClean(
			new google.maps.LatLngBounds(	
				new google.maps.LatLng(sw[0],sw[1]),//sw
				new google.maps.LatLng(ne[0],ne[1]) // ne
		    )
		);
	}
	return new Array(ne,sw);
};
function getMiPerLonAtLat(latitude) {
	return getMiPerLat() * Math.cos(deg2rad(latitude));
}
function getMiPerLat() {
	return 69.171662465;
}
function deg2rad (angle) {
    // Converts the number in degrees to the radian equivalent  
    // 
    // version: 909.322
    // discuss at: http://phpjs.org/functions/deg2rad
    // +   original by: Enrique Gonzalez
    // *     example 1: deg2rad(45);
    // *     returns 1: 0.7853981633974483
    return (angle/180)*Math.PI;
}
function setDefaultMapBoundsAsCoordinates(){
    var bounds = map.getOptions('bounds');
    if(typeof bounds == 'object'){
        var ne = bounds.getNorthEast();
        var sw = bounds.getSouthWest();
        $('#latitude_0').val(ne.lat());
        $('#longitude_0').val(ne.lng());
        $('#latitude_1').val(sw.lat());
        $('#longitude_1').val(sw.lng());
    }
};
$(document).ready(function() {
	lastAreaSelected = {
        id: $("#area_id").val(),
        value: $("#Search").val(),
        latitude: $("#latitude_0").val(),
        longitude: $("#longitude_0").val(),
        path: $("#path").val(),
        radius: $("#radius").val(),
        bounds: $("#region_bounds").val()
	};
});