001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.tagging.ac;
003
004import java.util.Objects;
005
006/**
007 * Describes the priority of an item in an autocompletion set.
008 * The selected flag is currently only used in plugins.
009 *
010 * Instances of this class are not modifiable.
011 * @since 12859 (copied from {@code gui.tagging.ac.AutoCompletionItemPriority})
012 */
013public class AutoCompletionPriority implements Comparable<AutoCompletionPriority> {
014
015    /**
016     * Indicates, that the value is standard and it is found in the data.
017     * This has higher priority than some arbitrary standard value that is
018     * usually not used by the user.
019     */
020    public static final AutoCompletionPriority IS_IN_STANDARD_AND_IN_DATASET = new AutoCompletionPriority(true, true, false);
021
022    /**
023     * Indicates that this is an arbitrary value from the data set, i.e.
024     * the value of a tag name=*.
025     */
026    public static final AutoCompletionPriority IS_IN_DATASET = new AutoCompletionPriority(true, false, false);
027
028    /**
029     * Indicates that this is a standard value, i.e. a standard tag name
030     * or a standard value for a given tag name (from the presets).
031     */
032    public static final AutoCompletionPriority IS_IN_STANDARD = new AutoCompletionPriority(false, true, false);
033
034    /**
035     * Indicates that this is a value from a selected object.
036     */
037    public static final AutoCompletionPriority IS_IN_SELECTION = new AutoCompletionPriority(false, false, true);
038
039    /** Unknown priority. This is the lowest priority. */
040    public static final AutoCompletionPriority UNKNOWN = new AutoCompletionPriority(false, false, false);
041
042    private static final int NO_USER_INPUT = Integer.MAX_VALUE;
043
044    private final int userInput;
045    private final boolean inDataSet;
046    private final boolean inStandard;
047    private final boolean selected;
048
049    /**
050     * Constructs a new {@code AutoCompletionItemPriority}.
051     *
052     * @param inDataSet true, if the item is found in the currently active data layer
053     * @param inStandard true, if the item is a standard tag, e.g. from the presets
054     * @param selected true, if it is found on an object that is currently selected
055     * @param userInput null, if the user hasn't entered this tag so far. A number when
056     * the tag key / value has been entered by the user before. A lower number means
057     * this happened more recently and beats a higher number in priority.
058     */
059    public AutoCompletionPriority(boolean inDataSet, boolean inStandard, boolean selected, Integer userInput) {
060        this.inDataSet = inDataSet;
061        this.inStandard = inStandard;
062        this.selected = selected;
063        this.userInput = userInput == null ? NO_USER_INPUT : userInput;
064    }
065
066    /**
067     * Constructs a new {@code AutoCompletionItemPriority}.
068     *
069     * @param inDataSet true, if the item is found in the currently active data layer
070     * @param inStandard true, if the item is a standard tag, e.g. from the presets
071     * @param selected true, if it is found on an object that is currently selected
072     */
073    public AutoCompletionPriority(boolean inDataSet, boolean inStandard, boolean selected) {
074        this(inDataSet, inStandard, selected, NO_USER_INPUT);
075    }
076
077    /**
078     * Determines if the item is found in the currently active data layer.
079     * @return {@code true} if the item is found in the currently active data layer
080     */
081    public boolean isInDataSet() {
082        return inDataSet;
083    }
084
085    /**
086     * Determines if the item is a standard tag, e.g. from the presets.
087     * @return {@code true} if the item is a standard tag, e.g. from the presets
088     */
089    public boolean isInStandard() {
090        return inStandard;
091    }
092
093    /**
094     * Determines if it is found on an object that is currently selected.
095     * @return {@code true} if it is found on an object that is currently selected
096     */
097    public boolean isSelected() {
098        return selected;
099    }
100
101    /**
102     * Returns a number when the tag key / value has been entered by the user before.
103     * A lower number means this happened more recently and beats a higher number in priority.
104     * @return a number when the tag key / value has been entered by the user before.
105     *         {@code null}, if the user hasn't entered this tag so far.
106     */
107    public Integer getUserInput() {
108        return userInput == NO_USER_INPUT ? null : userInput;
109    }
110
111    /**
112     * Imposes an ordering on the priorities.
113     * Currently, being in the current DataSet is worth more than being in the Presets.
114     */
115    @Override
116    public int compareTo(AutoCompletionPriority other) {
117        int ui = Integer.compare(other.userInput, userInput);
118        if (ui != 0)
119            return ui;
120
121        int sel = Boolean.compare(selected, other.selected);
122        if (sel != 0)
123            return sel;
124
125        int ds = Boolean.compare(inDataSet, other.inDataSet);
126        if (ds != 0)
127            return ds;
128
129        int std = Boolean.compare(inStandard, other.inStandard);
130        if (std != 0)
131            return std;
132
133        return 0;
134    }
135
136    /**
137     * Merges two priorities.
138     * The resulting priority is always &gt;= the original ones.
139     * @param other other priority
140     * @return the merged priority
141     */
142    public AutoCompletionPriority mergeWith(AutoCompletionPriority other) {
143        return new AutoCompletionPriority(
144                inDataSet || other.inDataSet,
145                inStandard || other.inStandard,
146                selected || other.selected,
147                Math.min(userInput, other.userInput));
148    }
149
150    @Override
151    public int hashCode() {
152        return Objects.hash(inDataSet, inStandard, selected, userInput);
153    }
154
155    @Override
156    public boolean equals(Object obj) {
157        if (this == obj)
158            return true;
159        if (obj == null || getClass() != obj.getClass())
160            return false;
161        AutoCompletionPriority other = (AutoCompletionPriority) obj;
162        return inDataSet == other.inDataSet &&
163               inStandard == other.inStandard &&
164               selected == other.selected &&
165               userInput == other.userInput;
166    }
167
168    @Override
169    public String toString() {
170        return String.format("<Priority; userInput: %s, inDataSet: %b, inStandard: %b, selected: %b>",
171                userInput == NO_USER_INPUT ? "no" : Integer.toString(userInput), inDataSet, inStandard, selected);
172    }
173}