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.Objects;
007import java.util.Set;
008import java.util.stream.Collectors;
009
010/**
011 * This is an extension of {@link RelationMember} that stores the parent relation and the index in it in addition to the role/child.
012 */
013public class RelationToChildReference {
014
015    /**
016     * Replies a set of all {@link RelationToChildReference}s for a given child primitive.
017     *
018     * @param child the child primitive
019     * @return  a set of all {@link RelationToChildReference}s for a given child primitive
020     */
021    public static Set<RelationToChildReference> getRelationToChildReferences(OsmPrimitive child) {
022        Set<Relation> parents = child.referrers(Relation.class).collect(Collectors.toSet());
023        Set<RelationToChildReference> references = new HashSet<>();
024        for (Relation parent: parents) {
025            for (int i = 0; i < parent.getMembersCount(); i++) {
026                if (parent.getMember(i).refersTo(child)) {
027                    references.add(new RelationToChildReference(parent, i, parent.getMember(i)));
028                }
029            }
030        }
031        return references;
032    }
033
034    /**
035     * Replies a set of all {@link RelationToChildReference}s for a collection of child primitives
036     *
037     * @param children the collection of child primitives
038     * @return  a set of all {@link RelationToChildReference}s to the children in the collection of child
039     * primitives
040     */
041    public static Set<RelationToChildReference> getRelationToChildReferences(Collection<? extends OsmPrimitive> children) {
042        Set<RelationToChildReference> references = new HashSet<>();
043        for (OsmPrimitive child: children) {
044            references.addAll(getRelationToChildReferences(child));
045        }
046        return references;
047    }
048
049    private final Relation parent;
050    private final int position;
051    private final String role;
052    private final OsmPrimitive child;
053
054    /**
055     * Create a new {@link RelationToChildReference}
056     * @param parent The parent relation
057     * @param position The position of the child in the parent
058     * @param role The role of the child
059     * @param child The actual child (member of parent)
060     */
061    public RelationToChildReference(Relation parent, int position, String role, OsmPrimitive child) {
062        this.parent = parent;
063        this.position = position;
064        this.role = role;
065        this.child = child;
066    }
067
068    /**
069     * Create a new {@link RelationToChildReference}
070     * @param parent The parent relation
071     * @param position The position of the child in the parent
072     * @param member The role and relation for the child
073     */
074    public RelationToChildReference(Relation parent, int position, RelationMember member) {
075        this(parent, position, member.getRole(), member.getMember());
076    }
077
078    /**
079     * Get the parent relation
080     * @return The parent
081     */
082    public Relation getParent() {
083        return parent;
084    }
085
086    /**
087     * Get the position of the child in the parent
088     * @return The position of the child
089     */
090    public int getPosition() {
091        return position;
092    }
093
094    /**
095     * Get the role of the child
096     * @return The role
097     */
098    public String getRole() {
099        return role;
100    }
101
102    /**
103     * Get the actual child
104     * @return The child
105     */
106    public OsmPrimitive getChild() {
107        return child;
108    }
109
110    @Override
111    public boolean equals(Object obj) {
112        if (this == obj) return true;
113        if (obj == null || getClass() != obj.getClass()) return false;
114        RelationToChildReference that = (RelationToChildReference) obj;
115        return position == that.position &&
116                Objects.equals(parent, that.parent) &&
117                Objects.equals(role, that.role) &&
118                Objects.equals(child, that.child);
119    }
120
121    @Override
122    public int hashCode() {
123        return Objects.hash(parent, position, role, child);
124    }
125}