001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import java.util.Collection;
005import java.util.HashSet;
006import java.util.List;
007import java.util.Set;
008
009import org.openstreetmap.josm.tools.Utils;
010
011/**
012 * IRelation captures the common functions of {@link Relation} and {@link RelationData}.
013 * @param <M> Type of OSM relation member
014 * @since 4098
015 */
016public interface IRelation<M extends IRelationMember<?>> extends IPrimitive {
017
018    /**
019     * Returns the number of members.
020     * @return number of members
021     */
022    int getMembersCount();
023
024    /**
025     * Returns the relation member at the specified index.
026     * @param index the index of the relation member
027     * @return relation member at the specified index
028     * @since 13766 (IRelation)
029     */
030    M getMember(int index);
031
032    /**
033     * Returns members of the relation.
034     * @return Members of the relation. Changes made in returned list are not mapped
035     * back to the primitive, use {@link #setMembers} to modify the members
036     * @since 1925
037     * @since 13766 (IRelation)
038     */
039    List<M> getMembers();
040
041    /**
042     * Sets members of the relation.
043     * @param members Can be null, in that case all members are removed
044     */
045    void setMembers(List<M> members);
046
047    /**
048     * Returns id of the member at given index.
049     * @param idx member index
050     * @return id of the member at given index
051     */
052    long getMemberId(int idx);
053
054    /**
055     * Returns role of the member at given index.
056     * @param idx member index
057     * @return role of the member at given index
058     */
059    String getRole(int idx);
060
061    /**
062     * Returns type of the member at given index.
063     * @param idx member index
064     * @return type of the member at given index
065     */
066    OsmPrimitiveType getMemberType(int idx);
067
068    /**
069     * Determines if at least one child primitive is incomplete.
070     *
071     * @return true if at least one child primitive is incomplete
072     * @since 13564
073     */
074    default boolean hasIncompleteMembers() {
075        return false;
076    }
077
078    @Override
079    default int compareTo(IPrimitive o) {
080        return o instanceof IRelation ? Long.compare(getUniqueId(), o.getUniqueId()) : -1;
081    }
082
083    @Override
084    default String getDisplayName(NameFormatter formatter) {
085        return formatter.format(this);
086    }
087
088    /**
089     * Determines if this relation is a boundary.
090     * @return {@code true} if a boundary relation
091     */
092    default boolean isBoundary() {
093        return "boundary".equals(get("type"));
094    }
095
096    @Override
097    default boolean isMultipolygon() {
098        return "multipolygon".equals(get("type")) || isBoundary();
099    }
100
101    /**
102     * Returns an unmodifiable list of the {@link OsmPrimitive}s referred to by at least one member of this relation.
103     * @return an unmodifiable list of the primitives
104     * @since 13957
105     */
106    default List<? extends IPrimitive> getMemberPrimitivesList() {
107        return Utils.transform(getMembers(), IRelationMember::getMember);
108    }
109
110    /**
111     * Replies a collection with the incomplete children this relation refers to.
112     *
113     * @return the incomplete children. Empty collection if no children are incomplete.
114     * @since 13957
115     */
116    default Collection<? extends IPrimitive> getIncompleteMembers() {
117        Set<IPrimitive> ret = new HashSet<>();
118        for (M rm : getMembers()) {
119            if (!rm.getMember().isIncomplete()) {
120                continue;
121            }
122            ret.add(rm.getMember());
123        }
124        return ret;
125    }
126}