package de.westnordost.streetcomplete.data.osm.changes;
import android.support.annotation.NonNull;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/** A diff that can be applied on a map of strings. Use StringMapChangesBuilder to conveniently build
* it. A StringMapChanges is immutable. */
public class StringMapChanges
{
private final List<StringMapEntryChange> changes;
public List<StringMapEntryChange> getChanges()
{
return Collections.unmodifiableList(changes);
}
public StringMapChanges(@NonNull List<StringMapEntryChange> changes)
{
this.changes = changes;
}
public boolean hasConflictsTo(@NonNull final Map<String,String> map)
{
return getConflictsTo(map).iterator().hasNext();
}
/** Return an iterable to iterate through the changes that have conflicts with the given map */
public Iterable<StringMapEntryChange> getConflictsTo(@NonNull final Map<String,String> map)
{
return new Iterable<StringMapEntryChange>()
{
@Override public Iterator<StringMapEntryChange> iterator()
{
return new ConflictIterator(map);
}
};
}
/** Applies this diff to the given map. */
public void applyTo(@NonNull Map<String,String> map)
{
if(hasConflictsTo(map))
{
throw new IllegalStateException("Could not apply the diff, there is at least one conflict.");
}
for(StringMapEntryChange change : changes)
{
change.applyTo(map);
}
}
public boolean isEmpty()
{
return changes.isEmpty();
}
@Override public String toString()
{
StringBuilder sb = new StringBuilder();
boolean first = true;
for(StringMapEntryChange change : changes)
{
if(first)
{
first = false;
}
else
{
sb.append(", ");
}
sb.append(change.toString());
}
return sb.toString();
}
@Override public boolean equals(Object other)
{
if(other == null || !(other instanceof StringMapChanges)) return false;
StringMapChanges o = (StringMapChanges) other;
return changes.equals(o.changes);
}
private class ConflictIterator implements Iterator<StringMapEntryChange>
{
private Map<String,String> map;
private StringMapEntryChange next;
private Iterator<StringMapEntryChange> it = changes.iterator();
public ConflictIterator(@NonNull Map<String,String> map)
{
this.map = map;
}
@Override public boolean hasNext()
{
findNext();
return next != null;
}
@Override public StringMapEntryChange next()
{
findNext();
StringMapEntryChange result = next;
next = null;
if(result == null)
{
throw new NoSuchElementException();
}
return result;
}
private void findNext()
{
if(next == null)
{
while (it.hasNext())
{
StringMapEntryChange change = it.next();
if (change.conflictsWith(map))
{
next = change;
return;
}
}
}
}
@Override public void remove()
{
throw new UnsupportedOperationException();
}
}
}