/* * Copyright 2013, L. Murer. * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see < http://www.gnu.org/licenses/ >. */ package models; import de.schildbach.pte.NetworkProvider; import de.schildbach.pte.dto.Location; import play.Logger; import java.io.IOException; import java.util.*; import java.util.regex.Pattern; /** * Created by IntelliJ IDEA. * User: Laurin * Date: 08.11.11 * Time: 07:52 */ public class Autocomplete { //How many items should be returned for an autocomplete request private final static int AUTOCOMPLETE_MAX = 5; //Cached data for an autocomplete request (Key of first map: Providers ID; Key of second map: Term to autocomplete private static final Map<String, Map<String, List<String>>> autocompleteCache = new HashMap<>(); //With which items in the popular location database the result for this cached autocomplete list was generated (Keys are the same as in autocompleteCache) private static final Map<String, Map<String, String>> autocompleteCacheLevel = new HashMap<>(); /** * Autocompletes a station * * @param provider ID of the provider * @param term to autocomplete * @return a list of stations */ public static List<String> stations(@SuppressWarnings("SameParameterValue") final String provider, final String term) { if (term == null) return new ArrayList<>(0); //get the autocomplete list for the given provider from the cache Map<String, List<String>> providers_autocomplete = autocompleteCache.get(provider); Map<String, String> providers_autocomplete_level = autocompleteCacheLevel.get(provider); //create a list if none exists if (providers_autocomplete == null || providers_autocomplete_level == null) { if (KnownProvider.get(provider) == null) { Logger.error("Autocompleteanfrage konnte für Provider '" + provider + "' nicht durchgeführt werden. Grund: Unbekannter Provider."); return new ArrayList<>(0); } providers_autocomplete = new HashMap<>(); providers_autocomplete_level = new HashMap<>(); autocompleteCache.put(provider, providers_autocomplete); autocompleteCacheLevel.put(provider, providers_autocomplete_level); } List<String> mostPopular = PopularLocation.getMostPopularLike(provider, term, AUTOCOMPLETE_MAX); //get the station list for the term from the cache List<String> autocomplete_list = null; if (providers_autocomplete_level.get(term) != null && providers_autocomplete_level.get(term).equals(join(mostPopular))) { autocomplete_list = providers_autocomplete.get(term); } //create the station list, if none exists if (autocomplete_list == null) { //get the provider object final NetworkProvider p = KnownProvider.get(provider); autocomplete_list = new ArrayList<>(AUTOCOMPLETE_MAX); autocomplete_list.addAll(mostPopular); if (autocomplete_list.size() < AUTOCOMPLETE_MAX) { try { //get the list of the requested stations from the provider List<Location> locations = p.autocompleteStations(term); String simplifiedTerm = simplify(term); boolean firstSuggestion = true; for (Location location : locations) { if (!autocomplete_list.contains(location.name)) { if (firstSuggestion || simplify(location.name).contains(simplifiedTerm)) { autocomplete_list.add(location.name); if (autocomplete_list.size() == AUTOCOMPLETE_MAX) { break; } } firstSuggestion = false; } } providers_autocomplete.put(term, autocomplete_list); providers_autocomplete_level.put(term, join(mostPopular)); } catch (IOException e) { Logger.error("Konnte vom Provider " + p.toString() + " keine Autovervollständigung von Station (" + term + ") abfragen.", e); } } else { providers_autocomplete_level.put(term, join(mostPopular)); } } return autocomplete_list; } /** * Simplifies a string heavily (removes everything that's not a normal letter and returns it in lowercase) * * @param string to simplify * @return simplified version of the string */ public static String simplify(String string) { return Pattern.compile("[^a-z]").matcher(string.toLowerCase()).replaceAll(""); } /** * Joins a string by ";" * * @param items some Strings to be put together * @return A string containing all inputstrings connected with a ";" */ private static String join(Collection<String> items) { if (items.isEmpty()) { return ""; } final String joinBy = ";"; StringBuilder sb = new StringBuilder(); for (String item : items) { sb.append(joinBy); sb.append(item); } return sb.substring(joinBy.length()); } }