001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import java.util.Date;
005import java.util.List;
006import java.util.Map;
007
008import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
009import org.openstreetmap.josm.tools.LanguageInfo;
010
011/**
012 * IPrimitive captures the common functions of {@link OsmPrimitive} and {@link PrimitiveData}.
013 * @since 4098
014 */
015public interface IPrimitive extends Tagged, PrimitiveId, Stylable, Comparable<IPrimitive> {
016
017    /**
018     * Replies <code>true</code> if the object has been modified since it was loaded from
019     * the server. In this case, on next upload, this object will be updated.
020     *
021     * Deleted objects are deleted from the server. If the objects are added (id=0),
022     * the modified is ignored and the object is added to the server.
023     *
024     * @return <code>true</code> if the object has been modified since it was loaded from
025     * the server
026     */
027    boolean isModified();
028
029    /**
030     * Marks this primitive as being modified.
031     *
032     * @param modified true, if this primitive is to be modified
033     */
034    void setModified(boolean modified);
035
036    /**
037     * Checks if object is known to the server.
038     * Replies true if this primitive is either unknown to the server (i.e. its id
039     * is 0) or it is known to the server and it hasn't be deleted on the server.
040     * Replies false, if this primitive is known on the server and has been deleted
041     * on the server.
042     *
043     * @return <code>true</code>, if the object is visible on server.
044     * @see #setVisible(boolean)
045     */
046    boolean isVisible();
047
048    /**
049     * Sets whether this primitive is visible, i.e. whether it is known on the server
050     * and not deleted on the server.
051     * @param visible {@code true} if this primitive is visible
052     *
053     * @throws IllegalStateException if visible is set to false on an primitive with id==0
054     * @see #isVisible()
055     */
056    void setVisible(boolean visible);
057
058    /**
059     * Replies <code>true</code>, if the object has been deleted.
060     *
061     * @return <code>true</code>, if the object has been deleted.
062     * @see #setDeleted(boolean)
063     */
064    boolean isDeleted();
065
066    /**
067     * Sets whether this primitive is deleted or not.
068     *
069     * Also marks this primitive as modified if deleted is true.
070     *
071     * @param deleted  true, if this primitive is deleted; false, otherwise
072     */
073    void setDeleted(boolean deleted);
074
075    /**
076     * Determines if this primitive is incomplete.
077     * @return {@code true} if this primitive is incomplete, {@code false} otherwise
078     */
079    boolean isIncomplete();
080
081    /**
082     * Replies <code>true</code> if the object has been deleted on the server and was undeleted by the user.
083     * @return <code>true</code> if the object has been undeleted
084     */
085    boolean isUndeleted();
086
087    /**
088     * Replies <code>true</code>, if the object is usable
089     * (i.e. complete and not deleted).
090     *
091     * @return <code>true</code>, if the object is usable.
092     * @see #setDeleted(boolean)
093     */
094    boolean isUsable();
095
096    /**
097     * Determines if this primitive is new or undeleted.
098     * @return True if primitive is new or undeleted
099     * @see #isNew()
100     * @see #isUndeleted()
101     */
102    boolean isNewOrUndeleted();
103
104    /**
105     * Replies true, if this primitive is disabled. (E.g. a filter applies)
106     * @return {@code true} if this object has the "disabled" flag enabled
107     * @since 13662
108     */
109    default boolean isDisabled() {
110        return false;
111    }
112
113    /**
114     * Replies true, if this primitive is disabled and marked as completely hidden on the map.
115     * @return {@code true} if this object has both the "disabled" and "hide if disabled" flags enabled
116     * @since 13662
117     */
118    default boolean isDisabledAndHidden() {
119        return false;
120    }
121
122    /**
123     * Replies true, if this primitive is preserved from filtering.
124     * @return {@code true} if this object has the "preserved" flag enabled
125     * @since 13764
126     */
127    default boolean isPreserved() {
128        return false;
129    }
130
131    /**
132     * Determines if this object is selectable.
133     * <p>
134     * A primitive can be selected if all conditions are met:
135     * <ul>
136     * <li>it is drawable
137     * <li>it is not disabled (greyed out) by a filter.
138     * </ul>
139     * @return {@code true} if this object is selectable
140     * @since 13664
141     */
142    default boolean isSelectable() {
143        return true;
144    }
145
146    /**
147     * Determines if this object is drawable.
148     * <p>
149     * A primitive is complete if all conditions are met:
150     * <ul>
151     * <li>type and id is known
152     * <li>tags are known
153     * <li>it is not deleted
154     * <li>it is not hidden by a filter
155     * <li>for nodes: lat/lon are known
156     * <li>for ways: all nodes are known and complete
157     * <li>for relations: all members are known and complete
158     * </ul>
159     * @return {@code true} if this object is drawable
160     * @since 13664
161     */
162    default boolean isDrawable() {
163        return true;
164    }
165
166    /**
167     * Determines whether the primitive is selected
168     * @return whether the primitive is selected
169     * @since 13664
170     */
171    default boolean isSelected() {
172        return false;
173    }
174
175    /**
176     * Determines if this primitive is a member of a selected relation.
177     * @return {@code true} if this primitive is a member of a selected relation, {@code false} otherwise
178     * @since 13664
179     */
180    default boolean isMemberOfSelected() {
181        return false;
182    }
183
184    /**
185     * Determines if this primitive is an outer member of a selected multipolygon relation.
186     * @return {@code true} if this primitive is an outer member of a selected multipolygon relation, {@code false} otherwise
187     * @since 13664
188     */
189    default boolean isOuterMemberOfSelected() {
190        return false;
191    }
192
193    /**
194     * Replies the id of this primitive.
195     *
196     * @return the id of this primitive.
197     */
198    long getId();
199
200    /**
201     * Replies the OSM id of this primitive.
202     * By default, returns the same value as {@link #getId}.
203     * Can be overidden by primitive implementations handling an internal id different from the OSM one.
204     *
205     * @return the OSM id of this primitive.
206     * @since 13924
207     */
208    default long getOsmId() {
209        return getId();
210    }
211
212    /**
213     * Replies the OSM primitive id for this primitive.
214     *
215     * @return the OSM primitive id for this primitive
216     * @see #getOsmId
217     * @since 13924
218     */
219    default PrimitiveId getOsmPrimitiveId() {
220        return new SimplePrimitiveId(getOsmId(), getType());
221    }
222
223    /**
224     * Replies the unique primitive id for this primitive.
225     *
226     * @return the unique primitive id for this primitive
227     * @see #getUniqueId
228     */
229    default PrimitiveId getPrimitiveId() {
230        return new SimplePrimitiveId(getUniqueId(), getType());
231    }
232
233    /**
234     * Replies the version number as returned by the API. The version is 0 if the id is 0 or
235     * if this primitive is incomplete.
236     * @return the version number as returned by the API
237     *
238     * @see PrimitiveData#setVersion(int)
239     */
240    int getVersion();
241
242    /**
243     * Sets the id and the version of this primitive if it is known to the OSM API.
244     *
245     * Since we know the id and its version it can't be incomplete anymore. incomplete
246     * is set to false.
247     *
248     * @param id the id. &gt; 0 required
249     * @param version the version &gt; 0 required
250     * @throws IllegalArgumentException if id &lt;= 0
251     * @throws IllegalArgumentException if version &lt;= 0
252     * @throws DataIntegrityProblemException if id is changed and primitive was already added to the dataset
253     */
254    void setOsmId(long id, int version);
255
256    /**
257     * Replies the user who has last touched this object. May be null.
258     *
259     * @return the user who has last touched this object. May be null.
260     */
261    User getUser();
262
263    /**
264     * Sets the user who has last touched this object.
265     *
266     * @param user the user
267     */
268    void setUser(User user);
269
270    /**
271     * Time of last modification to this object. This is not set by JOSM but
272     * read from the server and delivered back to the server unmodified. It is
273     * used to check against edit conflicts.
274     *
275     * @return date of last modification
276     * @see #setTimestamp
277     */
278    Date getTimestamp();
279
280    /**
281     * Time of last modification to this object. This is not set by JOSM but
282     * read from the server and delivered back to the server unmodified. It is
283     * used to check against edit conflicts.
284     *
285     * @return last modification as timestamp
286     * @see #setRawTimestamp
287     */
288    int getRawTimestamp();
289
290    /**
291     * Sets time of last modification to this object
292     * @param timestamp date of last modification
293     * @see #getTimestamp
294     */
295    void setTimestamp(Date timestamp);
296
297    /**
298     * Sets time of last modification to this object
299     * @param timestamp date of last modification
300     * @see #getRawTimestamp
301     */
302    void setRawTimestamp(int timestamp);
303
304    /**
305     * Determines if this primitive has no timestamp information.
306     * @return {@code true} if this primitive has no timestamp information
307     * @see #getTimestamp
308     * @see #getRawTimestamp
309     */
310    boolean isTimestampEmpty();
311
312    /**
313     * Replies the id of the changeset this primitive was last uploaded to.
314     * 0 if this primitive wasn't uploaded to a changeset yet or if the
315     * changeset isn't known.
316     *
317     * @return the id of the changeset this primitive was last uploaded to.
318     */
319    int getChangesetId();
320
321    /**
322     * Sets the changeset id of this primitive. Can't be set on a new primitive.
323     *
324     * @param changesetId the id. &gt;= 0 required.
325     * @throws IllegalStateException if this primitive is new.
326     * @throws IllegalArgumentException if id &lt; 0
327     */
328    void setChangesetId(int changesetId);
329
330    /**
331     * Makes the given visitor visit this primitive.
332     * @param visitor visitor
333     */
334    void accept(PrimitiveVisitor visitor);
335
336    /**
337     * <p>Visits {@code visitor} for all referrers.</p>
338     *
339     * @param visitor the visitor. Ignored, if null.
340     * @since 13806
341     */
342    void visitReferrers(PrimitiveVisitor visitor);
343
344    /**
345     * Replies the name of this primitive. The default implementation replies the value
346     * of the tag <code>name</code> or null, if this tag is not present.
347     *
348     * @return the name of this primitive
349     */
350    default String getName() {
351        return get("name");
352    }
353
354    /**
355     * Replies a localized name for this primitive given by the value of the name tags
356     * accessed from very specific (language variant) to more generic (default name).
357     *
358     * @return the name of this primitive, <code>null</code> if no name exists
359     * @see LanguageInfo#getLanguageCodes
360     */
361    default String getLocalName() {
362        for (String s : LanguageInfo.getLanguageCodes(null)) {
363            String val = get("name:" + s);
364            if (val != null)
365                return val;
366        }
367
368        return getName();
369    }
370
371    /**
372     * Replies the display name of a primitive formatted by <code>formatter</code>
373     * @param formatter formatter to use
374     *
375     * @return the display name
376     * @since 13564
377     */
378    String getDisplayName(NameFormatter formatter);
379
380    /**
381     * Gets the type this primitive is displayed at
382     * @return A {@link OsmPrimitiveType}
383     * @since 13564
384     */
385    default OsmPrimitiveType getDisplayType() {
386        return getType();
387    }
388
389    /**
390     * Updates the highlight flag for this primitive.
391     * @param highlighted The new highlight flag.
392     * @since 13664
393     */
394    void setHighlighted(boolean highlighted);
395
396    /**
397     * Checks if the highlight flag for this primitive was set
398     * @return The highlight flag.
399     * @since 13664
400     */
401    boolean isHighlighted();
402
403    /**
404     * Determines if this object is considered "tagged". To be "tagged", an object
405     * must have one or more "interesting" tags. "created_by" and "source"
406     * are typically considered "uninteresting" and do not make an object "tagged".
407     * @return true if this object is considered "tagged"
408     * @since 13662
409     */
410    boolean isTagged();
411
412    /**
413     * Determines if this object is considered "annotated". To be "annotated", an object
414     * must have one or more "work in progress" tags, such as "note" or "fixme".
415     * @return true if this object is considered "annotated"
416     * @since 13662
417     */
418    boolean isAnnotated();
419
420    /**
421     * Determines if this object is a relation and behaves as a multipolygon.
422     * @return {@code true} if it is a real multipolygon or a boundary relation
423     * @since 13667
424     */
425    default boolean isMultipolygon() {
426        return false;
427    }
428
429    /**
430     * true if this object has direction dependent tags (e.g. oneway)
431     * @return {@code true} if this object has direction dependent tags
432     * @since 13662
433     */
434    boolean hasDirectionKeys();
435
436    /**
437     * true if this object has the "reversed direction" flag enabled
438     * @return {@code true} if this object has the "reversed direction" flag enabled
439     * @since 13662
440     */
441    boolean reversedDirection();
442
443    /**
444     * Fetches the bounding box of the primitive.
445     * @return Bounding box of the object
446     * @since 13764
447     */
448    BBox getBBox();
449
450    /**
451     * Gets a list of all primitives in the current dataset that reference this primitive.
452     * @return The referrers
453     * @since 13764
454     */
455    default List<? extends IPrimitive> getReferrers() {
456        return getReferrers(false);
457    }
458
459    /**
460     * Find primitives that reference this primitive. Returns only primitives that are included in the same
461     * dataset as this primitive. <br>
462     *
463     * For example following code will add wnew as referer to all nodes of existingWay, but this method will
464     * not return wnew because it's not part of the dataset <br>
465     *
466     * <code>Way wnew = new Way(existingWay)</code>
467     *
468     * @param allowWithoutDataset If true, method will return empty list if primitive is not part of the dataset. If false,
469     * exception will be thrown in this case
470     *
471     * @return a collection of all primitives that reference this primitive.
472     * @since 13808
473     */
474    List<? extends IPrimitive> getReferrers(boolean allowWithoutDataset);
475
476    /**
477     * Returns the parent data set of this primitive.
478     * @return OsmData this primitive is part of.
479     * @since 13807
480     */
481    OsmData<?, ?, ?, ?> getDataSet();
482
483    /**
484     * Returns {@link #getKeys()} for which {@code key} does not fulfill uninteresting criteria.
485     * @return A map of interesting tags
486     * @since 13809
487     */
488    Map<String, String> getInterestingTags();
489
490    /**
491     * Replies true if other isn't null and has the same interesting tags (key/value-pairs) as this.
492     *
493     * @param other the other object primitive
494     * @return true if other isn't null and has the same interesting tags (key/value-pairs) as this.
495     * @since 13809
496     */
497    default boolean hasSameInterestingTags(IPrimitive other) {
498        return (!hasKeys() && !other.hasKeys())
499                || getInterestingTags().equals(other.getInterestingTags());
500    }
501}