/*
* 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.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import uk.me.parabola.imgfmt.app.trergn.TREHeader;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.osmstyle.NameFinder;
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);
/** maps country name (in all variants) to the 3 letter ISO code */
private final Map<String,
String> isoMap =
new HashMap<>();
/** maps the ISO code to the offset of the region in the is_in tag */
private final Map<String,
Integer> regOffsetMap =
new HashMap<>();
/** maps the ISO code to the POI display flag */
private final Map<String,
Integer> poiDispFlagMap =
new HashMap<>();
/** maps the ISO code to the drive-on-left flag */
private final Map<String,
Boolean> driveOnLeftFlagMap =
new HashMap<>();
/** contains the names of all continents */
private final Set<String> continents =
new HashSet<>();
/** maps ISO => default country name */
private final Map<String,
String> defaultCountryNames =
new HashMap<>();
/** Maps 3 letter ISO code to all tags of a country */
private final Map<String, Tags
> countryTagMap =
new HashMap<>();
private static final LocatorConfig instance =
new LocatorConfig
();
public static LocatorConfig get
() {
return instance
;
}
private LocatorConfig
()
{
loadConfig
("/LocatorConfig.xml");
}
private void loadConfig
(String fileName
)
{
try
{
DocumentBuilder builder =
DocumentBuilderFactory.
newInstance().
newDocumentBuilder();
InputStream inStream
;
try
{
inStream =
new FileInputStream("resources/" + fileName
);
}
catch (Exception ex
)
{
inStream =
null;
}
if(inStream ==
null) // If not loaded from disk use from jar file
inStream =
this.
getClass().
getResourceAsStream(fileName
);
Document document = builder.
parse(inStream
);
Node rootNode = document.
getDocumentElement();
if("locator".
equals(rootNode.
getNodeName()))
{
Node cNode = rootNode.
getFirstChild();
while(cNode
!=
null)
{
if("continent".
equals(cNode.
getNodeName()))
{
NamedNodeMap attr = cNode.
getAttributes();
if(attr
!=
null)
{
Node nameTag = attr.
getNamedItem("name");
if(nameTag
!=
null)
addContinent
(nameTag.
getNodeValue());
}
}
if ("country".
equals(cNode.
getNodeName())) {
NamedNodeMap attr = cNode.
getAttributes();
String iso =
null;
if (attr
!=
null) {
Node nameTag =
null;
Node abrTag = attr.
getNamedItem("abr");
if (abrTag
!=
null) {
iso = abrTag.
getNodeValue().
toUpperCase().
trim().
intern();
if (iso.
length() !=
3) {
log.
error("ISO code (abr) must have three characters: "
+ iso
);
}
}
nameTag = attr.
getNamedItem("name");
if (iso
!=
null && nameTag
!=
null) {
addISO
(nameTag.
getNodeValue(), iso
);
defaultCountryNames.
put(iso, nameTag
.
getNodeValue().
trim());
}
if (iso
!=
null)
addISO
(iso, iso
);
if(iso ==
null && nameTag
!=
null)
addISO
(nameTag.
getNodeValue(),
"");
Node regionOffsetTag = attr.
getNamedItem("regionOffset");
if(regionOffsetTag
!=
null && iso
!=
null)
{
addRegionOffset
(iso,
Integer.
parseInt(regionOffsetTag.
getNodeValue()));
}
int poiDispTag = 0x0
;
Node streetBeforeHousenumber = attr.
getNamedItem("streetBeforeHousenumber");
if (streetBeforeHousenumber
!=
null && "true".
equals(streetBeforeHousenumber.
getNodeValue())) {
poiDispTag |= TREHeader.
POI_FLAG_STREET_BEFORE_HOUSENUMBER;
}
Node postalcodeBeforeCity = attr.
getNamedItem("postalcodeBeforeCity");
if (postalcodeBeforeCity
!=
null && "true".
equals(postalcodeBeforeCity.
getNodeValue())) {
poiDispTag |= TREHeader.
POI_FLAG_POSTALCODE_BEFORE_CITY;
}
if (poiDispTag
!= 0x0
&& iso
!=
null) {
setPoiDispTag
(iso, poiDispTag
);
}
Node driveOnLeft = attr.
getNamedItem("driveOnLeft");
driveOnLeftFlagMap.
put(iso, driveOnLeft
!=
null && "true".
equals(driveOnLeft.
getNodeValue()));
}
if (iso
!=
null) {
Node cEntryNode = cNode.
getFirstChild();
while(cEntryNode
!=
null)
{
if("variant".
equals(cEntryNode.
getNodeName()))
{
Node nodeText = cEntryNode.
getFirstChild();
if (nodeText
!=
null)
addISO
(nodeText.
getNodeValue(), iso
);
}
cEntryNode = cEntryNode.
getNextSibling();
}
}
}
cNode = cNode.
getNextSibling();
}
}
else
{
log.
error(fileName +
"contains invalid root tag " + rootNode.
getNodeName());
}
}
catch (Exception ex
)
{
Logger.
defaultLogger.
error("Unexpected error reading " + fileName, ex
);
}
}
private void addISO
(String country,
String iso
)
{
String cStr = country.
toUpperCase().
trim();
isoMap.
put(cStr,iso
);
}
private void addRegionOffset
(String iso,
Integer offset
)
{
regOffsetMap.
put(iso,offset
);
}
private void setPoiDispTag
(String iso,
int flag
)
{
// only two flags are allowed to be configured
poiDispFlagMap.
put(iso, flag
& (TREHeader.
POI_FLAG_STREET_BEFORE_HOUSENUMBER | TREHeader.
POI_FLAG_POSTALCODE_BEFORE_CITY));
}
private void addContinent
(String continent
)
{
String cStr = continent.
toUpperCase().
trim();
continents.
add(cStr
);
}
public synchronized void setDefaultCountry
(String country,
String abbr
)
{
addISO
(country, abbr
);
}
public synchronized boolean isCountry
(String country
)
{
return isoMap.
containsKey(country.
toUpperCase().
trim());
}
public synchronized boolean countryHasTags
(String isoCode
) {
return countryTagMap.
containsKey(isoCode
);
}
public synchronized String addCountryWithTags
(String isoCode, Tags countryTags
) {
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 (countryHasTags
(isoCode
)) {
// country is already known
return isoCode
;
}
// add it as new country to the tag map
countryTagMap.
put(isoCode, countryTags.
copy());
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
;
}
/**
* 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
)
{
if (country ==
null) {
return null;
}
String res = isoMap.
get(country
);
if (res ==
null){
res = isoMap.
get(country.
toUpperCase().
trim());
if (res
!=
null) {
isoMap.
put(country, res
);
}
}
return res
;
}
/**
* 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 nameFinder the list of name tags
* @return the full country name (<code>null</code> if unknown)
*/
public synchronized String getCountryName
(String isoCode, NameFinder nameFinder
) {
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
);
}
return nameFinder.
getName(countryTags
);
}
public synchronized int getRegionOffset
(String iso
)
{
if (iso ==
null) {
return 1;
}
Integer regOffset = regOffsetMap.
get(iso
);
if(regOffset
!=
null)
return regOffset
;
else
return 1; // Default is 1 the next string after before country
}
public synchronized int getPoiDispFlag
(String iso
)
{
if (iso ==
null) {
return 0;
}
Integer flag = poiDispFlagMap.
get(iso
);
if(flag
!=
null)
return flag
;
else
return 0; // Default is 0
}
public synchronized boolean isContinent
(String continent
)
{
String s = continent.
toUpperCase().
trim();
return continents.
contains(s
);
}
public synchronized boolean getDriveOnLeftFlag
(String iso
)
{
if (iso ==
null)
return false;
Boolean driveOnLeft = driveOnLeftFlagMap.
get(iso
);
if (driveOnLeft ==
null){
log.
warn("Did not find iso code",iso,
"in LocatorConfig.xml, assuming drive-on-right for it");
driveOnLeftFlagMap.
put(iso,
false);
return false;
}
else
return driveOnLeft
;
}
}