001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import java.util.Objects;
005
006import org.openstreetmap.josm.tools.Pair;
007
008/**
009 * A directed pair of nodes (a,b != b,a).
010 * @since 12463 (extracted from CombineWayAction)
011 */
012public class NodePair {
013    private final Node a;
014    private final Node b;
015
016    /**
017     * Constructs a new {@code NodePair}.
018     * @param a The first node
019     * @param b The second node
020     */
021    public NodePair(Node a, Node b) {
022        this.a = a;
023        this.b = b;
024    }
025
026    /**
027     * Constructs a new {@code NodePair}.
028     * @param pair An existing {@code Pair} of nodes
029     */
030    public NodePair(Pair<Node, Node> pair) {
031        this(pair.a, pair.b);
032    }
033
034    /**
035     * Replies the first node.
036     * @return The first node
037     */
038    public Node getA() {
039        return a;
040    }
041
042    /**
043     * Replies the second node
044     * @return The second node
045     */
046    public Node getB() {
047        return b;
048    }
049
050    /**
051     * Determines if this pair is successor of another one (other.b == this.a)
052     * @param other other pair
053     * @return {@code true} if other.b == this.a
054     */
055    public boolean isSuccessorOf(NodePair other) {
056        return other.getB() == a;
057    }
058
059    /**
060     * Determines if this pair is predecessor of another one (this.b == other.a)
061     * @param other other pair
062     * @return {@code true} if this.b == other.a
063     */
064    public boolean isPredecessorOf(NodePair other) {
065        return b == other.getA();
066    }
067
068    /**
069     * Returns the inversed pair.
070     * @return swapped copy
071     */
072    public NodePair swap() {
073        return new NodePair(b, a);
074    }
075
076    @Override
077    public String toString() {
078        return new StringBuilder()
079        .append('[')
080        .append(a.getId())
081        .append(',')
082        .append(b.getId())
083        .append(']')
084        .toString();
085    }
086
087    /**
088     * Determines if this pair contains the given node.
089     * @param n The node to look for
090     * @return {@code true} if {@code n} is in the pair, {@code false} otherwise
091     */
092    public boolean contains(Node n) {
093        return a == n || b == n;
094    }
095
096    @Override
097    public int hashCode() {
098        return Objects.hash(a, b);
099    }
100
101    @Override
102    public boolean equals(Object obj) {
103        if (this == obj) return true;
104        if (obj == null || getClass() != obj.getClass()) return false;
105        NodePair nodePair = (NodePair) obj;
106        return Objects.equals(a, nodePair.a) &&
107               Objects.equals(b, nodePair.b);
108    }
109}