// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.data.conflict;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.tools.CheckParameterUtil;
/**
* GWT ok
*/
/**
* This is a collection of {@see Conflict}s. This collection is {@see Iterable}, i.e.
* it can be used in <code>for</code>-loops as follows:
* <pre>
* ConflictCollection conflictCollection = ....
*
* for(Conflict c : conflictCollection) {
* // do something
* }
* </pre>
*
* This collection emits an event when the content of the collection changes. You can register
* and unregister for these events using:
* <ul>
* <li>{@see #addConflictListener(IConflictListener)}</li>
* <li>{@see #removeConflictListener(IConflictListener)}</li>
* </ul>
*/
public class ConflictCollection implements Iterable<Conflict<? extends OsmPrimitive>>{
private final List<Conflict<? extends OsmPrimitive>> conflicts;
private CopyOnWriteArrayList<IConflictListener> listeners;
public ConflictCollection() {
conflicts = new ArrayList<Conflict<?>>();
listeners = new CopyOnWriteArrayList<IConflictListener>();
}
public void addConflictListener(IConflictListener listener) {
if (listener != null) {
listeners.addIfAbsent(listener);
}
}
public void removeConflictListener(IConflictListener listener) {
listeners.remove(listener);
}
protected void fireConflictAdded() {
for (IConflictListener listener : listeners) {
listener.onConflictsAdded(this);
}
}
protected void fireConflictRemoved() {
Iterator<IConflictListener> it = listeners.iterator();
while(it.hasNext()) {
it.next().onConflictsRemoved(this);
}
}
/**
* Adds a conflict to the collection
*
* @param conflict the conflict
* @exception IllegalStateException thrown, if this collection already includes a
* conflict for conflict.getMy()
*/
protected void addConflict(Conflict<?> conflict) throws IllegalStateException {
if (hasConflictForMy(conflict.getMy()))
throw new IllegalStateException(tr("Already registered a conflict for primitive ''{0}''.", conflict.getMy().toString()));
if (!conflicts.contains(conflict)) {
conflicts.add(conflict);
}
}
/**
* Adds a conflict to the collection of conflicts.
*
* @param conflict the conflict to add. Must not be null.
* @throws IllegalArgumentException thrown, if conflict is null
* @throws IllegalStateException thrown if this collection already includes a conflict for conflict.getMy()
*
*/
public void add(Conflict<?> conflict) throws IllegalStateException {
CheckParameterUtil.ensureParameterNotNull(conflict, "conflict");
addConflict(conflict);
fireConflictAdded();
}
/**
* Add the conflicts in <code>otherConflicts</code> to this collection of conflicts
*
* @param otherConflicts the collection of conflicts. Does nothing is conflicts is null.
*/
public void add(Collection<Conflict<?>> otherConflicts) {
if (otherConflicts == null) return;
for(Conflict<?> c : otherConflicts) {
addConflict(c);
}
fireConflictAdded();
}
/**
* Adds a conflict for the pair of {@see OsmPrimitive}s given by <code>my</code> and
* <code>their</code>.
*
* @param my my primitive
* @param their their primitive
*/
public void add(OsmPrimitive my, OsmPrimitive their) {
addConflict(new Conflict<OsmPrimitive>(my, their));
fireConflictAdded();
}
/**
* removes a conflict from this collection
*
* @param conflict the conflict
*/
public void remove(Conflict<?> conflict) {
conflicts.remove(conflict);
fireConflictRemoved();
}
/**
* removes the conflict registered for {@see OsmPrimitive} <code>my</code> if any
*
* @param my the primitive
*/
public void remove(OsmPrimitive my) {
Iterator<Conflict<?>> it = iterator();
while(it.hasNext()) {
if (it.next().isMatchingMy(my)) {
it.remove();
}
}
fireConflictRemoved();
}
/**
* Replies the conflict for the {@see OsmPrimitive} <code>my</code>, null
* if no such conflict exists.
*
* @param my my primitive
* @return the conflict for the {@see OsmPrimitive} <code>my</code>, null
* if no such conflict exists.
*/
public Conflict<?> getConflictForMy(OsmPrimitive my) {
for(Conflict<?> c : conflicts) {
if (c.isMatchingMy(my))
return c;
}
return null;
}
/**
* Replies the conflict for the {@see OsmPrimitive} <code>their</code>, null
* if no such conflict exists.
*
* @param my my primitive
* @return the conflict for the {@see OsmPrimitive} <code>their</code>, null
* if no such conflict exists.
*/
public Conflict<?> getConflictForTheir(OsmPrimitive their) {
for(Conflict<?> c : conflicts) {
if (c.isMatchingTheir(their))
return c;
}
return null;
}
/**
* Replies true, if this collection includes a conflict for <code>my</code>.
*
* @param my my primitive
* @return true, if this collection includes a conflict for <code>my</code>; false, otherwise
*/
public boolean hasConflictForMy(OsmPrimitive my) {
return getConflictForMy(my) != null;
}
/**
* Replies true, if this collection includes a given conflict
*
* @param c the conflict
* @return true, if this collection includes the conflict; false, otherwise
*/
public boolean hasConflict(Conflict<?> c) {
return hasConflictForMy(c.getMy());
}
/**
* Replies true, if this collection includes a conflict for <code>their</code>.
*
* @param their their primitive
* @return true, if this collection includes a conflict for <code>their</code>; false, otherwise
*/
public boolean hasConflictForTheir(OsmPrimitive their) {
return getConflictForTheir(their) != null;
}
/**
* Removes any conflicts for the {@see OsmPrimitive} <code>my</code>.
*
* @param my the primitive
*/
public void removeForMy(OsmPrimitive my) {
Iterator<Conflict<?>> it = iterator();
while(it.hasNext()) {
if (it.next().isMatchingMy(my)) {
it.remove();
}
}
}
/**
* Removes any conflicts for the {@see OsmPrimitive} <code>their</code>.
*
* @param their the primitive
*/
public void removeForTheir(OsmPrimitive their) {
Iterator<Conflict<?>> it = iterator();
while(it.hasNext()) {
if (it.next().isMatchingTheir(their)) {
it.remove();
}
}
}
/**
* Replies the conflicts as list.
*
* @return the list of conflicts
*/
public List<Conflict<?>> get() {
return conflicts;
}
/**
* Replies the size of the collection
*
* @return the size of the collection
*/
public int size() {
return conflicts.size();
}
/**
* Replies the conflict at position <code>idx</code>
*
* @param idx the index
* @return the conflict at position <code>idx</code>
*/
public Conflict<?> get(int idx) {
return conflicts.get(idx);
}
/**
* Replies the iterator for this collection.
*
* @return the iterator
*/
public Iterator<Conflict<?>> iterator() {
return conflicts.iterator();
}
public void add(ConflictCollection other) {
for (Conflict<?> c : other) {
add(c);
}
}
/**
* Replies the set of {@see OsmPrimitive} which participate in the role
* of "my" in the conflicts managed by this collection.
*
* @return the set of {@see OsmPrimitive} which participate in the role
* of "my" in the conflicts managed by this collection.
*/
public Set<OsmPrimitive> getMyConflictParties() {
HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
for (Conflict<?> c: conflicts) {
ret.add(c.getMy());
}
return ret;
}
/**
* Replies the set of {@see OsmPrimitive} which participate in the role
* of "their" in the conflicts managed by this collection.
*
* @return the set of {@see OsmPrimitive} which participate in the role
* of "their" in the conflicts managed by this collection.
*/
public Set<OsmPrimitive> getTheirConflictParties() {
HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
for (Conflict<?> c: conflicts) {
ret.add(c.getTheir());
}
return ret;
}
/**
* Replies true if this collection is empty
*
* @return true, if this collection is empty; false, otherwise
*/
public boolean isEmpty() {
return size() == 0;
}
@Override
public String toString() {
return conflicts.toString();
}
}