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