/*
This file is part of RouteConverter.
RouteConverter is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
RouteConverter is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RouteConverter; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 2007 Christian Pesch. All Rights Reserved.
*/
package slash.navigation.converter.gui.helpers;
import slash.navigation.common.NavigationPosition;
import slash.navigation.geocoding.GeocodingService;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import static java.util.Arrays.sort;
import javax.naming.ServiceUnavailableException;
/**
* A geocoding service that tries to find the best available geocoding service.
*
* @author Christian Pesch
*/
public class AutomaticGeocodingService implements GeocodingService {
private static final Logger log = Logger.getLogger(AutomaticGeocodingService.class.getName());
private static final String AUTOMATIC_GEOCODING_SERVICE_NAME = "Automatic";
private final GeocodingServiceFacade geocodingServiceFacade;
public AutomaticGeocodingService(GeocodingServiceFacade geocodingServiceFacade) {
this.geocodingServiceFacade = geocodingServiceFacade;
}
public String getName() {
return AUTOMATIC_GEOCODING_SERVICE_NAME;
}
public boolean isDownload() {
return true;
}
public boolean isOverQueryLimit() {
return false;
}
public List<NavigationPosition> getPositionsFor(String address) throws IOException, ServiceUnavailableException {
IOException lastException = null;
for (GeocodingService service : sortByBestEffort(geocodingServiceFacade.getGeocodingServices())) {
try {
if(service.isOverQueryLimit())
continue;
List<NavigationPosition> positions = service.getPositionsFor(address);
if (positions != null) {
log.info("Used " + service.getName() + " to retrieve positions " + positions + "D for " + address);
return positions;
}
} catch (IOException e) {
lastException = e;
}
}
if(lastException != null)
throw lastException;
else
return null;
}
public String getAddressFor(NavigationPosition position) throws IOException, ServiceUnavailableException {
IOException lastException = null;
for (GeocodingService service : sortByBestEffort(geocodingServiceFacade.getGeocodingServices())) {
try {
String address = service.getAddressFor(position);
if (address != null) {
log.info("Used " + service.getName() + " to retrieve address for " + address);
return address;
}
} catch (IOException e) {
lastException = e;
}
}
if(lastException != null)
throw lastException;
else
return null;
}
private GeocodingService[] sortByBestEffort(List<GeocodingService> geocodingServices) {
List<GeocodingService> toSort = new ArrayList<>(geocodingServices);
toSort.remove(this);
GeocodingService[] result = toSort.toArray(new GeocodingService[toSort.size()]);
sort(result, new GeocodingServicePriorityComparator());
return result;
}
private static class GeocodingServicePriorityComparator implements Comparator<GeocodingService> {
private static final Map<String, Integer> PRIORITY = new HashMap<>();
static {
PRIORITY.put("Google Maps", 1);
PRIORITY.put("Nominatim", 2);
PRIORITY.put("Photon", 3);
PRIORITY.put("GeoNames", 4);
}
private int getPriority(GeocodingService geocodingService) {
Integer priority = PRIORITY.get(geocodingService.getName());
return priority == null ? 10 : priority;
}
public int compare(GeocodingService g1, GeocodingService g2) {
return getPriority(g1) - getPriority(g2);
}
}
}