package cgeo.geocaching.filter; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; import android.util.Pair; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import cgeo.geocaching.R; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.location.Geopoint; import cgeo.geocaching.models.Geocache; import cgeo.geocaching.sensors.GeoData; import cgeo.geocaching.sensors.Sensors; public class MultiListingFilter extends AbstractFilter { private static final double MAX_DISTANCE_KILOMETERS = 0.02; public static final Creator<MultiListingFilter> CREATOR = new Parcelable.Creator<MultiListingFilter>() { @Override public MultiListingFilter createFromParcel(final Parcel in) { return new MultiListingFilter(in); } @Override public MultiListingFilter[] newArray(final int size) { return new MultiListingFilter[size]; } }; protected MultiListingFilter() { super(R.string.caches_filter_multi_listing); } public MultiListingFilter(final Parcel in) { super(in); } @Override public boolean accepts(@NonNull final Geocache cache) { // not used in this filter return false; } @Override public void filter(@NonNull final List<Geocache> list) { final List<Pair<Float, Geocache>> sorted = getDistanceSortedCaches(list); final HashSet<Geocache> filtered = new HashSet<>(); for (int i = 0; i < sorted.size(); i++) { final Geocache current = sorted.get(i).second; for (int j = i + 1; j < sorted.size(); j++) { final Geocache next = sorted.get(j).second; if (current.getCoords().distanceTo(next) < MAX_DISTANCE_KILOMETERS && haveSimilarNames(current, next)) { if (ConnectorFactory.getConnector(current) != ConnectorFactory.getConnector(next) && current.isFound() != next.isFound()) { filtered.add(current); filtered.add(next); } } else { break; } } } list.retainAll(filtered); } private static boolean haveSimilarNames(final Geocache current, final Geocache next) { return StringUtils.getLevenshteinDistance(current.getName(), next.getName()) < 3; } private static List<Pair<Float, Geocache>> getDistanceSortedCaches(final List<Geocache> list) { final GeoData geo = Sensors.getInstance().currentGeo(); final Geopoint currentPos = new Geopoint(geo); final List<Pair<Float, Geocache>> sorted = new ArrayList<>(); for (final Geocache cache : list) { final Geopoint coords = cache.getCoords(); if (coords != null) { final float distance = currentPos.distanceTo(coords); sorted.add(new Pair<>(distance, cache)); } } Collections.sort(sorted, new Comparator<Pair<Float, Geocache>>() { @Override public int compare(final Pair<Float, Geocache> lhs, final Pair<Float, Geocache> rhs) { return Float.compare(lhs.first, rhs.first); } }); return sorted; } }