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