001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.data.osm.history;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import java.util.ArrayList;
007    import java.util.Collections;
008    import java.util.Date;
009    import java.util.List;
010    
011    import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
012    import org.openstreetmap.josm.data.osm.User;
013    import org.openstreetmap.josm.data.osm.Way;
014    import 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     */
021    public class HistoryWay extends HistoryOsmPrimitive {
022    
023        private ArrayList<Long> nodeIds = new ArrayList<Long>();
024    
025        /**
026         * Constructs a new {@code HistoryWay}.
027         * 
028         * @param id the id (> 0 required)
029         * @param version the version (> 0 required)
030         * @param visible whether the node is still visible
031         * @param user the user (! null required)
032         * @param changesetId the changeset id (> 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) throws IllegalArgumentException {
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 (> 0 required)
045         * @param version the version (> 0 required)
046         * @param visible whether the node is still visible
047         * @param user the user (! null required)
048         * @param changesetId the changeset id (> 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) throws IllegalArgumentException {
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 (> 0 required)
062         * @param version the version (> 0 required)
063         * @param visible whether the node is still visible
064         * @param user the user (! null required)
065         * @param changesetId the changeset id (> 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, ArrayList<Long> nodeIdList) throws IllegalArgumentException {
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         * @exception IndexOutOfBoundsException thrown, if  idx <0 || idx >= {#see {@link #getNumNodes()}
098         */
099        public long getNodeId(int idx) throws IndexOutOfBoundsException {
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    }