function geolocate(callbackFn, failureFn) {
  if (navigator.geolocation) {
    setTimeout(function() {
      if($.browser.mozilla && $.browser.version.substr(0,3) == "1.9") {
        $("#location-alert").fadeIn('slow');
      }
    }, 5000);
    navigator.geolocation.getCurrentPosition(function(pos) {
      var lat, lng;
      // For Firefox 3.5 or later, or previous versions with Geode extension
      //   http://labs.mozilla.com/2008/10/introducing-geode/
      //   http://azarask.in/local/
      //   https://developer.mozilla.org/En/Using_geolocation
      if (pos.coords) { // FF 3.5
        lat = pos.coords.latitude;
        lng = pos.coords.longitude;
        // http://dev.w3.org/geo/api/spec-source.html#accuracy
        accuracy = pos.coords.accuracy;
      } else { // Geode plugin
        lat = pos.latitude;
        lng = pos.longitude;
      }
      var geocoder = new google.maps.Geocoder();
      geocoder.geocode({'latLng': new google.maps.LatLng(lat, lng)}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          var loc = results[0];
          var city = getCityNameFromLocation(loc);
          var geoInfo = { latitude: lat, longitude: lng, accuracy: accuracy,
                          address: results[0].formatted_address, city: city };
          callbackFn(geoInfo);
        } else {
          // console.log(I18n.t('geocoder_failed') + status);
          failureFn();
        }
      });
    }, failureFn);
  } else if (window.google && google.gears) {
      var geo = google.gears.factory.create('beta.geolocation');
      geo.getCurrentPosition(function(pos) {
        var geoInfo = {
          latitude: pos.coords.latitude,
          longitude: pos.coords.longitude,
          accuracy: pos.coords.accuracy,
          address: formatGearsAddress(pos.gearsAddress),
          city: pos.gearsAddress.city
        };
        callbackFn(geoInfo);
        // http://www.cherny.com/webdev/60/javascript-function-arguments-default-values-passing-objects-and-overloading
        //send_location_cookie({lat: pos.coords.latitude, lng: pos.coords.longitude, })
      },
      failureFn,
      {'gearsRequestAddress': true});
  } else {
    // Guessing location through IP address
    // http://code.google.com/apis/ajax/documentation/#ClientLocation
    if (google.loader.ClientLocation) {
      var geoInfo = {
        latitude: google.loader.ClientLocation.latitude,
        longitude: google.loader.ClientLocation.longitude,
        accuracy: 100000,
        address: (google.loader.ClientLocation && google.loader.ClientLocation.address) ?
                                google.loader.ClientLocation.address.city : "",
        city: google.loader.ClientLocation.address.city
      };
      callbackFn(geoInfo);
    } else {
      failureFn();
    }
  }
};

function formatGearsAddress(a) {
  // http://en.wikipedia.org/wiki/Address_(geography) -%>
  var formattedAddress;
  if (a.countryCode == 'US') {
    streetAddress = (a.streetNumber || '') + (a.street ? (a.streetNumber ? ' ' : '') + a.street : '');
    formattedAddress = (a.streetNumber ? a.streetNumber + ' ' : '') + a.street + ', ' + a.city + ' ' + a.postalCode;
  }
  else {
    streetAddress = (a.street || '') + (a.streetNumber ? (a.street ? ' ' : '') + a.streetNumber : '');
    formattedAddress = (streetAddress ? streetAddress + ', ' : '') + a.postalCode + ' ' + a.city;
  }
  return formattedAddress;
};

function setLocationCookie(geoInfo) {
  if (!geoInfo || !geoInfo.latitude || !geoInfo.longitude) {
    // set a default location
    var geoInfo = {
      latitude: 41.3879170,
      longitude: 2.1699187,
      address: "Barcelona, Spain"
    }
  }

  var locVal = [
    geoInfo.latitude || '',
    geoInfo.longitude || '',
    geoInfo.accuracy || '',
    geoInfo.address || '',
    '', // geoname_city
    '', // geoname_id
    geoInfo.city || ''
  ].join("|");
  var date = new Date();
  date.setTime(date.getTime() + LOCATION_COOKIE_LIFETIME_IN_MINUTES*60*1000);
  setTimeout(function() {
    $.cookie('location', locVal, { expires: date.toUTCString(), path: '/', domain: window.location.hostname.replace(/^m\./i, "") })
  }, 0);
};

function precisionIsCityLevelOrBetter(location, index) {
  if (location.address_components[0].types.length == 0) { // This is the case for landmarks e.g. 'Yankee Stadium'
    return true;
  } else if (location.address_components[0].types[0] == 'transit_station') { // Metro stations and the like
    return true;
  } else {
    for (var j = location.address_components.length - 1; j >= 0; j--) { // 'Real' cities
      var component = location.address_components[j];
      if (component.types[0] == 'locality') { // Closest approximation to an identifier for a city
        return true;
      }
    }
  }
  return false;
};

function getCityNameFromLocation(location) {
  for (var i = 0; i < location.address_components.length; i++) {
    var component = location.address_components[i];
    if (component.types[0] == 'locality') {
      return component.long_name;
    }
  }
  return '';
};
