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.tools.AlphanumComparator;
013
014/**
015 * Comparators for comparing primitives.
016 */
017public final class OsmPrimitiveComparator {
018
019    /**
020     * Returns a comparator comparing primitives by their name using {@link DefaultNameFormatter}.
021     *
022     * {@linkplain DefaultNameFormatter#format(IPrimitive) Formatted names} are cached.
023     *
024     * @return a comparator comparing primitives by their name using {@link DefaultNameFormatter}
025     */
026    public static Comparator<OsmPrimitive> comparingNames() {
027        final Comparator<String> digitsLast = comparing(str -> !str.isEmpty() && Character.isDigit(str.charAt(0)) ? 1 : 0);
028        return comparing(memoize(DefaultNameFormatter.getInstance()::format),
029                digitsLast.thenComparing(AlphanumComparator.getInstance()));
030    }
031
032    /**
033     * Returns a comparator comparing primitives by their {@linkplain OsmPrimitive#getUniqueId unique id}.
034     *
035     * @return a comparator comparing primitives by their {@linkplain OsmPrimitive#getUniqueId unique id}.
036     */
037    public static Comparator<OsmPrimitive> comparingUniqueId() {
038        return comparing(OsmPrimitive::getUniqueId);
039    }
040
041    /**
042     * Returns a comparator ordering the primitives by type in the order NODE, WAY, RELATION
043     *
044     * @return a comparator ordering the primitives by type in the order NODE, WAY, RELATION
045     */
046    public static Comparator<OsmPrimitive> orderingNodesWaysRelations() {
047        return comparingInt(osm -> osm.getType().ordinal());
048    }
049
050    /**
051     * Returns a comparator ordering the primitives by type in the order WAY, RELATION, NODE
052     *
053     * @return a comparator ordering the primitives by type in the order WAY, RELATION, NODE
054     */
055    public static Comparator<OsmPrimitive> orderingWaysRelationsNodes() {
056        return comparingInt(osm -> {
057            switch (osm.getType()) {
058                case WAY:
059                    return 1;
060                case RELATION:
061                    return 2;
062                case NODE:
063                    return 3;
064                default:
065                    throw new IllegalStateException();
066            }
067        });
068    }
069
070    /**
071     * Returns a comparator ordering the primitives by type in the order RELATION, WAY, NODE
072     *
073     * @return a comparator ordering the primitives by type in the order RELATION, WAY, NODE
074     * @since 11679
075     */
076    public static Comparator<OsmPrimitive> orderingRelationsWaysNodes() {
077        return comparingInt(osm -> {
078            switch (osm.getType()) {
079                case RELATION:
080                    return 1;
081                case WAY:
082                    return 2;
083                case NODE:
084                    return 3;
085                default:
086                    throw new IllegalStateException();
087            }
088        });
089    }
090
091    private static <T, R> Function<T, R> memoize(Function<T, R> base) {
092        final Map<T, R> cache = new HashMap<>();
093        return t -> cache.computeIfAbsent(t, base);
094    }
095
096    private OsmPrimitiveComparator() {
097    }
098}