//This file was started by Paul 19/11/2008 to query Google to get the driving distances between stops.
//Google's GDirection object lets you get the driving distance and time but only works on the first part
//of the post code. So this uses an Ajax method  to first get the full lat/long of all the stops
//(copied from http://www.tomanthony.co.uk/blog/geocoding-uk-postcodes-with-google-map-api/). Then
//it gets the directions. 

var STOPBASE = '50.875629,0.017858'; //the first and last stop for the taxi (Lewes Taxis World HQ)
var STOPFORM = null; //this stores the current form that the page is using
var STOPDEBUG = false; //turn this on to fill in some default stops and output the progress via alerts

//Get the driving distances, passing in the form. The form elements are from the Cake forms
//and have fairly specific names, like data[stop0], data[stop1], data[distance] and data[time].
function GetQuickQuoteDrivingDistance (theform) {
	//Build an array with all the stop names in it
	var stopnames = new Array();
	var el=null; for (var i=0; i<20; i++) if ((el = theform['data[stop' + i + ']']) && el.value.length>1) stopnames.push (el.value);
	//Save the form in a global variable
	STOPFORM = theform;
	//They must have entered at least 2 locations. In debug mode prefill a couple automatically
	if (STOPDEBUG && stopnames.length < 2) {stopnames[0] = 'Brighton'; stopnames[1] = 'Worthing';}
	if (stopnames.length < 2) {alert ('Please enter a pick-up and destination.'); return false;}
	//Start looking things up, the database requires exact matches so pass in true
	GetDrivingDistance ('StoreDrivingDistance', stopnames, true);
	//Return false so that the form doesn't submit immediately
	return false;
}

//This is called from the from/to page to refine the places. 
function RefineDrivingDistance (theform) {
	//First popup a message if they haven't entered all the pickup details
	if (!theform['data[0][house]'].value || !theform['data[0][street]'].value || !theform['data[0][post_code]'].value) 
		if (!confirm ('Please be as specific as possible, and fill in the pick-up house number, street, town and post code, unless you are being picked up from a station or airport.\n\nClick Cancel to fill in more information, or OK to continue.')) return false;
	//Build an array with all the stop names in it
	var stopnames = new Array();
	for (var i=0; i<20; i++) { //loop through all desinations
		if (!theform['data[' + i + '][house]']) continue;  //skip this one
		var stop = ''; var part = ''; var street = ''; var city = '';
		var pcpart = theform['data[' + i + '][post_code]'].value; //the post code part
		if (pcpart.length >= 5) stop += ', ' + pcpart; //they have provided a post code so just use this for the lookup, added by Paul 4/3/2009
		else { //they have not provided a full post code, so use the rest of the form for the lookup, added by Paul 4/3/2009
			if ((part = theform['data[' + i + '][house]'].value) && part.length < 5) stop += ', ' + part; //only use house if it is a short string so we know it's a number
			if (street = theform['data[' + i + '][street]'].value) stop += ', ' + street;
			if (city = theform['data[' + i + '][city]'].value) stop += ', ' + city;
			
			// MS: 2009.05.27 KLUDGE: Workaround to fix Google error when looking for High St Lewes (it goes to High St Newick)
			if ((street.toLowerCase().substr(0,4) == 'high' && city.toLowerCase().substr(0,5) == 'lewes') && !pcpart) {
				pcpart = 'BN7';
				theform['data[' + i + '][post_code]'].value = pcpart;
			}
			// MS: 2009.05.27 END KLUDGE: Workaround to fix Google error when looking for High St Lewes (it goes to High St Newick)
			
			if (pcpart) stop += ', ' + pcpart;
		}
		//Replace & with and's or else the database lookup doesn't work because "/locations/lookup/St Peter & James" cuts off at the & no matter how much I escape it
		if (stop) stopnames.push (stop.substr(2)); //push the stop name onto the array
		else {alert ('Please enter all the stops.'); return false;}
	}
	//Save the form in a global variable
	STOPFORM = theform;
	//Start looking things up, the database doesn't require exact matches
	GetDrivingDistance ('StoreDrivingDistance', stopnames, false);
	//Return false so that the form doesn't submit immediately
	return false;
}

//This is called after the distances are retrieved by the refining function above
function StoreDrivingDistance (stopnames, latlons, results) {
	var theform = STOPFORM;
	theform['data[stopnames]'].value = stopnames.join ('/'); //the stops joined by slashes
	theform['data[latlons]'].value = latlons.join ('/'); //the lat longs joined by slashes
	theform['data[distance_taxi]'].value = results[0];
	theform['data[duration_taxi]'].value = results[1];
	theform['data[distance_customer]'].value = results[2];
	theform['data[duration_customer]'].value = results[3];
	theform.submit(); //submit the form
}

//This function should be passed a list of places. It will lookup the lat/lons for each and compute
//the taxi distance/duration. It passes all these to the call back function. This process works by
//first calling GetNextStop a few times, and then GetNextDirections.
function GetDrivingDistance (callback, stopnames, exactdb) {
	if (!GBrowserIsCompatible()) {alert ('Sorry - you need a Google compatible browser to use this facility'); return null;}
	//Now start searching. After a search has finished, the next search will be called.
	var search = new GlocalSearch();
  	GetNextStop (callback, search, stopnames, 0, new Array(), exactdb); 
	//Return false so that the form doesn't submit immediately
	return false;
}

//This gets the next stop and then calls the same function again and again until all the stops have been found.
//It looks in the Lewes Taxis database (locations table) and in Google. On 4/3/2009 Paul added a database override
//for the Google search, so if the database found something that could be match but it not definite, then the Google
//search is still preformed, and if Google doesn't know the answer, then the broad database match is used.
function GetNextStop (callback, search, stopnames, stopindex, latlons, exactdb, fromdatabase, fromgooglesearch, fromdatabaseoverride) {
	//We have successfully found all the stops, so now we can look up the distance. This is only called
	//after all the stops have been found either in the database or in Google.
	if (stopindex >= stopnames.length) {
		//This is the query for the taxi from the pick up, through Lewes base, to the destination
		var queries = new Array ('', ''); queries[0] = 'from: ' + latlons[0] + ' to: ' + STOPBASE + ' to: ' + latlons[latlons.length-1];
		//Now do the next query from the pick up, through the vias, to the destination
		for (var i=0; i<latlons.length; i++) if (latlons[i]) queries[1]+= latlons[i] + ' to: ';
		queries[1] = 'from: ' + queries[1].substring (0, queries[1].length-5);
		//Now start getting the distances and durations by using Google directions
		GetNextDirections (callback, stopnames, latlons, queries, 0, new Array());
	}
	//If we have just done a database search then try to get the results. If so, save it. If not, then setup a google search. 
	//The Google search will end up triggering the next else condition instead of this one.
	else if (fromdatabase) {
		var latpos = fromdatabase.indexOf ('<latitude>'); var lonpos = fromdatabase.indexOf ('<longitude>');
		var latdb = fromdatabase.substring (latpos+10, fromdatabase.indexOf ('</latitude>')); //parse for latitude
		var londb = fromdatabase.substring (lonpos+11, fromdatabase.indexOf ('</longitude>')); //parse for longitude
		//If this was a broad match only, then still do the Google search but allow it to override the results, added by Paul 4/3/2009
		var broadmatch = !exactdb && latpos >= 0 && lonpos >= 0 && fromdatabase.indexOf ('<exactmatch>') < 0 ? latdb + ',' + londb : '';
		//From 4/3/2009, if it was only a broad match, then still do the Google search but pass in the parameters found as an override
		if (!broadmatch && latpos >= 0 && lonpos >= 0) latlons[stopindex] = latdb + ',' + londb; //save from the results
		else { //Or else look for the location in Google, passing in all the same parameters
			if (STOPDEBUG && !confirm ('About to ask Google about stop ' + stopindex + ': ' + stopnames[stopindex] + (broadmatch ? ', has broad match ' + broadmatch : ''))) return;
			search.setSearchCompleteCallback (null, function() {GetNextStop (callback, search, stopnames, stopindex, latlons, exactdb, null, true, broadmatch);});
			search.execute (stopnames[stopindex] + ', UK');
		}
	}
	//Or else if the last call was from Google, then parse the data from there. If we found a place then do the next search
	//or else output an error message and stop.
	else if (search.results && fromgooglesearch) {
		var i=0; while (i<search.results.length && search.results[i].country != 'GB' && i<1000) i++; //until we find one within the UK
		if (i<search.results.length) latlons[stopindex] = search.results[i].lat + ',' + search.results[i].lng; //record the lat and lon
		else if (fromdatabaseoverride) latlons[stopindex] = fromdatabaseoverride; //if no Google results were found then use the database's broad match
		if (!latlons[stopindex]) {alert ('Sorry but we could not find ' + stopnames[stopindex]); return;} //time to give up if we haven't found it by now
	}
	//Or else we need to kick off the search in the first place. This happens the first time this function is called and 
	//after a location was successfully found in the database or Google search
	else {
		if (STOPDEBUG && !confirm ('About to look in the database for stop ' + stopindex + ': ' + stopnames[stopindex])) return;
		//Replace & with something or else the database lookup doesn't work because "/locations/lookup/St Peter & James" cuts off at the & no matter how much I escape it
		GDownloadUrl ('/locations/lookup/' + escape (stopnames[stopindex].replace (/&/, 'AMPERSAND')) + (exactdb?'/yes':''), function (data) {GetNextStop (callback, search, stopnames, stopindex, latlons, exactdb, data);});
	}
	//If we have just found this stop, either in the database or the search above, we can go onto the next search.
	if (latlons[stopindex]) {
		if (STOPDEBUG && !confirm ('Location ' + stopindex + ' at ' + stopnames[stopindex] + ' found at ' + latlons[stopindex])) return;
		GetNextStop (callback, search, stopnames, stopindex+1, latlons, exactdb); //lookup the next place
	}
}


//Now we will get the directions for each of the queries passed in. After the final set of directions, run the call back
function GetNextDirections (callback, stopnames, latlons, queries, queryindex, results) {
	//Create a new directions object and get the directions between the stops
	//The warning div is required when getting walking directions: http://groups.google.com/group/Google-Maps-API/browse_thread/thread/294792bda4489fbe/1909af7df0fbe591
	//var directions = new GDirections (null, document.getElementById ('googlewarningdiv')); //the warning div is necessary if using walking distances
	var directions = new GDirections (null); 
	var query = queries[queryindex]; //which query to use
	//Now start the directions query
	if (STOPDEBUG && !confirm ('About to load directions for the query:\n' + query)) return;
	GEvent.addListener (directions, 'error', function() {alert ("We're sorry but we can't fulfill your query at this time (error: " + directions.getStatus().code + ')');});
	GEvent.addListener (directions, 'load', function() {
		var meters = directions.getDistance().meters; //get the distance
		var seconds = directions.getDuration().seconds; //and the duration
		if (STOPDEBUG && !confirm ('For query ' + queryindex + ', the distance is ' + meters + ' meters, it takes ' + seconds + ' seconds')) return;
		results.push (meters, seconds); //add the distance and duration to the results
		//If we're not on the last query then call the next directions query
		if (queryindex < queries.length - 1) GetNextDirections (callback, stopnames, latlons, queries, queryindex+1, results); //get the next query
		else eval (callback + '(stopnames, latlons, results)');
	});
	//directions.load (query, {locale: 'en_UK'}); //load the driving directions
	//directions.load (query, {locale: 'en_UK', travelMode: G_TRAVEL_MODE_WALKING}); //load the walking directions
	directions.load (query, {locale: 'en_UK', avoidHighways: true}); //from 15/4/2009 avoid highways
}


//This function is called from fromto.ctp to show the directions visually
function ShowDirections (mapid, query) {
	if (!GBrowserIsCompatible()) return;
	//Create a new icon for the different points on the map, tip came from http://groups.google.com/group/Google-Maps-API/browse_thread/thread/82d8840a140426ee?pli=1
	//But I couldn't get it to work quickly, so I'll return to it later:
	//G_START_ICON.image = '/img/google-map/pink-circle.png';
	//Create the new map and add the controls
	map = new GMap2 (document.getElementById (mapid));
	//var pos = STOPBASE.indexOf (','); map.setCenter (new GLatLng (STOPBASE.substr (0, pos), STOPBASE.substr (pos+1)), 8); //no need to do this
	map.addControl (new GLargeMapControl()); //add zooming
	//map.addControl (new GMapTypeControl()); //but not the type of view
	//Get the directions
	if (STOPDEBUG && !confirm ('About to load directions for the query:\n' + query)) return;
	var directions = new GDirections (map); 
	GEvent.addListener (directions, 'error', function() {alert ("We're sorry but we can't fulfill your query at this time (error: " + directions.getStatus().code + ')');});
	directions.load (query, {locale: 'en_UK'}); //load the driving directions
	GEvent.addListener (directions, 'load', function() {map.zoomOut();});
}
