Up to now the names of the countries were taken from the LocatorConfig.xml file no matter what has been configured in the name-tag-list option. But the name-tag-list option was used to get the country names from the precompiled bounds which causes a problem if country name in the special language is not contained in the LocatorConfig.xml.

The patch now uses the name-tag-list consistently for all places where country names are standardized.

Additionally the values in the LocatorConfig.xml are automatically completed by all name tags of the precompiled boundaries.

http://files.mkgmap.org.uk/detail/37 links to r2047 including this patch.

WanMil
Index: src/uk/me/parabola/mkgmap/reader/osm/LocationHook.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/LocationHook.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/reader/osm/LocationHook.java	(working copy)
@@ -15,7 +15,6 @@
 import java.io.File;
 import java.io.FileFilter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -34,6 +33,7 @@
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.build.Locator;
+import uk.me.parabola.mkgmap.build.LocatorUtil;
 import uk.me.parabola.mkgmap.reader.osm.boundary.Boundary;
 import uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryUtil;
 import uk.me.parabola.util.ElementQuadTree;
@@ -45,13 +45,11 @@
 
 	private ElementSaver saver;
 	private final List<String> nameTags = new ArrayList<String>();
-	private final Locator locator = new Locator();
+	private Locator locator;
 	private final Set<String> autofillOptions = new HashSet<String>();
 	
 	private File boundaryDir;
 
-	private static final Pattern COMMA_OR_SPACE_PATTERN = Pattern
-			.compile("[,\\s]+");
 	private static final Pattern COMMA_OR_SEMICOLON_PATTERN = Pattern
 			.compile("[,;]+");
 	
@@ -80,17 +78,18 @@
 			return false;
 		}
 
+		this.locator = new Locator(props);
+		
 		this.saver = saver;
 
-		autofillOptions.addAll(Locator.parseAutofillOption(props.getProperty("location-autofill", "bounds")));
+		autofillOptions.addAll(LocatorUtil.parseAutofillOption(props));
 
 		if (autofillOptions.isEmpty()) {
 			log.info("Disable LocationHook because no location-autofill option set.");
 			return false;
 		}
 		
-		String nameTagProp = props.getProperty("name-tag-list", "name");
-		nameTags.addAll(Arrays.asList(COMMA_OR_SPACE_PATTERN.split(nameTagProp)));
+		nameTags.addAll(LocatorUtil.getNameTags(props));
 
 		if (autofillOptions.contains(BOUNDS_OPTION)) {
 
@@ -165,15 +164,11 @@
 			}
 
 			if ("2".equals(b.getTags().get("admin_level"))) {
-				log.info("Input country: " + name);
-				String lowercaseName = name;
-				name = locator.fixCountryString(name);
-				log.info("Fixed country: " + name);
-				String cCode = locator.getCountryCode(name);
-				if (cCode != null) {
-					name = cCode;
+				String isoCode = locator.addCountry(b.getTags());
+				if (isoCode != null) {
+					name = isoCode;
 				} else {
-					log.error("Country name "+lowercaseName+" not in locator config. Country may not be assigned correctly.");
+					log.error("Country name "+name+" not in locator config. Country may not be assigned correctly.");
 				}
 				log.info("Coded: " + name);
 			}
@@ -400,7 +395,30 @@
 	}
 
 
+	/** 
+	 * These tags are used to retrieve the name of admin_level=2 boundaries. They need to
+	 * be handled special because their name is changed to the 3 letter ISO code using
+	 * the Locator class and the LocatorConfig.xml file. 
+	 */
+	private static final String[] LEVEL2_NAMES = new String[]{"name","name:en","int_name"};
+	
 	private String getName(Tags tags) {
+		if ("2".equals(tags.get("admin_level"))) {
+			for (String enNameTag : LEVEL2_NAMES)
+			{
+				String nameTagValue = tags.get(enNameTag);
+				if (nameTagValue == null) {
+					continue;
+				}
+
+				String[] nameParts = COMMA_OR_SEMICOLON_PATTERN.split(nameTagValue);
+				if (nameParts.length == 0) {
+					continue;
+				}
+				return nameParts[0].trim().intern();
+			}
+		}
+		
 		for (String nameTag : nameTags) {
 			String nameTagValue = tags.get(nameTag);
 			if (nameTagValue == null) {
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/MapBuilder.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/build/MapBuilder.java	(working copy)
@@ -100,7 +100,7 @@
 
 	private boolean doRoads;
 
-	private final Locator locator = new Locator();
+	private Locator locator;
 
 	private final java.util.Map<String, Highway> highways = new HashMap<String, Highway>();
 
@@ -128,10 +128,11 @@
 
 	public MapBuilder() {
 		regionName = null;
+		locator = new Locator();
 	}
 
 	public void config(EnhancedProperties props) {
-
+		
 		countryName = props.getProperty("country-name", countryName);
 		countryAbbr = props.getProperty("country-abbr", countryAbbr);
 		regionName = props.getProperty("region-name", null);
@@ -153,7 +154,7 @@
 
 		routeCenterBoundaryType = props.getProperty("route-center-boundary", 0);
 		
-		locator.setLocationAutofill(Locator.parseAutofillOption(props.getProperty("location-autofill", "bounds")));
+		locator = new Locator(props);
 	}
 
 	/**
@@ -255,12 +256,12 @@
 
 				String countryStr = p.getCountry();
 				if (countryStr != null) {
-					countryStr = locator.fixCountryString(countryStr);
+					countryStr = locator.normalizeCountry(countryStr);
 					p.setCountry(countryStr);
 				}
 
 				if(countryStr != null) {
-					thisCountry = lbl.createCountry(countryStr, locator.getCountryCode(countryStr));
+					thisCountry = lbl.createCountry(countryStr, locator.getCountryISOCode(countryStr));
 				} else
 					thisCountry = getDefaultCountry();
 
@@ -293,7 +294,7 @@
 				String cityName = line.getCity();
 				String cityCountryName = line.getCountry();
 				if (cityCountryName != null) {
-					cityCountryName = locator.fixCountryString(cityCountryName);
+					cityCountryName = locator.normalizeCountry(cityCountryName);
 					line.setCountry(cityCountryName);
 				}
 				String cityRegionName  = line.getRegion();
@@ -319,7 +320,7 @@
 
 				if(cityName != null) {
 
-					Country cc = (cityCountryName == null)? getDefaultCountry() : lbl.createCountry(cityCountryName, locator.getCountryCode(cityCountryName));
+					Country cc = (cityCountryName == null)? getDefaultCountry() : lbl.createCountry(cityCountryName, locator.getCountryISOCode(cityCountryName));
 
 					Region cr = (cityRegionName == null)? getDefaultRegion() : lbl.createRegion(cc, cityRegionName, null);
 
@@ -362,7 +363,7 @@
 				String cityStr    = p.getCity();
 
 				if(countryStr != null)
-					countryStr = locator.fixCountryString(countryStr);
+					countryStr = locator.normalizeCountry(countryStr);
 
 				if(countryStr == null || regionStr == null || (zipStr == null && cityStr == null))
 				{
@@ -415,7 +416,7 @@
 					Country thisCountry;
 
 					if(countryStr != null)
-						thisCountry = lbl.createCountry(countryStr, locator.getCountryCode(countryStr));
+						thisCountry = lbl.createCountry(countryStr, locator.getCountryISOCode(countryStr));
 					else
 						thisCountry = getDefaultCountry();
 
Index: src/uk/me/parabola/mkgmap/build/Locator.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/Locator.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/build/Locator.java	(working copy)
@@ -1,68 +1,28 @@
 /*
- * Copyright (C) 2009 Bernhard Heibler
- * 
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- * 
- *  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.
- * 
- *  The Locator tries to fill missing country, region, postal code information
- *
- *	The algorithm works like this:
+ * Copyright (C) 2006, 2011.
  *
- *	1. Step: Go through all cities an check if they have useful country region info
- *	The best case is if the tags is_in:country and is_in:county are present that's easy.
- *	Some cities have is_in information that can be used. We check for three different 
- *	formats:
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
  *
- *	County, State, Country, Continent
- *	County, State, Country
- *	Continent, Country, State, County, ...
- *
- *	In "openGeoDb countries" this info is pretty reliable since it was imported from a 
- *	external db into osm. Other countries have very sparse is_in info.
- *
- *	All this cities that have such info will end up in "city" list. All which lack 
- *	such information in "location" list.
- *
- * 	2. Step: Go through the "location" list and check if the is_in info has some relations 
- *	to the cities we have info about.
- *
- *	Especially hamlets often have no full is_in information. They only have one entry in 
- *	is_in that points to the city they belong to. I will check if I can find the name 
- *	of this city in the "City" list. If there are more with the same name I use the 
- *	closest one. If we can't find the exact name I use fuzzy name search. That's a
- *	workaround for german umlaut since sometimes there are used in the tags and
- *	sometimes there are written as ue ae oe. 
- *
- *	3. Step: Do the same like in step 2 once again. This is used to support at least
- *	one level of recursion in is_in relations.
- *
- *  If there is still no info found I use brute force and use the information from the
- *	next city. Has to be used for countries with poor is_in tagging.
- *
- * Author: Bernhard Heibler
- * Create date: 02-Jan-2009
+ * 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.
  */
-
 package uk.me.parabola.mkgmap.build;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.general.MapPoint;
 import uk.me.parabola.mkgmap.general.MapPointFastFindMap;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.util.EnhancedProperties;
 
 public class Locator {
 	private static final Logger log = Logger.getLogger(Locator.class);
@@ -70,53 +30,23 @@
 	private final MapPointFastFindMap cityMap  					= new MapPointFastFindMap();
 	private final List<MapPoint> placesMap  =  new ArrayList<MapPoint>();
 
+	/** Contains the tags defined by the option name-tag-list */
+	private final List<String> nameTags;
+
 	private final LocatorConfig locConfig = LocatorConfig.get();
 
-	private final Set<String> locationAutofill = new HashSet<String>();
+	private final Set<String> locationAutofill;
 	
 	private static final double MAX_CITY_DIST = 30000;
 
-	private static final Pattern COMMA_OR_SPACE_PATTERN = Pattern.compile("[,\\s]+");
-	
-	/**
-	 * Parses the parameters of the location-autofill option. Establishes also downwards
-	 * compatibility with the old integer values of location-autofill. 
-	 * @param optionStr the value of location-autofill
-	 * @return the options
-	 */
-	public static Set<String> parseAutofillOption(String optionStr) {
-		if (optionStr == null) {
-			return Collections.emptySet();
-		}
-
-		Set<String> autofillOptions = new HashSet<String>(Arrays.asList(COMMA_OR_SPACE_PATTERN
-				.split(optionStr)));
-
-		// convert the old autofill options to the new parameters
-		if (autofillOptions.contains("0")) {
-			autofillOptions.add("is_in");
-			autofillOptions.remove("0");
-		}
-		if (autofillOptions.contains("1")) {
-			autofillOptions.add("is_in");
-			// PENDING: fuzzy search
-			autofillOptions.remove("1");
-		}
-		if (autofillOptions.contains("2")) {
-			autofillOptions.add("is_in");
-			// PENDING: fuzzy search
-			autofillOptions.add("nearest");
-			autofillOptions.remove("2");
-		}		
-		if (autofillOptions.contains("3")) {
-			autofillOptions.add("is_in");
-			// PENDING: fuzzy search
-			autofillOptions.add("nearest");
-			autofillOptions.remove("3");
-		}	
-		return autofillOptions;
+	public Locator() {
+		this(new EnhancedProperties());
 	}
 	
+	public Locator(EnhancedProperties props) {
+		this.nameTags = LocatorUtil.getNameTags(props);
+		this.locationAutofill = new HashSet<String>(LocatorUtil.parseAutofillOption(props));
+	}
 	
 	public void addCityOrPlace(MapPoint p) 
 	{
@@ -131,7 +61,7 @@
 		// correct the country name
 		// usually this is the translation from 3letter ISO code to country name
 		if(p.getCountry() != null)
-			p.setCountry(fixCountryString(p.getCountry()));
+			p.setCountry(normalizeCountry(p.getCountry()));
 
 		resolveIsInInfo(p); // Pre-process the is_in field
 
@@ -150,34 +80,51 @@
 		log.debug("E City 0x"+Integer.toHexString(p.getType()), p.getName(), "|", p.getCity(), "|", p.getRegion(), "|", p.getCountry());
 	}
 
-			
-	public void setLocationAutofill(Collection<String> autofillOptions) {
-		this.locationAutofill.addAll(autofillOptions);
-	}
-
 	public void setDefaultCountry(String country, String abbr)
 	{
 		locConfig.setDefaultCountry(country, abbr);
 	}
-
-	public String fixCountryString(String country)
+	
+	public String normalizeCountry(String country)
 	{
-		return locConfig.fixCountryString(country);
+		if (country == null) {
+			return null;
+		}
+		
+		String iso = locConfig.getCountryISOCode(country);
+		if (iso != null) {
+			String normedCountryName = locConfig.getCountryName(iso, nameTags);
+			if (normedCountryName != null) {
+				return normedCountryName;
+			}
+		}
+		
+		// cannot find the country in our config => return the country itself
+		return country;
 	}
 
-	private String isCountry(String country)
+	/**
+	 * Checks if the country given by attached tags is already known, adds or completes
+	 * the Locator information about this country and return the three letter ISO code
+	 * (in case the country is known in the LocatorConfig.xml) or the country name.
+	 * 
+	 * @param tags the countries tags
+	 * @return the three letter ISO code or <code>null</code> if ISO code is unknown
+	 */
+	public String addCountry(Tags tags)
 	{
-		return locConfig.isCountry(country);
+		return locConfig.addCountryWithTags(tags);
 	}
+	
 
-	public String getCountryCode(String country)
+	public String getCountryISOCode(String country)
 	{
-		return locConfig.getCountryCode(country);
+		return locConfig.getCountryISOCode(country);
 	}
 
 	public int getPOIDispFlag(String country)
 	{
-		return locConfig.getPoiDispFlag(country);
+		return locConfig.getPoiDispFlag(getCountryISOCode(country));
 	}
 
 	private boolean isContinent(String continent)
@@ -216,11 +163,11 @@
 			{
 				if (p.getCountry() == null) {
 					// The one before continent should be the country
-					p.setCountry(fixCountryString(cityList[cityList.length-2].trim()));
+					p.setCountry(normalizeCountry(cityList[cityList.length-2].trim()));
 				}
 				
 				// aks the config which info to use for region info				
-				int offset = locConfig.getRegionOffset(p.getCountry()) + 1;
+				int offset = locConfig.getRegionOffset(getCountryISOCode(p.getCountry())) + 1;
 
 				if(cityList.length > offset && p.getRegion() == null)
 					p.setRegion(cityList[cityList.length-(offset+1)].trim());
@@ -233,10 +180,10 @@
 			{
 				if (p.getCountry() == null) {
 					// The one before continent should be the country
-					p.setCountry(fixCountryString(cityList[1].trim()));
+					p.setCountry(normalizeCountry(cityList[1].trim()));
 				}
 				
-				int offset = locConfig.getRegionOffset(p.getCountry()) + 1;
+				int offset = locConfig.getRegionOffset(getCountryISOCode(p.getCountry())) + 1;
 
 				if(cityList.length > offset && p.getRegion() == null)
 					p.setRegion(cityList[offset].trim());
@@ -247,14 +194,12 @@
 			if(p.getCountry() == null && cityList.length > 0)
 			{
 				// I don't like to check for a list of countries but I don't want other stuff in country field
-
-				String countryStr = isCountry(cityList[cityList.length-1]);
-
-				if(countryStr != null)
+				String isoCode = locConfig.getCountryISOCode(cityList[cityList.length-1]);
+				if (isoCode != null)
 				{	
-					p.setCountry(countryStr);
+					p.setCountry(normalizeCountry(isoCode));
 
-					int offset = locConfig.getRegionOffset(countryStr) + 1;
+					int offset = locConfig.getRegionOffset(isoCode) + 1;
 
 					if(cityList.length > offset && p.getRegion() == null)
 						p.setRegion(cityList[cityList.length-(offset+1)].trim());	
Index: src/uk/me/parabola/mkgmap/build/LocatorConfig.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/LocatorConfig.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/build/LocatorConfig.java	(working copy)
@@ -1,45 +1,49 @@
 /*
- * Copyright (C) 2009 Bernhard Heibler
- * 
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- * 
- *  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.
- * 
- *  The Locator tries to fill missing country, region, postal code information
+ * Copyright (C) 2006, 2011.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
  *
- *  To do so we analyse the is_in information and if this doesn't helps us we
- *  try to get info from the next known city
- * 
- * Author: Bernhard Heibler
- * Create date: 02-Jan-2009
+ * 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.
  */
 package uk.me.parabola.mkgmap.build;
 
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 
 public class LocatorConfig {
+	private static final Logger log = Logger.getLogger(LocatorConfig.class);
 
-	private final Map<String,String>  variantMap = new HashMap<String,String>();
-	private final Map<String,String>  abrMap = new HashMap<String,String>();
+	private final Map<String,String>  isoMap = new HashMap<String,String>();
 	private final Map<String,Integer>  regOffsetMap = new HashMap<String,Integer>();
 	private final Map<String,Integer>  poiDispFlagMap = new HashMap<String,Integer>();
 	private final Map<String,Boolean> continentMap = new HashMap<String,Boolean>();
 
+	/** maps ISO => default country name */
+	private final Map<String, String> defaultCountryNames = new HashMap<String, String>();
+	
+	/** Maps 3 letter ISO code to all tags of a country */
+	private final Map<String, Tags> countryTagMap = new HashMap<String, Tags>();
+	
 	private final static LocatorConfig instance = new LocatorConfig();
 	
 	public static LocatorConfig get() {
@@ -98,46 +102,59 @@
 						{
 							NamedNodeMap attr = cNode.getAttributes();
 							Node nameTag = null;
-
+							Node abrTag = attr.getNamedItem("abr");
+							String iso = null;
+							if (abrTag != null) {
+								iso = abrTag.getNodeValue().toUpperCase().trim().intern();
+								if (iso.length() != 3) {
+									log.error("ISO code (abr) must have three characters: "+iso);
+								}
+							}
+							
 							if(attr != null)
 							{
 								nameTag = attr.getNamedItem("name");
 								
-								Node abrTag = attr.getNamedItem("abr");
-
-								if(abrTag != null && nameTag != null)
-									addAbr(nameTag.getNodeValue(),abrTag.getNodeValue());
+								if(iso != null && nameTag != null) {
+									addISO(nameTag.getNodeValue(),iso);
+									defaultCountryNames.put(iso, nameTag.getNodeValue().trim());
+								}
+								
+								if (iso != null)
+									addISO(iso, iso);
 								
-								if(abrTag == null && nameTag != null)					
-									addAbr(nameTag.getNodeValue(),"");
+								if(iso == null && nameTag != null)					
+									addISO(nameTag.getNodeValue(),"");
 
+								
 								Node regionOffsetTag = attr.getNamedItem("regionOffset");
 
-								if(regionOffsetTag != null && nameTag != null)
+								if(regionOffsetTag != null && iso != null)
 								{
-									addRegionOffset(nameTag.getNodeValue(),Integer.parseInt(regionOffsetTag.getNodeValue()));
+									addRegionOffset(iso,Integer.parseInt(regionOffsetTag.getNodeValue()));
 								}
 
 								Node poiDispTag = attr.getNamedItem("poiDispFlag");
 
-								if(poiDispTag != null && nameTag != null)
+								if(poiDispTag != null && iso != null)
 								{
-									addPoiDispTag(nameTag.getNodeValue(),Integer.decode(poiDispTag.getNodeValue()));
+									addPoiDispTag(iso,Integer.decode(poiDispTag.getNodeValue()));
 								}
 							}
 
-							Node cEntryNode = cNode.getFirstChild();
-							while(cEntryNode != null)
-							{
-								if(cEntryNode.getNodeName().equals("variant"))
+							if (iso != null) {
+								Node cEntryNode = cNode.getFirstChild();
+								while(cEntryNode != null)
 								{
-									Node nodeText = cEntryNode.getFirstChild();
-
-									if(nodeText != null && nameTag != null)
-										addVariant(nameTag.getNodeValue(), nodeText.getNodeValue());
-										
+									if(cEntryNode.getNodeName().equals("variant"))
+									{
+										Node nodeText = cEntryNode.getFirstChild();
+									
+										if (nodeText != null)
+											addISO(nodeText.getNodeValue(), iso);
+									}
+									cEntryNode = cEntryNode.getNextSibling();
 								}
-								cEntryNode = cEntryNode.getNextSibling();
 							}
 						}
 
@@ -156,34 +173,21 @@
 		}
   	}
 
-	private void addVariant(String country, String variant)
-	{
-		String cStr = country.toUpperCase().trim();
-		String vStr = variant.toUpperCase().trim();
-
-		variantMap.put(vStr,cStr);
-	}
-
-	private void addAbr(String country, String abr)
+	private void addISO(String country, String iso)
 	{
 		String cStr = country.toUpperCase().trim();
-		String aStr = abr.toUpperCase().trim();
 
-		abrMap.put(cStr,aStr);
+		isoMap.put(cStr,iso);
 	}
 
-	private void addRegionOffset(String country, Integer offset)
+	private void addRegionOffset(String iso, Integer offset)
 	{
-		String cStr = country.toUpperCase().trim();
-
-		regOffsetMap.put(cStr,offset);
+		regOffsetMap.put(iso,offset);
 	}
 
-	private void addPoiDispTag(String country, Integer flag)
+	private void addPoiDispTag(String iso, Integer flag)
 	{
-		String cStr = country.toUpperCase().trim();
-
-		poiDispFlagMap.put(cStr,flag);
+		poiDispFlagMap.put(iso,flag);
 	}
 
 	private void addContinent(String continent)
@@ -196,43 +200,119 @@
 
 	public synchronized void setDefaultCountry(String country, String abbr)
 	{
-		addAbr(country, abbr);
+		addISO(country, abbr);
 	}
 
-	public synchronized String fixCountryString(String country)
+	public synchronized boolean isCountry(String country)
 	{
-		String cStr = country.toUpperCase().trim();
+		return isoMap.containsKey(country.toUpperCase().trim());
+	}
+	
+	private final static String[] PREFERRED_NAME_TAGS = {"name","name:en","int_name"};
+	
+	public synchronized String addCountryWithTags(Tags countryTags) {
+		String isoCode = null;
+		for (String nameTag : PREFERRED_NAME_TAGS) {
+			String nameValue = countryTags.get(nameTag);
+			isoCode = getCountryISOCode(nameValue);
+			if (isoCode != null) {
+				break;
+			}
+		}
 		
-		String fixedString = variantMap.get(cStr);
-
-		if(fixedString != null)
-			return fixedString;
-		else
-			return(cStr);
+		if (isoCode == null) {
+			for (String countryStr : countryTags.getTagsWithPrefix("name:", false).values()) {
+				isoCode = getCountryISOCode(countryStr);
+				if (isoCode != null) {
+					break;
+				}
+			}
+		}
+		
+		if (isoCode == null) {
+			// cannot find three letter iso code for this countries
+			// do not use it
+			log.warn("Cannot find country with tags", countryTags);
+			return null;
+		}
+		
+		if (countryTagMap.containsKey(isoCode)) {
+			// country is already known
+			return isoCode;
+		}
+		
+		// add it as new country to the tag map
+		Tags cTagsCopy = new Tags();
+		Iterator<Entry<String,String>> tagIter = countryTags.entryIterator();
+		while (tagIter.hasNext()) {
+			Entry<String,String> nextTag = tagIter.next();
+			cTagsCopy.put(nextTag.getKey(), nextTag.getValue());
+		}
+		countryTagMap.put(isoCode, cTagsCopy);
+		
+		String name = countryTags.get("name");
+		if (name != null) {
+			addISO(name, isoCode);
+		}
+		String int_name = countryTags.get("int_name");
+		if (int_name != null) {
+			addISO(int_name, isoCode);
+		}
+		// add all variants to the abbreviation map
+		for (String countryName : countryTags.getTagsWithPrefix("name:", false).values()) {
+			addISO(countryName, isoCode);
+		}
+		return isoCode;
 	}
 
-	public synchronized String isCountry(String country)
+	/**
+	 * Retrieves the three letter ISO code which is used by the Garmins.
+	 * @param country a country name 
+	 * @return the three letter ISO code (<code>null</code> = unknown)
+	 */
+	public synchronized String getCountryISOCode(String country)
 	{
-		String cStr = fixCountryString(country);
-
-		if(getCountryCode(cStr) != null)
-			return cStr;
-		else
+		if (country == null) {
 			return null;
-	
+		}
+		return isoMap.get(country.toUpperCase().trim());
 	}
-
-	public synchronized String getCountryCode(String country)
-	{
-		String cStr = country.toUpperCase().trim();
-		return abrMap.get(cStr);
+	
+	/**
+	 * Retrieves the name of a country by its three letter iso code and the list of 
+	 * name tags. The first available value of the tags in the nameTags list is returned.
+	 * 
+	 * @param isoCode the three letter ISO code
+	 * @param nameTags the list of name tags 
+	 * @return the full country name (<code>null</code> if unknown)
+	 */
+	public synchronized String getCountryName(String isoCode, List<String> nameTags) {
+		Tags countryTags = countryTagMap.get(isoCode);
+		if (countryTags==null) {
+			// no tags for this country available
+			// return the default country name from the LocatorConfig.xml
+			return defaultCountryNames.get(isoCode);
+		}
+		
+		// search for the first available tag of the nameTags list
+		for (String nameTag : nameTags) {
+			String name = countryTags.get(nameTag);
+			if (name != null) {
+				return name;
+			}
+		}
+		
+		// last try: just the simple "name" tag
+		return countryTags.get("name");
 	}
 
-	public synchronized int getRegionOffset(String country)
+	public synchronized int getRegionOffset(String iso)
 	{
-		String cStr = country.toUpperCase().trim();
+		if (iso == null) {
+			return 1;
+		}
 		
-		Integer regOffset = regOffsetMap.get(cStr);
+		Integer regOffset = regOffsetMap.get(iso);
 
 		if(regOffset != null)
 			return regOffset;
@@ -240,16 +320,18 @@
 			return 1; // Default is 1 the next string after before country
 	}
 
-	public synchronized int getPoiDispFlag(String country)
+	public synchronized int getPoiDispFlag(String iso)
 	{
-		String cStr = country.toUpperCase().trim();
+		if (iso == null) {
+			return 0;
+		}
 		
-		Integer flag = poiDispFlagMap.get(cStr);
+		Integer flag = poiDispFlagMap.get(iso);
 
 		if(flag != null)
 			return flag;
 		else
-			return 0; // Default is 1 the next string after before country
+			return 0; // Default is 0 
 	}
 
 	public synchronized boolean isContinent(String continent)
Index: src/uk/me/parabola/mkgmap/build/LocatorUtil.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/LocatorUtil.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/build/LocatorUtil.java	(revision 0)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006, 2011.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+package uk.me.parabola.mkgmap.build;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.util.EnhancedProperties;
+
+public class LocatorUtil {
+
+	private static final Pattern COMMA_OR_SPACE_PATTERN = Pattern
+			.compile("[,\\s]+");
+	
+	public static List<String> getNameTags(EnhancedProperties props) {
+		String nameTagProp = props.getProperty("name-tag-list", "name");
+		return Arrays.asList(COMMA_OR_SPACE_PATTERN.split(nameTagProp));
+	}
+
+	/**
+	 * Parses the parameters of the location-autofill option. Establishes also downwards
+	 * compatibility with the old integer values of location-autofill. 
+	 * @param optionStr the value of location-autofill
+	 * @return the options
+	 */
+	public static Set<String> parseAutofillOption(EnhancedProperties props) {
+		String optionStr = props.getProperty("location-autofill", "bounds");
+		if (optionStr == null) {
+			return Collections.emptySet();
+		}
+	
+		Set<String> autofillOptions = new HashSet<String>(Arrays.asList(COMMA_OR_SPACE_PATTERN
+				.split(optionStr)));
+	
+		// convert the old autofill options to the new parameters
+		if (autofillOptions.contains("0")) {
+			autofillOptions.add("is_in");
+			autofillOptions.remove("0");
+		}
+		if (autofillOptions.contains("1")) {
+			autofillOptions.add("is_in");
+			// PENDING: fuzzy search
+			autofillOptions.remove("1");
+		}
+		if (autofillOptions.contains("2")) {
+			autofillOptions.add("is_in");
+			// PENDING: fuzzy search
+			autofillOptions.add("nearest");
+			autofillOptions.remove("2");
+		}		
+		if (autofillOptions.contains("3")) {
+			autofillOptions.add("is_in");
+			// PENDING: fuzzy search
+			autofillOptions.add("nearest");
+			autofillOptions.remove("3");
+		}	
+		return autofillOptions;
+	}
+}
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to