// JavaScript Document

			/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

			/* Great Circle calculation code from http://www.movable-type.co.uk/scripts/latlong.html
			 *
			 * Use Haversine formula to Calculate distance (in km) between two points specified by 
			 * latitude/longitude (in numeric degrees)
			 *
			 * from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine",
			 *       Sky and Telescope, vol 68, no 2, 1984
			 *       http://www.census.gov/cgi-bin/geo/gisfaq?Q5.1
			 *
			 * example usage from form:
			 *   result.value = LatLon.distHaversine(lat1.value.parseDeg(), long1.value.parseDeg(), 
			 *                                       lat2.value.parseDeg(), long2.value.parseDeg());
			 * where lat1, long1, lat2, long2, and result are form fields
			 */
			LatLon.distHaversine = function(lat1, lon1, lat2, lon2) {
			  var R = 6371; // earth's mean radius in km
			  var dLat = (lat2-lat1).toRad();
			  var dLon = (lon2-lon1).toRad();
			  lat1 = lat1.toRad(), lat2 = lat2.toRad();

			  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
			          Math.cos(lat1) * Math.cos(lat2) * 
			          Math.sin(dLon/2) * Math.sin(dLon/2);
			  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
			  var d = R * c;
			  return d;
			}

			/*
			 * construct a LatLon object: arguments in numeric degrees
			 *
			 * note all LatLong methods expect & return numeric degrees (for lat/long & for bearings)
			 */
			function LatLon(lat, lon) {
			  this.lat = lat;
			  this.lon = lon;
			}


			/*
			 * represent point {lat, lon} in standard representation
			 */
			LatLon.prototype.toString = function() {
			  return this.lat.toLat() + ', ' + this.lon.toLon();
			}



			// extend Number object with methods for converting degrees/radians

			Number.prototype.toRad = function() {  // convert degrees to radians
			  return this * Math.PI / 180;
			}

			Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
			  return this * 180 / Math.PI;
			}

			Number.prototype.toBrng = function() {  // convert radians to degrees (as bearing: 0...360)
			  return (this.toDeg()+360) % 360;
			}

			/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

			// function reduceTotal(JQuery targetElement, float reductionAmount)
			function reduceTotal(targetElement, reductionAmount) {
				newTotal =  parseFloat(targetElement.html()) - parseFloat(reductionAmount);
				newTotal = Math.round(newTotal*100)/100;
				targetElement.html(newTotal);
			}

			// we can't offset more passengers than are in the vehicle, so make sure passengers in vehicle is at least the number of passengers to offset.
			function matchSmallVehiclePassengers() {
				if ( $("#small-ground-offset-passengers").val() > $("#small-ground-vehicle-passengers").val()) {
					$("#small-ground-vehicle-passengers").val($("#small-ground-offset-passengers").val());
				}
			}


			// this is all the stuff that runs once the DOM for the page is ready, like onLoad but without the wait for images.
			$(document).ready(function(){

				showHideTable($("#ground-summary"), $("#ground-emissions-total"));

				// add the code to delete an entry from the summary list on clicking the delete link.
				$(".delete_entry").click( function() {
					// check the user really wants to do that.
					var answer = confirm("Delete this entry?");
					if (answer) {
						// hide the record from the page.
						$(this).parent().parent().hide();

						reduceTotal($("#ground-emissions-total"), parseFloat($(this).parent().prev().html()));

						// setup the URL to the PHP page that will actually remove the record from the DB.
						deleteURL = "./includes/delete-db-record.php?action=deleterecord&table=emissions&id=" + $(this).attr('id');

						// do an AJAX call in the background to delete the DB record.
						$.get(deleteURL);
						updateTotalDisplay();
						showHideTable($("#ground-summary"), $("#ground-emissions-total"));
					}
					});

				$("input[@name='return-or-oneway']").click(function(){
					recalculateGround();
				});

				$("input[@name='cities-or-distance']").click(function(){
					recalculateGround();
				});

				$("#start-city").change( function() {
					recalculateGround();
					$("#hidden-start-city").val($("#start-city option:selected").text() + ", " + $("#start-state").val());
				});

				$("#destination-city").change( function() {
					recalculateGround();
					$("#hidden-destination-city").val($("#destination-city option:selected").text() + ", " + $("#destination-state").val());
				});

				$("#large-ground-offset-passengers").change( function() {
					recalculateGround();
				});

				$("#small-ground-offset-passengers").change( function() {
					recalculateGround();
					matchSmallVehiclePassengers();
				});

				$("#small-ground-vehicle-passengers").change( function() {
					recalculateGround();
				});

				$("#transportationMode").change( function() {
					recalculateGround();
				});

				$("#ground-distance").change( function() {
					recalculateGround();
				});

				$("#ground-distance-unit").change( function() {
					recalculateGround();
				});

				$("#start-state").change( function() {
					var blankOption = "<option value=''>-- city --</option>\n";
					$("#start-city").html(blankOption + stateCities($("#start-state").val()));		
					$('#start-city option:first').attr('selected', 'selected');
					recalculateGround();
				});

				$("#destination-state").change( function() {
					var blankOption = "<option value=''>-- city --</option>\n";
					$("#destination-city").html(blankOption + stateCities($("#destination-state").val()));
					$('#destination-city option:first').attr('selected', 'selected');
					recalculateGround();
				});

				$("#ground-hours").change( function() {
					recalculateGround();
				});


			}); // $(document).ready ENDS

			// function calculateGroundEmissions(string transportMode, int distance, int passengers)
			// calculates emissions for ground journeys based on emissions per passenger mile.	
			// NOTE: calculations are different from original, to allow calculating emissions for multiple passengers.	
			function calculateGroundEmissions(transportMode, distance, passengersToOffsetLarge, passengersToOffsetSmall, passengersInVehicleSmall) {
				var tEmissions;
				switch (transportMode) {
					case "train": tEmissions = distance * 0.1 * passengersToOffsetLarge;
					break;
					case "bus": tEmissions = distance * 0.06 * passengersToOffsetLarge;
					break;
					case "small-car": tEmissions = distance * (0.23 / passengersInVehicleSmall) * passengersToOffsetSmall;
					break;
					case "large-car": tEmissions = distance * (0.3 / passengersInVehicleSmall) * passengersToOffsetSmall;
					break;
					case "suv-van": tEmissions = distance * (0.37 / passengersInVehicleSmall) * passengersToOffsetSmall;
					break;
				}

				// double the emissions if we're calculating for a return journey.
				if ( $("input[@name='return-or-oneway']:checked").val() == 'return' ) {
					tEmissions = tEmissions * 2;
				}

				tEmissions = tEmissions / 1000;
				tEmissions = Math.round(tEmissions * 100)/100;
				return tEmissions;	
			}

			function displayGroundEmissions(emissionValue) {
				$("span#totalGroundEmissions").html(emissionValue);
				$("#hidden-emissions").val(emissionValue);
			}

			function calculateDistance(lat1, lon1, lat2, lon2) {
				// check that both sets of coordinates are set.
				if (lat1 && lon1 && lat2 && lon2) {
					var distanceKM = Math.round(LatLon.distHaversine(lat1, lon1, lat2, lon2)*1)/1;
					return distanceKM;
				}
			}

			function recalculateGround() {

				if ( $("#transportationMode").val() == 'small-car' || $("#transportationMode").val() == 'large-car' || $("#transportationMode").val() == 'suv-van' ) {
					switchLayer('small-vehicle', 'on');
					switchLayer('hours-driven', 'on');
					switchLayer('large-vehicle', 'off');
					$("#hidden-vehicle-size").val('small');
				} else {
					switchLayer('small-vehicle', 'off');
					switchLayer('hours-driven', 'off');
					switchLayer('large-vehicle', 'on');				
					$("#hidden-vehicle-size").val('large');
				}

				coords1 = $("#start-city").val().split(",");
				coords2 = $("#destination-city").val().split(",");
				lat1 = parseFloat(coords1[0]);
				lon1 = parseFloat(coords1[1]);
				lat2 = parseFloat(coords2[0]);
				lon2 = parseFloat(coords2[1]);

				var distance = 0;

				if ( $("input[@name='cities-or-distance']:checked").val() == 'cities-option' ) {
					distance = calculateDistance(lat1, lon1, lat2, lon2);
				} else if ( $("input[@name='cities-or-distance']:checked").val() == 'distance-option' ) {
					distance = $("#ground-distance").val();
					if ($("#ground-distance-unit").val() == "MILES") {
						distance = distance * MILES2KMMULTIPLIER;
					}
				} else if ( $("input[@name='cities-or-distance']:checked").val() == 'hours-option' ) {
					KMPERHOUR = 100;
					distance = $("#ground-hours").val() * KMPERHOUR;
				}
				var emissions = calculateGroundEmissions($("#transportationMode").val(), distance, $("#large-ground-offset-passengers").val(), $("#small-ground-offset-passengers").val(), $("#small-ground-vehicle-passengers").val());
				// alert(emissions);
				if ( emissions > 0 ) {
					displayGroundEmissions(emissions);
					$("#add_ground").disabled = false;
					$("#add_ground").attr('disabled', false);
					$("#totalGroundEmissionsSection").css("display", "block");
				} else {
					displayGroundEmissions( '0' ); 
				}
			}

			function stateCities(state) {
				switch (state) {
					case "AB": return ABCities; break;
					case "AB": return ABCities; break;
					case "AK": return AKCities; break;
					case "AL": return ALCities; break;
					case "AR": return ARCities; break;
					case "AZ": return AZCities; break;
					case "BC": return BCCities; break;
					case "CA": return CACities; break;
					case "CO": return COCities; break;
					case "CT": return CTCities; break;
					case "DC": return DCCities; break;
					case "DE": return DECities; break;
					case "FL": return FLCities; break;
					case "GA": return GACities; break;
					case "IA": return IACities; break;
					case "ID": return IDCities; break;
					case "IL": return ILCities; break;
					case "IN": return INCities; break;
					case "KS": return KSCities; break;
					case "KY": return KYCities; break;
					case "LA": return LACities; break;
					case "MA": return MACities; break;
					case "MB": return MBCities; break;
					case "MD": return MDCities; break;
					case "MI": return MICities; break;
					case "MN": return MNCities; break;
					case "MO": return MOCities; break;
					case "MS": return MSCities; break;
					case "MT": return MTCities; break;
					case "NB": return NBCities; break;
					case "NC": return NCCities; break;
					case "ND": return NDCities; break;
					case "NE": return NECities; break;
					case "NH": return NHCities; break;
					case "NJ": return NJCities; break;
					case "NL": return NLCities; break;
					case "NM": return NMCities; break;
					case "NS": return NSCities; break;
					case "NT": return NTCities; break;
					case "NU": return NUCities; break;
					case "NV": return NVCities; break;
					case "NY": return NYCities; break;
					case "OH": return OHCities; break;
					case "OK": return OKCities; break;
					case "ON": return ONCities; break;
					case "OR": return ORCities; break;
					case "PA": return PACities; break;
					case "PE": return PECities; break;
					case "QC": return QCCities; break;
					case "RI": return RICities; break;
					case "SC": return SCCities; break;
					case "SD": return SDCities; break;
					case "SK": return SKCities; break;
					case "TN": return TNCities; break;
					case "TX": return TXCities; break;
					case "UT": return UTCities; break;
					case "VA": return VACities; break;
					case "WA": return WACities; break;
					case "WI": return WICities; break;
					case "WV": return WVCities; break;
					case "WY": return WYCities; break;
					case "YT": return YTCities; break;				
				}
			}



