001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import java.util.Arrays;
005import java.util.Collection;
006import java.util.Map;
007import java.util.Objects;
008
009/**
010 * Objects implement Tagged if they provide a map of key/value pairs.
011 *
012 * @since 2115
013 */
014// FIXME: better naming? setTags(), getTags(), getKeys() instead of keySet() ?
015//
016public interface Tagged {
017
018    /**
019     * The maximum tag length allowed by OSM API
020     * @since 13414
021     */
022    int MAX_TAG_LENGTH = 255;
023
024    /**
025     * Sets the map of key/value pairs
026     *
027     * @param keys the map of key value pairs. If null, reset to the empty map.
028     */
029    void setKeys(Map<String, String> keys);
030
031    /**
032     * Replies the map of key/value pairs. Never null, but may be the empty map.
033     *
034     * @return the map of key/value pairs
035     */
036    Map<String, String> getKeys();
037
038    /**
039     * Calls the visitor for every key/value pair.
040     *
041     * @param visitor The visitor to call.
042     * @see #getKeys()
043     * @since 13668
044     */
045    default void visitKeys(KeyValueVisitor visitor) {
046        getKeys().forEach((k, v) -> visitor.visitKeyValue(this, k, v));
047    }
048
049    /**
050     * Sets a key/value pairs
051     *
052     * @param key the key
053     * @param value the value. If null, removes the key/value pair.
054     */
055    void put(String key, String value);
056
057    /**
058     * Sets a key/value pairs
059     *
060     * @param tag The tag to set.
061     * @since 10736
062     */
063    default void put(Tag tag) {
064        put(tag.getKey(), tag.getValue());
065    }
066
067    /**
068     * Replies the value of the given key; null, if there is no value for this key
069     *
070     * @param key the key
071     * @return the value
072     */
073    String get(String key);
074
075    /**
076     * Removes a given key/value pair
077     *
078     * @param key the key
079     */
080    void remove(String key);
081
082    /**
083     * Replies true, if there is at least one key/value pair; false, otherwise
084     *
085     * @return true, if there is at least one key/value pair; false, otherwise
086     */
087    boolean hasKeys();
088
089    /**
090     * Replies true if there is a tag with key <code>key</code>.
091     * The value could however be empty. See {@link #hasTag(String)} to check for non-empty tags.
092     *
093     * @param key the key
094     * @return true, if there is a tag with key <code>key</code>
095     * @see #hasTag(String)
096     * @since 11608
097     */
098    default boolean hasKey(String key) {
099        return get(key) != null;
100    }
101
102    /**
103     * Replies true if there is a non-empty tag with key <code>key</code>.
104     *
105     * @param key the key
106     * @return true, if there is a non-empty tag with key <code>key</code>
107     * @see Tagged#hasKey(String)
108     * @since 13430
109     */
110    default boolean hasTag(String key) {
111        String v = get(key);
112        return v != null && !v.isEmpty();
113    }
114
115    /**
116     * Tests whether this primitive contains a tag consisting of {@code key} and {@code value}.
117     * @param key the key forming the tag.
118     * @param value value forming the tag.
119     * @return true if primitive contains a tag consisting of {@code key} and {@code value}.
120     * @since 13668
121     */
122    default boolean hasTag(String key, String value) {
123        return Objects.equals(value, get(key));
124    }
125
126    /**
127     * Tests whether this primitive contains a tag consisting of {@code key} and any of {@code values}.
128     * @param key the key forming the tag.
129     * @param values one or many values forming the tag.
130     * @return true if primitive contains a tag consisting of {@code key} and any of {@code values}.
131     * @since 13668
132     */
133    default boolean hasTag(String key, String... values) {
134        return hasTag(key, Arrays.asList(values));
135    }
136
137    /**
138     * Tests whether this primitive contains a tag consisting of {@code key} and any of {@code values}.
139     * @param key the key forming the tag.
140     * @param values one or many values forming the tag.
141     * @return true if primitive contains a tag consisting of {@code key} and any of {@code values}.
142     * @since 13668
143     */
144    default boolean hasTag(String key, Collection<String> values) {
145        return values.contains(get(key));
146    }
147
148    /**
149     * Tests whether this primitive contains a tag consisting of {@code key} and a value different from {@code value}.
150     * @param key the key forming the tag.
151     * @param value value not forming the tag.
152     * @return true if primitive contains a tag consisting of {@code key} and a value different from {@code value}.
153     * @since 13668
154     */
155    default boolean hasTagDifferent(String key, String value) {
156        String v = get(key);
157        return v != null && !v.equals(value);
158    }
159
160    /**
161     * Tests whether this primitive contains a tag consisting of {@code key} and none of {@code values}.
162     * @param key the key forming the tag.
163     * @param values one or many values forming the tag.
164     * @return true if primitive contains a tag consisting of {@code key} and none of {@code values}.
165     * @since 13668
166     */
167    default boolean hasTagDifferent(String key, String... values) {
168        return hasTagDifferent(key, Arrays.asList(values));
169    }
170
171    /**
172     * Tests whether this primitive contains a tag consisting of {@code key} and none of {@code values}.
173     * @param key the key forming the tag.
174     * @param values one or many values forming the tag.
175     * @return true if primitive contains a tag consisting of {@code key} and none of {@code values}.
176     * @since 13668
177     */
178    default boolean hasTagDifferent(String key, Collection<String> values) {
179        String v = get(key);
180        return v != null && !values.contains(v);
181    }
182
183    /**
184     * Replies the set of keys
185     *
186     * @return the set of keys
187     */
188    Collection<String> keySet();
189
190    /**
191     * Gets the number of keys
192     * @return The number of keys set for this tagged object.
193     * @since 13625
194     */
195    int getNumKeys();
196
197    /**
198     * Removes all tags
199     */
200    void removeAll();
201
202    /**
203     * Returns true if the {@code key} corresponds to an OSM true value.
204     * @param key OSM key
205     * @return {@code true} if the {@code key} corresponds to an OSM true value
206     * @see OsmUtils#isTrue(String)
207     */
208    default boolean isKeyTrue(String key) {
209        return OsmUtils.isTrue(get(key));
210    }
211
212    /**
213     * Returns true if the {@code key} corresponds to an OSM false value.
214     * @param key OSM key
215     * @return {@code true} if the {@code key} corresponds to an OSM false value
216     * @see OsmUtils#isFalse(String)
217     */
218    default boolean isKeyFalse(String key) {
219        return OsmUtils.isFalse(get(key));
220    }
221}