package org.eclipse.mylyn.reviews.ui.spi.editor;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.mylyn.reviews.core.model.IComment;
import org.eclipse.mylyn.reviews.core.model.IFileItem;
import org.eclipse.mylyn.reviews.core.model.ILocation;
import org.eclipse.mylyn.reviews.core.model.IReviewItemSet;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
final class ReviewSetContentProvider implements ITreeContentProvider {
private final Multimap<ILocation, IComment> threads = LinkedHashMultimap.create();
private final Multimap<String, ILocation> threadLocationsByFile = LinkedHashMultimap.create();
public Object[] getElements(Object inputElement) {
return getReviewItems(inputElement).toArray();
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// do nothing
}
@Override
public void dispose() {
threads.clear();
threadLocationsByFile.clear();
}
@Override
public boolean hasChildren(Object element) {
return !getFileComments(element).isEmpty() || element instanceof ILocation;
}
@Override
public Object getParent(Object element) {
// unsupported
return null;
}
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof IFileItem) {
IFileItem file = (IFileItem) parentElement;
Multimap<Long, IComment> commentsByLocation = Multimaps.index(getFileComments(file), commentLineNumber());
for (ILocation location : threadLocationsByFile.get(file.getId())) {
threads.removeAll(location);
}
threadLocationsByFile.removeAll(file.getId());
for (Long line : commentsByLocation.keySet()) {
ILocation location = null;
for (IComment comment : commentsByLocation.get(line)) {
if (location == null) {
location = comment.getLocations().iterator().next();
threadLocationsByFile.put(file.getId(), location);
}
if (!threads.containsValue(comment)) {
threads.put(location, comment);
}
}
}
Collection<ILocation> relevantThreads = threadLocationsByFile.get(file.getId());
ILocation[] locations = relevantThreads.toArray(new ILocation[relevantThreads.size()]);
Arrays.sort(locations, lineNumberComparator());
return locations;
} else if (parentElement instanceof ILocation) {
return threads.get((ILocation) parentElement).toArray();
}
return new Object[0];
}
private Comparator<ILocation> lineNumberComparator() {
return new Comparator<ILocation>() {
@Override
public int compare(ILocation o1, ILocation o2) {
return (int) (o1.getIndex() - o2.getIndex());
}
};
}
private Function<? super IComment, Long> commentLineNumber() {
return new Function<IComment, Long>() {
@Override
public Long apply(IComment comment) {
return comment.getLocations().iterator().next().getIndex();
}
};
}
private Predicate<IComment> hasLocation() {
return new Predicate<IComment>() {
@Override
public boolean apply(IComment input) {
return input.getLocations().iterator().hasNext();
}
};
}
private List<IFileItem> getReviewItems(Object inputElement) {
if (inputElement instanceof IReviewItemSet) {
return ((IReviewItemSet) inputElement).getItems();
}
return ImmutableList.of();
}
private List<IComment> getFileComments(Object inputElement) {
if (inputElement instanceof IFileItem) {
return FluentIterable.from(((IFileItem) inputElement).getAllComments()).filter(hasLocation()).toList();
}
return ImmutableList.of();
}
}