package net.osmand.plus.poi;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.data.Amenity;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.util.MapUtils;
import net.sf.junidecode.Junidecode;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class NominatimPoiFilter extends PoiUIFilter {
private static final String FILTER_ID = "name_finder"; //$NON-NLS-1$
private static final Log log = PlatformUtil.getLog(NominatimPoiFilter.class);
private static final int LIMIT = 300;
private String lastError = ""; //$NON-NLS-1$
private boolean addressQuery;
public NominatimPoiFilter(OsmandApplication application, boolean addressQuery) {
super(application);
this.addressQuery = addressQuery;
this.name =
application.getString(R.string.poi_filter_nominatim); //$NON-NLS-1$
if(addressQuery) {
this.name += " - " + application.getString(R.string.shared_string_address);
} else {
this.name += " - " + application.getString(R.string.shared_string_places);
}
if(addressQuery) {
this.distanceToSearchValues = new double[] {500};
} else {
this.distanceToSearchValues = new double[] {1, 2, 5, 10, 20, 50, 100, 200, 500 };
}
this.filterId = FILTER_ID + (addressQuery ? "_address" : "_places");
}
public boolean isPlacesQuery() {
return !addressQuery;
}
@Override
public boolean isAutomaticallyIncreaseSearch() {
return false;
}
// do nothing test jackdaw lane, oxford"
@Override
public AmenityNameFilter getNameFilter(String filter) {
return new AmenityNameFilter() {
@Override
public boolean accept(Amenity a) {
return true;
}
};
}
@Override
protected List<Amenity> searchAmenitiesInternal(double lat, double lon, double topLatitude,
double bottomLatitude, double leftLongitude, double rightLongitude, int zoom, ResultMatcher<Amenity> matcher) {
final int deviceApiVersion = android.os.Build.VERSION.SDK_INT;
String NOMINATIM_API;
if (deviceApiVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) {
NOMINATIM_API = "https://nominatim.openstreetmap.org/search/";
} else {
NOMINATIM_API = "http://nominatim.openstreetmap.org/search/";
}
currentSearchResult = new ArrayList<Amenity>();
String viewbox = "viewboxlbrt="+((float) leftLongitude)+","+((float) bottomLatitude)+","+((float) rightLongitude)+","+((float) topLatitude);
try {
lastError = "";
String urlq ;
if(addressQuery) {
urlq = NOMINATIM_API + "?format=xml&addressdetails=0&accept-language="+ Locale.getDefault().getLanguage()
+ "&q=" + URLEncoder.encode(getFilterByName());
} else {
urlq = NOMINATIM_API + URLEncoder.encode(getFilterByName()) + "?format=xml&addressdetails=1&limit=" + LIMIT
+ "&bounded=1&" + viewbox;
}
log.info(urlq);
URLConnection connection = NetworkUtils.getHttpURLConnection(urlq); //$NON-NLS-1$
InputStream stream = connection.getInputStream();
XmlPullParser parser = PlatformUtil.newXMLPullParser();
parser.setInput(stream, "UTF-8"); //$NON-NLS-1$
int eventType;
int namedDepth = 0;
Amenity a = null;
MapPoiTypes poiTypes = ((OsmandApplication) getApplication()).getPoiTypes();
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("searchresults")) { //$NON-NLS-1$
String err = parser.getAttributeValue("", "error"); //$NON-NLS-1$ //$NON-NLS-2$
if (err != null && err.length() > 0) {
lastError = err;
stream.close();
return currentSearchResult;
}
}
if (parser.getName().equals("place")) { //$NON-NLS-1$
namedDepth++;
if (namedDepth == 1) {
try {
a = new Amenity();
a.setLocation(Double.parseDouble(parser.getAttributeValue("", "lat")), //$NON-NLS-1$//$NON-NLS-2$
Double.parseDouble(parser.getAttributeValue("", "lon"))); //$NON-NLS-1$//$NON-NLS-2$
a.setId(Long.parseLong(parser.getAttributeValue("", "place_id"))); //$NON-NLS-1$ //$NON-NLS-2$
String name = parser.getAttributeValue("", "display_name"); //$NON-NLS-1$//$NON-NLS-2$
a.setName(name);
a.setEnName(Junidecode.unidecode(name));
a.setType(poiTypes.getOtherPoiCategory());
a.setSubType(parser.getAttributeValue("", "type")); //$NON-NLS-1$//$NON-NLS-2$
if (matcher == null || matcher.publish(a)) {
currentSearchResult.add(a);
}
} catch (NumberFormatException e) {
log.info("Invalid attributes", e); //$NON-NLS-1$
}
}
} else if (a != null && parser.getName().equals(a.getSubType())) {
if (parser.next() == XmlPullParser.TEXT) {
String name = parser.getText();
if (name != null) {
a.setName(name);
a.setEnName(Junidecode.unidecode(name));
}
}
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("place")) { //$NON-NLS-1$
namedDepth--;
if (namedDepth == 0) {
a = null;
}
}
}
}
stream.close();
} catch (IOException e) {
log.error("Error loading name finder poi", e); //$NON-NLS-1$
lastError = getApplication().getString(R.string.shared_string_io_error); //$NON-NLS-1$
} catch (XmlPullParserException e) {
log.error("Error parsing name finder poi", e); //$NON-NLS-1$
lastError = getApplication().getString(R.string.shared_string_io_error); //$NON-NLS-1$
}
MapUtils.sortListOfMapObject(currentSearchResult, lat, lon);
return currentSearchResult;
}
public String getLastError() {
return lastError;
}
}