001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import java.util.HashMap;
005import java.util.HashSet;
006import java.util.Iterator;
007import java.util.Map;
008import java.util.Map.Entry;
009import java.util.Set;
010
011import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
012import org.openstreetmap.josm.tools.CheckParameterUtil;
013
014/**
015 * A ChangesetDataSet holds the content of a changeset.
016 */
017public class ChangesetDataSet {
018
019    public enum ChangesetModificationType {
020        CREATED,
021        UPDATED,
022        DELETED
023    }
024
025    public interface ChangesetDataSetEntry {
026        ChangesetModificationType getModificationType();
027
028        HistoryOsmPrimitive getPrimitive();
029    }
030
031    private final Map<PrimitiveId, HistoryOsmPrimitive> primitives = new HashMap<>();
032    private final Map<PrimitiveId, ChangesetModificationType> modificationTypes = new HashMap<>();
033
034    /**
035     * Remembers a history primitive with the given modification type
036     *
037     * @param primitive the primitive. Must not be null.
038     * @param cmt the modification type. Must not be null.
039     * @throws IllegalArgumentException if primitive is null
040     * @throws IllegalArgumentException if cmt is null
041     */
042    public void put(HistoryOsmPrimitive primitive, ChangesetModificationType cmt) {
043        CheckParameterUtil.ensureParameterNotNull(primitive, "primitive");
044        CheckParameterUtil.ensureParameterNotNull(cmt, "cmt");
045        primitives.put(primitive.getPrimitiveId(), primitive);
046        modificationTypes.put(primitive.getPrimitiveId(), cmt);
047    }
048
049    /**
050     * Replies true if the changeset content contains the object with primitive <code>id</code>.
051     * @param id the id.
052     * @return true if the changeset content contains the object with primitive <code>id</code>
053     */
054    public boolean contains(PrimitiveId id) {
055        if (id == null) return false;
056        return primitives.containsKey(id);
057    }
058
059    /**
060     * Replies the modification type for the object with id <code>id</code>. Replies null, if id is null or
061     * if the object with id <code>id</code> isn't in the changeset content.
062     *
063     * @param id the id
064     * @return the modification type
065     */
066    public ChangesetModificationType getModificationType(PrimitiveId id) {
067        if (!contains(id)) return null;
068        return modificationTypes.get(id);
069    }
070
071    /**
072     * Replies true if the primitive with id <code>id</code> was created in this
073     * changeset. Replies false, if id is null.
074     *
075     * @param id the id
076     * @return true if the primitive with id <code>id</code> was created in this
077     * changeset.
078     */
079    public boolean isCreated(PrimitiveId id) {
080        if (!contains(id)) return false;
081        return ChangesetModificationType.CREATED.equals(getModificationType(id));
082    }
083
084    /**
085     * Replies true if the primitive with id <code>id</code> was updated in this
086     * changeset. Replies false, if id is null.
087     *
088     * @param id the id
089     * @return true if the primitive with id <code>id</code> was updated in this
090     * changeset.
091     */
092    public boolean isUpdated(PrimitiveId id) {
093        if (!contains(id)) return false;
094        return ChangesetModificationType.UPDATED.equals(getModificationType(id));
095    }
096
097    /**
098     * Replies true if the primitive with id <code>id</code> was deleted in this
099     * changeset. Replies false, if id is null.
100     *
101     * @param id the id
102     * @return true if the primitive with id <code>id</code> was deleted in this
103     * changeset.
104     */
105    public boolean isDeleted(PrimitiveId id) {
106        if (!contains(id)) return false;
107        return ChangesetModificationType.DELETED.equals(getModificationType(id));
108    }
109
110    /**
111     * Replies the set of primitives with a specific modification type
112     *
113     * @param cmt the modification type. Must not be null.
114     * @return the set of primitives
115     * @throws IllegalArgumentException if cmt is null
116     */
117    public Set<HistoryOsmPrimitive> getPrimitivesByModificationType(ChangesetModificationType cmt) {
118        CheckParameterUtil.ensureParameterNotNull(cmt, "cmt");
119        Set<HistoryOsmPrimitive> ret = new HashSet<>();
120        for (Entry<PrimitiveId, ChangesetModificationType> entry: modificationTypes.entrySet()) {
121            if (entry.getValue().equals(cmt)) {
122                ret.add(primitives.get(entry.getKey()));
123            }
124        }
125        return ret;
126    }
127
128    /**
129     * Replies the number of objects in the dataset
130     *
131     * @return the number of objects in the dataset
132     */
133    public int size() {
134        return primitives.size();
135    }
136
137    /**
138     * Replies the {@link HistoryOsmPrimitive} with id <code>id</code> from this
139     * dataset. null, if there is no such primitive in the data set.
140     *
141     * @param id the id
142     * @return  the {@link HistoryOsmPrimitive} with id <code>id</code> from this
143     * dataset
144     */
145    public HistoryOsmPrimitive getPrimitive(PrimitiveId id) {
146        if (id == null)  return null;
147        return primitives.get(id);
148    }
149
150    public Iterator<ChangesetDataSetEntry> iterator() {
151        return new DefaultIterator();
152    }
153
154    private static class DefaultChangesetDataSetEntry implements ChangesetDataSetEntry {
155        private ChangesetModificationType modificationType;
156        private HistoryOsmPrimitive primitive;
157
158        DefaultChangesetDataSetEntry(ChangesetModificationType modificationType, HistoryOsmPrimitive primitive) {
159            this.modificationType = modificationType;
160            this.primitive = primitive;
161        }
162
163        @Override
164        public ChangesetModificationType getModificationType() {
165            return modificationType;
166        }
167
168        @Override
169        public HistoryOsmPrimitive getPrimitive() {
170            return primitive;
171        }
172    }
173
174    private class DefaultIterator implements Iterator<ChangesetDataSetEntry> {
175        private Iterator<Entry<PrimitiveId, ChangesetModificationType>> typeIterator;
176
177        DefaultIterator() {
178            typeIterator = modificationTypes.entrySet().iterator();
179        }
180
181        @Override
182        public boolean hasNext() {
183            return typeIterator.hasNext();
184        }
185
186        @Override
187        public ChangesetDataSetEntry next() {
188            Entry<PrimitiveId, ChangesetModificationType> next = typeIterator.next();
189            ChangesetModificationType type = next.getValue();
190            HistoryOsmPrimitive primitive = primitives.get(next.getKey());
191            return new DefaultChangesetDataSetEntry(type, primitive);
192        }
193
194        @Override
195        public void remove() {
196            throw new UnsupportedOperationException();
197        }
198    }
199}