package edu.ualberta.med.biobank.common.action.util;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import edu.ualberta.med.biobank.model.HasId;
import edu.ualberta.med.biobank.model.util.IdUtil;
/**
* Immutable snapshot of the difference between two {@link Set}-s at a given
* point in time.
*
* @author Jonathan Ferland
*
* @param <E> element type
*/
public class DiffSet<E> implements Set<E> {
private static final String NOT_MUTEX_MSG = "Sets not mutually exclusive."
+ " The additions and removals sets must not share any equal values.";
private final Set<E> additions;
private final Set<E> removals;
private final Set<E> difference;
private DiffSet(Set<E> additions, Set<E> removals) {
this.additions = Collections.unmodifiableSet(additions);
this.removals = Collections.unmodifiableSet(removals);
Set<E> difference = new HashSet<E>();
difference.addAll(additions);
difference.addAll(removals);
if (difference.size() != additions.size() + removals.size()) {
throw new IllegalArgumentException(NOT_MUTEX_MSG);
}
this.difference = Collections.unmodifiableSet(difference);
}
public Set<E> getAdditions() {
return additions;
}
public Set<E> getRemovals() {
return removals;
}
/**
* Apply the difference to the given {@link Set}.
*
* @param s {@link Set} to apply this {@link DiffSet} to.
*/
public void apply(Set<E> s) {
s.removeAll(removals);
s.addAll(additions);
}
public static <E> DiffSet<E> copy(Set<E> additions, Set<E> removals) {
return new DiffSet<E>(additions, removals);
}
public static <E> DiffSet<E> of(Set<E> before, Set<E> after) {
Set<E> additions = new HashSet<E>(after);
additions.removeAll(before);
Set<E> removals = new HashSet<E>(before);
additions.removeAll(after);
return new DiffSet<E>(additions, removals);
}
public static <U extends Serializable, E extends HasId<U>> DiffSet<U> ofIds(
Set<E> before, Set<E> after) {
return of(IdUtil.getIds(before), IdUtil.getIds(after));
}
@Override
public boolean add(E e) {
return difference.add(e);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return difference.addAll(c);
}
@Override
public void clear() {
difference.clear();
}
@Override
public boolean contains(Object o) {
return difference.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return difference.containsAll(c);
}
@Override
public boolean isEmpty() {
return difference.isEmpty();
}
@Override
public Iterator<E> iterator() {
return difference.iterator();
}
@Override
public boolean remove(Object o) {
return difference.remove(o);
}
@Override
public boolean removeAll(Collection<?> c) {
return difference.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return difference.retainAll(c);
}
@Override
public int size() {
return difference.size();
}
@Override
public Object[] toArray() {
return difference.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return difference.toArray(a);
}
}