// Specify the search origin.
// storing its key info into variables that will be used to form
// the search request.
function addOrigin(lat,lng,address)
{
	$('#originLocationCheck').hide();
	$('#originLocationCheck').html('');

	if(gmarkers["origin"]!=false){
		map.removeOverlay(gmarkers['origin']);
	}	
    var point = new GLatLng(lat,lng);
	gmarkers['origin'] = new GMarker(point, originIcon);
	map.addOverlay(gmarkers['origin']);
	
	originstring = address;
	if(originPolygon.containsLatLng(point)){
		clearWarnings();
		origincountrycode = "GB";
	}else{
		showWarning("Searches must be made from an origin in the UK. Wider coverage will be available in later releases.");
	}	
	return;
}

// see add origin
function addDestination(lat,lng,address)
{
	destinationresortid = 0; // If there is one it will be set by autosuggest.
	$('#destinationLocationCheck').hide();
	$('#destinationLocationCheck').html('');
	
	if(gmarkers["destination"]!=false){
		map.removeOverlay(gmarkers['destination']);
	}
    var point = new GLatLng(lat,lng);
	gmarkers['destination'] = new GMarker(point, destinationIcon);
	map.addOverlay(gmarkers['destination']);
	
	destinationstring = address;

	if(everywherePolygon.containsLatLng(point)){
		clearWarnings();
		// Permitted destination, set country code and message appropriately
		if(originPolygon.containsLatLng(point)){
			destinationcountrycode = "GB";
		}else{
			destinationcountrycode = "FR"; // FR is used to mean !UK
			if(enhancedPolygon.containsLatLng(point)==false){
				showWarning("This destination only has 'standard' coverage. This means we will compare hire cars, and taxis at the destination but not all rail or local transport. See <a href=\"/coverage.htm\">coverage</a> for more details.");
			}
		}
	}else{
        showWarning("Searches must be made to to one of the European countries we have <a href=\"/coverage.htm\">coverage</a> of.");
	}
	return;
}

// Geocode the text in the origin field, if the result is ambiguous say
// "did you mean blah..." and let people select it. End result should
// be a lat, long, string addOrigin for validation and storage
function findOrigin()
{
	var address = document.getElementById('searchBox_From').value;
	if(address==''){
		return;
	}
	geocoding = true;
	geocoder.setBaseCountryCode('UK');
	
	// can we find a postcode unit?
	var postcodeRegex = new RegExp("(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW]) [0-9][ABD-HJLNP-UW-Z]{2})","gi");
	var hasPostcode = postcodeRegex.exec(address);
	
	if (hasPostcode){
		// if we could identify postcodes, pick the first one and outsource it.
		originFromPostcode(hasPostcode[0], address);
	} else {
		// Add 'UK' to the address if it isn't there already
		var containsUk = address.search(/UK/i);
		if (containsUk > -1){
			var geocodeAddress = address;
		} else {
			var geocodeAddress = address + ', UK';
		}
		geocoder.getLocations(geocodeAddress, function (result)
			{
				if(result.Status.code == G_GEO_SUCCESS){
					if (result.Placemark.length > 1){
						var apostropheRegExp = new RegExp("\'","g");
						document.getElementById("originLocationCheck").innerHTML = "Did you mean:";
						for (var i=0; i<result.Placemark.length; i++){
							var escapedAddress = result.Placemark[i].address.replace(apostropheRegExp,"\\'");
							var p = result.Placemark[i].Point.coordinates;
							document.getElementById("originLocationCheck").innerHTML += '<br>'+(i+1)+': <a href="javascript:addOrigin(' +p[1]+','+p[0]+',\''+escapedAddress+'\')">'+ result.Placemark[i].address+'<\/a>';
						}
						$('#originLocationCheck').show();
						
					}else{
						var p = result.Placemark[0].Point.coordinates;
						addOrigin(p[1],p[0],result.Placemark[0].address);
	            		scaleOriginDestination();
					}
				}else{
	        		var reason="Code "+result.Status.code;
	        		if (reasons[result.Status.code]){
	        			reason = reasons[result.Status.code];
	        		}
	        		showWarning('Could not find "'+address+ '"<br/> ' + reason);
	        	}
	        	geocoding = false;
	      	});	
	}
}

// equivalent to find origin
function findDestination()
{	
	var address = document.getElementById('searchBox_To').value;
	// Empty ot we have already matched this place.
	if(address=='' || address==destinationstring){
		return;
	}
		
	geocoding = true;
	geocoder.setBaseCountryCode('UK');
	
	// can we find a postcode unit?
	var postcodeRegex = new RegExp("(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW]) [0-9][ABD-HJLNP-UW-Z]{2})","gi");
	var hasPostcode = postcodeRegex.exec(address);
	
	if (hasPostcode){
		// if we could identify postcodes, pick the first one and outsource it.
		destinationFromPostcode(hasPostcode[0], address);
	} else {
		geocoder.getLocations(address, function (result)
		{
			if(result.Status.code == G_GEO_SUCCESS){
				if (result.Placemark.length > 1 ){
					var apostropheRegExp = new RegExp("\'","g");
					document.getElementById("destinationLocationCheck").innerHTML = "Did you mean:";
					
					for (var i=0; i<result.Placemark.length; i++){
						var escapedAddress = result.Placemark[i].address.replace(apostropheRegExp,"\\'");
						var p = result.Placemark[i].Point.coordinates;
						document.getElementById("destinationLocationCheck").innerHTML += '<br>'+(i+1)+': <a href="javascript:addDestination(' +p[1]+','+p[0]+',\''+escapedAddress+'\')">'+ result.Placemark[i].address+'<\/a>';
					}
					$('#destinationLocationCheck').show();
				}else{
					var p = result.Placemark[0].Point.coordinates;
					addDestination(p[1],p[0],result.Placemark[0].address);
            		scaleOriginDestination();
				}
			}else{
        		var reason="Code "+result.Status.code;
        		if (reasons[result.Status.code]){
        			reason = reasons[result.Status.code];
        		}
        		showWarning('Could not find "'+address+ '"<br/> ' + reason);
        	}
        	geocoding = false;
      	});
	}
}

function destinationFromPostcode(postcode, address, callbackFunction) {
    var localSearch = new GlocalSearch();
    
	localSearch.setSearchCompleteCallback(null, 
		function() {
			
			if (localSearch.results[0])
			{		
				var resultLat = localSearch.results[0].lat;
			    var resultLng = localSearch.results[0].lng;
			    addDestination(resultLat, resultLng, address);
			    scaleOriginDestination();
			}else{
				// TODO fail neatly
			}
			geocoding = false;
		});	
		
	localSearch.execute(postcode + ", UK");
}

function originFromPostcode(postcode, address, callbackFunction) {
    var localSearch = new GlocalSearch();
    
	localSearch.setSearchCompleteCallback(null, 
		function() {
			
			if (localSearch.results[0])
			{		
				var resultLat = localSearch.results[0].lat;
			    var resultLng = localSearch.results[0].lng;
			    addOrigin(resultLat, resultLng, address);
			    scaleOriginDestination();
			}else{
				// TODO fail neatly
			}
			geocoding = false;
		});	
		
	localSearch.execute(postcode + ", UK");
}

function loadBoundaries()
{
	// Create polygon method for collision detection
	// Based on http://dawsdesign.com/drupal/google_maps_point_in_polygon
	GPolygon.prototype.containsLatLng = function(latLng) {
		// Do simple calculation so we don't do more CPU-intensive calcs for obvious misses
		var bounds = this.getBounds();
		
		if(bounds != null && !bounds.containsLatLng(latLng)) {
			return false;
		}
		
		// Point in polygon algorithm found at http://msdn.microsoft.com/en-us/library/cc451895.aspx
		var numPoints = this.getVertexCount();
		var inPoly = false;
		var i;
		var j = numPoints-1;
		
		for(var i=0; i < numPoints; i++) { 
			var vertex1 = this.getVertex(i);
			var vertex2 = this.getVertex(j);
			
			if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng())  {
				if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
					inPoly = !inPoly;
				}
			}
			
			j = i;
		}
		
		return inPoly;
	};
	originPolygon = new GPolygon([			new GLatLng(49.52,-6.15),
	                            			new GLatLng(50.45,1.05),
	                            			new GLatLng(56.84,5.56),
	                            			new GLatLng(61.08,-0.57),
	                            			new GLatLng(57.96,-8.26),
	                            			new GLatLng(55.44,-7.27),
	                            			new GLatLng(55.06,-7.38),
	                            			new GLatLng(54.68,-8.00),
	                            			new GLatLng(54.44,-8.23),
	                            			new GLatLng(54.03,-7.54),
	                            			new GLatLng(54.21,-6.97),
	                            			new GLatLng(53.99,-6.64),
	                            			new GLatLng(54.11,-5.12),
	                            			new GLatLng(49.53,-6.15)
	                             ]);
	everywherePolygon = new GPolygon([new GLatLng(69.90,31.11),
	                                  new GLatLng(72.45,34.80),
	                                  new GLatLng(66.65,-27.07),
	                                  new GLatLng(34.89,-10.20),
	                                  new GLatLng(36.47,-3.34),
	                                  new GLatLng(37.94,11.89),
	                                  new GLatLng(35.56,14.37),
	                                  new GLatLng(40.13,18.85),
	                                  new GLatLng(42.67,18.46),
	                                  new GLatLng(45.12,15.89),
	                                  new GLatLng(44.90,19.20),
	                                  new GLatLng(45.95,18.92),
	                                  new GLatLng(46.16,20.24),
	                                  new GLatLng(44.28,22.76),
	                                  new GLatLng(42.26,22.46),
	                                  new GLatLng(41.34,22.98),
	                                  new GLatLng(40.85,21.14),
	                                  new GLatLng(39.66,20.08),
	                                  new GLatLng(39.96,19.64),
	                                  new GLatLng(37.00,18.65),
	                                  new GLatLng(33.94,24.93),
	                                  new GLatLng(34.52,34.76),
	                                  new GLatLng(35.89,35.90),
	                                  new GLatLng(36.63,36.78),
	                                  new GLatLng(37.13,44.78),
	                                  new GLatLng(41.28,43.41),
	                                  new GLatLng(41.71,41.40),
	                                  new GLatLng(42.36,34.37),
	                                  new GLatLng(45.21,29.88),
	                                  new GLatLng(45.74,27.99),
	                                  new GLatLng(46.92,28.30),
	                                  new GLatLng(48.37,26.76),
	                                  new GLatLng(48.11,22.85),
	                                  new GLatLng(49.04,22.76),
	                                  new GLatLng(50.51,24.17),
	                                  new GLatLng(52.40,23.25),
	                                  new GLatLng(52.86,23.95),
	                                  new GLatLng(54.21,23.42),
	                                  new GLatLng(54.88,18.98),
	                                  new GLatLng(59.62,22.37),
	                                  new GLatLng(60.39,27.77),
	                                  new GLatLng(62.88,31.90),
	                                  new GLatLng(67.02,29.05),
	                                  new GLatLng(67.68,30.32),
	                                  new GLatLng(69.02,28.65),
	                                  new GLatLng(69.90,31.11)]);
	enhancedPolygon = new GPolygon([new GLatLng(51.17,2.48),
	                                new GLatLng(49.01,8.44),
	                                new GLatLng(47.55,7.54),
	                                new GLatLng(46.51,6.31),
	                                new GLatLng(46.47,7.29),
	                                new GLatLng(43.71,7.84),
	                                new GLatLng(37.41,4.33),
	                                new GLatLng(35.73,-7.43),
	                                new GLatLng(42.02,-6.7),
	                                new GLatLng(42.07,-9.27),
	                                new GLatLng(50.4,-10.24),
	                                new GLatLng(52.36,-5.82),
	                                new GLatLng(54.28,-3.87),
	                                new GLatLng(54.53,-4.55),
	                                new GLatLng(54,-5.93),
	                                new GLatLng(54.18,-7.95),
	                                new GLatLng(54.5,-8.35),
	                                new GLatLng(55.33,-6.99),
	                                new GLatLng(57.61,-6.83),
	                                new GLatLng(58.68,-5.03),
	                                new GLatLng(58.76,-2.42),
	                                new GLatLng(55.24,0.57),
	                                new GLatLng(51.17,2.48)]);	
}

function getReasons()
{
	 var reasons = [];
	 reasons[G_GEO_SUCCESS]            = "Success";
     reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
     reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
     reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";                                                               
     reasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";                                                                
     reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";                                                                  
     reasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
     return reasons;
}

function showError(errorstring) {
	$('#searchBox div.formError').html(errorstring);
	$('#searchBox div.formError').show("slow");
	return;
}

function showWarning(warningstring) {
	$('#searchBox div.formWarning').html(warningstring);
	$('#searchBox div.formWarning').show("slow");
	return;
}

function clearErrors() {
	$('#searchBox div.formError').hide("slow");
	$('#searchBox div.formError').html('');
	return;
}

function clearWarnings() {
	$('#searchBox div.formWarning').hide("slow");
	$('#searchBox div.formWarning').html('');
	return;
}

function checkForm() {
	clearErrors();
	clearWarnings();
	if($('#searchBox_Depart').val() == "" || $('#searchBox_Return').val() == "")
	{
		showError("Both a departure date and return date must be given. Please try again.");
		return false;
	}

	if (gmarkers["origin"] === false || gmarkers["destination"] === false) {
		showError("Cannot search as start and/or end location has not been identified.<br/> Please try entering the origin and destination again.");
		return false;
	}
	if (origincountrycode != "GB" || (destinationcountrycode != "GB" && destinationcountrycode != "FR")) {
		$('originLocationCheck').hide();
		$('originLocationCheck').html('');
		$('destinationLocationCheck').hide();
		$('destinationLocationCheck').html('');
		showError("Searches must be made from an origin in the UK to one of the European countries we <a href=\"/coverage.htm\">cover</a>.");
		return false;
	}
	
	// Check the dates
	var outwardDate = $('#searchBox_Depart').datepicker('getDate');
	var returnDate = $('#searchBox_Return').datepicker('getDate');
	var now = new Date();
	var dateFailure = false;
	var dateMessage = "";
	if(returnDate<outwardDate){
		dateFailure = true;
		dateMessage += "Sorry, the selected outward date is after the selected return date.";
	}
	if(outwardDate < now){
		dateFailure = true;
		dateMessage += " Sorry, the outward date must be later than today.";
	}
	if(dateFailure){
		dateMessage += " Please change the dates and try again.";
		showError(dateMessage);
		return false;
	}

	if(siysIframe === true){
		// Ideally wait for geocoding to finish as in regular search
		scaleOriginDestination();
		searchRequest();
		return true;
	}else{		
		geocodingwait = 0;
		delayLaunch();
	}
}

function delayLaunch() {
	if (geocoding == false) {
		scaleOriginDestination();
		searchRequest();
	} else if (geocodingwait < 5) {
		geocodingwait++;
		setTimeout("delayLaunch()", 1000);
	} else {
		showError("Cannot search as start and/or end location have not been identified.<br/> Please try entering the origin and destination again.");
	}
}

function searchRequest() {
	// For Ajax based requests only allow it to be requested once.
	if(!siysIframe){
		if(dontStartSearch==true){
			return;
		}else{
	    	dontStartSearch=true;
		}
	}
	var originGLatLng = gmarkers['origin'].getLatLng();
	var destinationGLatLng = gmarkers['destination'].getLatLng();
	var outwarddate = $('#searchBox_Depart').val();
	var returndate = $('#searchBox_Return').val();

	// The 'address' values from the geocoder are too long.
	originstring = $('#searchBox_From').val();
	destinationstring = $('#searchBox_To').val();
	
	if(siysIframe === true){
		// Set the hidden fields of the form
		$('#originlat').val(originGLatLng.lat());
		$('#originlng').val(originGLatLng.lng());
		$('#destinationlat').val(destinationGLatLng.lat());
		$('#destinationlng').val(destinationGLatLng.lng());
		$('#outwarddate').val(outwarddate);
		$('#returndate').val(returndate);
		$('#originstring').val(originstring);
		$('#destinationstring').val(destinationstring);
		$('#origincountry').val(origincountrycode);
		$('#destinationcountry').val(destinationcountrycode);
		$('#destinationresortid').val(destinationresortid);
	}else{
		
		$.getJSON(
					'/search/request/create',
					{
						originlat : originGLatLng.lat(),
						originlng : originGLatLng.lng(),
						destinationlat : destinationGLatLng.lat(),
						destinationlng : destinationGLatLng.lng(),
						outwarddate : outwarddate,
						returndate : returndate,
						originstring : originstring,
						destinationstring : destinationstring,
						origincountry : origincountrycode,
						destinationcountry : destinationcountrycode,
						destinationresortid : destinationresortid,
						format : 'json'
					},
					function(requestresultjson) {
						if (!requestresultjson.error) {
							searchId = requestresultjson.searchId;
							window.location = '/search/results/progress/searchId/' + searchId;
						} else {
							dontStartSearch=false;
							showError(requestresultjson.message);
						}
					});
	}
	return;
}

function addLeadingZero(value) {
	if (value < 10) {
		value = '0' + value;
	}
	return value;
}

//Scale map so it shows the origin and destination pins.
function scaleOriginDestination(){
   	 if(gmarkers["origin"]===false || gmarkers["destination"]===false)
   	 {
   	 	return;
   	 }
	var bounds = new GLatLngBounds();
	bounds.extend(gmarkers["origin"].getLatLng());
	bounds.extend(gmarkers["destination"].getLatLng());
	map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
	
	// Warn people if it is a very short journey within the UK
	if(destinationcountrycode == "GB"){
		var distanceInMetres = gmarkers['origin'].getLatLng().distanceFrom(gmarkers['destination'].getLatLng());
		if(distanceInMetres < 100000){
			showWarning("Zoombu can run searches for short distances like this, but it performs best for longer journeys where it is useful to consider options such as flying.");
		}
	}
}