jQuery(function($) {
	function pluralize() {
		$result = $('.tabs-container .result');
		if ($result.find('.trees').html()>1) $result.find('.treesPlural').show();
		else $result.find('.treesPlural').hide();	
	}
	
	function getDistance(origin, callback) { 
		if (typeof(google)!=='undefined') {
			geocoder = new google.maps.Geocoder();
			geocoder.geocode( { 'address': origin }, function(results, status) {
				if (status == google.maps.GeocoderStatus.OK) {
					// Origin
					var lat1 = results[0].geometry.location.b;
					var lon1 = results[0].geometry.location.c;
					var originAddress = results[0].formatted_address;
					// Nelson
					var lat2 = -41.270786;
					var lon2 = 173.284;
				
					// Great circle distance
					var R = 6371; // km
					var dLat = (lat2-lat1).toRad();
					var dLon = (lon2-lon1).toRad(); 
					var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
					        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
					        Math.sin(dLon/2) * Math.sin(dLon/2); 
					var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
					var d = R * c;
					
					callback({ distance: d, address: originAddress, message: "OK" });
				} else {
					callback({ distance: false, address: "", message: "Location not found, please try again." });
				}
			});
		} else {
			callback({ distance: false, address: "", message: "Could not connect to the location server, please try the dropdown." });
		}
	}
	
	var flightOrigins = {
		1000: {name: "--- NZ ---"},
		1: {name: "Auckland", distance: 508},
		2: {name: "Christchurch", distance: 257},
		3: {name: "Wellington", distance: 125},
		1001: {name: "--- Australia ---"},
		4: {name: "Brisbane", distance: 2400},
		5: {name: "Melbourne", distance: 2448},
		6: {name: "Perth", distance: 5135},
		7: {name: "Sydney", distance: 2105},
		1002: {name: "--- World ---"},
		8: {name: "Bangkok", distance: 9629},
		9: {name: "Buenos Aires", distance: 10066},
		10: {name: "Dublin", distance: 18672},
		11: {name: "Frankfurt", distance: 18472},
		12: {name: "Hong Kong", distance: 9339},
		13: {name: "Johannesburg", distance: 11702},
		14: {name: "London", distance: 18772},
		15: {name: "Los Angeles", distance: 14517},
		16: {name: "Moscow", distance: 16454},
		17: {name: "New York", distance: 14517},
		18: {name: "Singapore", distance: 8411},
		19: {name: "Tokyo", distance: 9214},

	};

	var carbonMapping = {
		flight: {
			"international": 0.097,
			"domestic": 0.118
		},
		car: {
			"petrol": {
				"medium": 0.234
			}
		}
	};
	
	var carbonToTrees = 1/525;
	var treeToPrice = 25;

	// Generate the dropdown
	for (var id in flightOrigins) {
		$('#ec-tabs-flight .form #FlightFrom').append($('<option value="'+id+'">'+flightOrigins[id].name+'</option>'));
	}
	
	// Clear the error
	$('#ec-tabs form').submit(function(e) {
		$(this).parent().siblings('.error').hide();
	});
	
	// Reset the dropdown when doing location search
	$('#ec-tabs-flight #FlightForm #FlightFromSearch').focus(function(e) {
		$('#ec-tabs-flight .form #FlightFrom').val(0);
	});
	
	// Calculate the carbon for flight
	$('#ec-tabs-flight #FlightForm').submit(function(e) {		
		var id = $('#ec-tabs-flight #FlightForm #FlightFrom').val();
		var search = $('#ec-tabs-flight #FlightForm #FlightFromSearch').val();
		
		function success(distance, origin) {
			var carbonFactor = distance>2000 ? carbonMapping.flight.international : carbonMapping.flight.domestic;
			
			$('#ec-tabs-flight .result #ec-flight-tabs-oneway .distance').html(
				distance.format('0,0')
			);
			$('#ec-tabs-flight .result #ec-flight-tabs-oneway .origin').html(
				origin
			);
			$('#ec-tabs-flight .result #ec-flight-tabs-oneway .carbon').html(
				(distance * carbonFactor).format('0,0.00')
			);
			$('#ec-tabs-flight .result #ec-flight-tabs-oneway .trees').html(
				Math.ceil(distance * carbonFactor * carbonToTrees)
			);
						
			$('#ec-tabs-flight .result #ec-flight-tabs-return .distance').html(
				(distance * 2).format('0,0')
			);
			$('#ec-tabs-flight .result #ec-flight-tabs-return .origin').html(
				origin
			);
			$('#ec-tabs-flight .result #ec-flight-tabs-return .carbon').html(
				(distance * 2 * carbonFactor).format('0,0.00')
			);
			$('#ec-tabs-flight .result #ec-flight-tabs-return .trees').html(
				Math.ceil(distance * 2 * carbonFactor * carbonToTrees)
			);
			
			$('#ec-tabs-flight .result').show();
			$('#ec-tabs-flight .form').hide();
			
			pluralize();
		}
		
		if (id && id<1000 && flightOrigins[id]) {
			success(flightOrigins[id].distance, flightOrigins[id].name);
		}
		else if (search) {
			var that = this;
			
			getDistance(search, function(result) {
				if (result.distance!==false) {
					success(Math.round(result.distance), result.address);
				}
				else {
					$(that).parent().siblings('.error').html(result.message).show();
				}
			});
		}
		else {
			$(this).parent().siblings('.error').html('Please fill in the fields.').show();
		}
		
		e.preventDefault();
	});
	
	// Calculate the carbon for a car
	$('#ec-tabs-car #CarForm').submit(function(e) {
		var carbonFactor = carbonMapping.car['petrol']['medium'];
		var distance = parseInt($('#ec-tabs-car .form #CarDistance').val());
		
		if (carbonFactor && distance) {
			$('#ec-tabs-car .result .distance').html(
				distance.format('0,0')
			);
			$('#ec-tabs-car .result .carbon').html(
				(distance * carbonFactor).format('0,0.00')
			);
			$('#ec-tabs-car .result .trees').html(
				Math.ceil(distance * carbonFactor * carbonToTrees)
			);
			
			$('#ec-tabs-car .result').show();
			$('#ec-tabs-car .form').hide();
		}
		else {
			$(this).parent().siblings('.error').html('Please fill in all fields.').show();
		}
		
		e.preventDefault();
	});
	
	// Show the form again to allow recalculation. Reset the fields.
	$('#ec-tabs .recalculate').click(function(e) {
		$(this).parents('.result').hide().siblings('.form').show();
		$('#ec-tabs-flight .form #FlightFrom').val(0);
		$('#ec-tabs-flight .form #FlightFromSearch').val('');
		$('#ec-tabs-car .form #CarDistance').val('');
		e.preventDefault();
	});
	
	// Pluralize the "tree" if needed
	$('#ec-tabs form').submit(pluralize);
	
	// Redirect to online payment page with default payment set
	$('#ec-tabs .buyNow').click(function(e) {
		var trees = $(this).parents('.tabs-container').find('.trees').html();
		document.location = $('#EmissionsWidget .meta .nelsonPaymentPage').html()+'?o=Carbon&t='+trees+'&a='+(trees * treeToPrice);
	});
	
	// The calculator is hidden by default for non-js-enabled browsers.
	$('#EmissionsWidget').show();
});

/**
 * Convert from degrees to radians
 */
if (typeof(Number.prototype.toRad) === "undefined") {
  Number.prototype.toRad = function() {
    return this * Math.PI / 180;
  }
}

/**
 * Formatting helper
 */
if (typeof(Number.prototype.format) === "undefined") {
	Number.prototype.format = function(format) {
	  if ( typeof(format)!='string' ) {return;} // sanity check
 
	  var hasComma = -1 < format.indexOf(','),
	    psplit = format.split('.'),
	    that = this;
 
	  // compute precision
	  if (1 < psplit.length) {
	    // fix number precision
	    that = that.toFixed(psplit[1].length);
	  }
	  // error: too many periods
	  else if (2 < psplit.length) {
	    throw('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
	  }
	  // remove precision
	  else {
	    that = that.toFixed(0);
	  } 
 
	  // get the string now that precision is correct
	  var fnum = that.toString();
 
	  // format has comma, then compute commas
	  if (hasComma) {
	    // remove precision for computation
	    psplit = fnum.split('.');
 
	    var cnum = psplit[0],
	      parr = [],
	      j = cnum.length,
	      m = Math.floor(j / 3),
	      n = cnum.length % 3 || 3; // n cannot be ZERO or causes infinite loop
 
	    // break the number into chunks of 3 digits; first chunk may be less than 3
	    for (var i = 0; i < j; i += n) {
	      if (i != 0) {n = 3;}
	      parr[parr.length] = cnum.substr(i, n);
	      m -= 1;
	    }
 
	    // put chunks back together, separated by comma
	    fnum = parr.join(',');
 
	    // add the precision back in
	    if (psplit[1]) {fnum += '.' + psplit[1];}
	  } 
 
	  // replace the number portion of the format with fnum
	  return format.replace(/[\d,?\.?]+/, fnum);
	};
}