001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm.history;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.Date;
009import java.util.List;
010
011import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
012import org.openstreetmap.josm.data.osm.User;
013import org.openstreetmap.josm.data.osm.Way;
014import org.openstreetmap.josm.tools.CheckParameterUtil;
015
016/**
017 * Represents an immutable OSM way in the context of a historical view on
018 * OSM data.
019 *
020 */
021public class HistoryWay extends HistoryOsmPrimitive {
022
023    private final List<Long> nodeIds = new ArrayList<>();
024
025    /**
026     * Constructs a new {@code HistoryWay}.
027     *
028     * @param id the id (&gt; 0 required)
029     * @param version the version (&gt; 0 required)
030     * @param visible whether the node is still visible
031     * @param user the user (!= null required)
032     * @param changesetId the changeset id (&gt; 0 required if {@code checkHistoricParams} is true)
033     * @param timestamp the timestamp (!= null required if {@code checkHistoricParams} is true)
034     * @throws IllegalArgumentException if preconditions are violated
035     */
036    public HistoryWay(long id, long version, boolean visible, User user, long changesetId, Date timestamp) {
037        super(id, version, visible, user, changesetId, timestamp);
038    }
039
040    /**
041     * Constructs a new {@code HistoryWay} with a configurable checking of historic parameters.
042     * This is needed to build virtual HistoryWays for modified ways, which do not have a timestamp and a changeset id.
043     *
044     * @param id the id (&gt; 0 required)
045     * @param version the version (&gt; 0 required)
046     * @param visible whether the node is still visible
047     * @param user the user (!= null required)
048     * @param changesetId the changeset id (&gt; 0 required if {@code checkHistoricParams} is true)
049     * @param timestamp the timestamp (!= null required if {@code checkHistoricParams} is true)
050     * @param checkHistoricParams if true, checks values of {@code changesetId} and {@code timestamp}
051     * @throws IllegalArgumentException if preconditions are violated
052     * @since 5440
053     */
054    public HistoryWay(long id, long version, boolean visible, User user, long changesetId, Date timestamp, boolean checkHistoricParams) {
055        super(id, version, visible, user, changesetId, timestamp, checkHistoricParams);
056    }
057
058    /**
059     * Constructs a new {@code HistoryWay} with a given list of node ids.
060     *
061     * @param id the id (&gt; 0 required)
062     * @param version the version (&gt; 0 required)
063     * @param visible whether the node is still visible
064     * @param user the user (!= null required)
065     * @param changesetId the changeset id (&gt; 0 required if {@code checkHistoricParams} is true)
066     * @param timestamp the timestamp (!= null required if {@code checkHistoricParams} is true)
067     * @param nodeIdList the node ids (!= null required)
068     * @throws IllegalArgumentException if preconditions are violated
069     */
070    public HistoryWay(long id, long version, boolean visible, User user, long changesetId, Date timestamp, List<Long> nodeIdList) {
071        this(id, version, visible, user, changesetId, timestamp);
072        CheckParameterUtil.ensureParameterNotNull(nodeIdList, "nodeIdList");
073        this.nodeIds.addAll(nodeIdList);
074    }
075
076    /**
077     * Constructs a new {@code HistoryWay} from an existing {@link Way}.
078     * @param w the way
079     */
080    public HistoryWay(Way w) {
081        super(w);
082    }
083
084    /**
085     * replies the number of nodes in this way
086     * @return the number of nodes
087     */
088    public int getNumNodes() {
089        return nodeIds.size();
090    }
091
092    /**
093     * replies the idx-th node id in the list of node ids of this way
094     *
095     * @param idx the index
096     * @return the idx-th node id
097     * @throws IndexOutOfBoundsException if  idx &lt; 0 || idx &gt;= {#see {@link #getNumNodes()}
098     */
099    public long getNodeId(int idx) {
100        if (idx < 0 || idx >= nodeIds.size())
101            throw new IndexOutOfBoundsException(tr("Parameter {0} not in range 0..{1}. Got ''{2}''.", "idx", nodeIds.size(), idx));
102        return nodeIds.get(idx);
103    }
104
105    /**
106     * replies an immutable list of the ways node ids
107     *
108     * @return the ways node ids
109     */
110    public List<Long> getNodes() {
111        return Collections.unmodifiableList(nodeIds);
112    }
113
114    /**
115     * replies the ways type, i.e. {@link OsmPrimitiveType#WAY}
116     *
117     * @return the ways type
118     */
119    @Override
120    public OsmPrimitiveType getType() {
121        return OsmPrimitiveType.WAY;
122    }
123
124    /**
125     * adds a node id to the list nodes of this way
126     *
127     * @param ref the node id to add
128     */
129    public void addNode(long ref) {
130        nodeIds.add(ref);
131    }
132
133    /**
134     * Replies true if this way is closed.
135     *
136     * @return true if this way is closed.
137     */
138    public boolean isClosed() {
139        return getNumNodes() >= 3 && nodeIds.get(0) == nodeIds.get(nodeIds.size()-1);
140    }
141
142    @Override
143    public String getDisplayName(HistoryNameFormatter formatter) {
144        return formatter.format(this);
145    }
146}