001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import static java.util.Comparator.comparing;
005import static java.util.Comparator.comparingInt;
006
007import java.util.Comparator;
008import java.util.HashMap;
009import java.util.Map;
010import java.util.function.Function;
011
012import org.openstreetmap.josm.gui.DefaultNameFormatter;
013import org.openstreetmap.josm.tools.AlphanumComparator;
014
015/**
016 * Comparators for comparing primitives.
017 */
018public final class OsmPrimitiveComparator {
019
020    /**
021     * Returns a comparator comparing primitives by their name using {@link DefaultNameFormatter}.
022     *
023     * {@linkplain DefaultNameFormatter#format(OsmPrimitive) Formatted names} are cached.
024     *
025     * @return a comparator comparing primitives by their name using {@link DefaultNameFormatter}
026     */
027    public static Comparator<OsmPrimitive> comparingNames() {
028        final Comparator<String> digitsLast = comparing(str -> Character.isDigit(str.charAt(0)) ? 1 : 0);
029        return comparing(memoize(DefaultNameFormatter.getInstance()::format),
030                digitsLast.thenComparing(AlphanumComparator.getInstance()));
031    }
032
033    /**
034     * Returns a comparator comparing primitives by their {@linkplain OsmPrimitive#getUniqueId unique id}.
035     *
036     * @return a comparator comparing primitives by their {@linkplain OsmPrimitive#getUniqueId unique id}.
037     */
038    public static Comparator<OsmPrimitive> comparingUniqueId() {
039        return comparing(OsmPrimitive::getUniqueId);
040    }
041
042    /**
043     * Returns a comparator ordering the primitives by type in the order NODE, WAY, RELATION
044     *
045     * @return a comparator ordering the primitives by type in the order NODE, WAY, RELATION
046     */
047    public static Comparator<OsmPrimitive> orderingNodesWaysRelations() {
048        return comparingInt(osm -> osm.getType().ordinal());
049    }
050
051    /**
052     * Returns a comparator ordering the primitives by type in the order WAY, RELATION, NODE
053     *
054     * @return a comparator ordering the primitives by type in the order WAY, RELATION, NODE
055     */
056    public static Comparator<OsmPrimitive> orderingWaysRelationsNodes() {
057        return comparingInt(osm -> {
058            switch (osm.getType()) {
059                case WAY:
060                    return 1;
061                case RELATION:
062                    return 2;
063                case NODE:
064                    return 3;
065                default:
066                    throw new IllegalStateException();
067            }
068        });
069    }
070
071    private static <T, R> Function<T, R> memoize(Function<T, R> base) {
072        final Map<T, R> cache = new HashMap<>();
073        return t -> cache.computeIfAbsent(t, base);
074    }
075
076    private OsmPrimitiveComparator() {
077    }
078}