package net.pterodactylus.sone.core;
import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.fromNullable;
import static com.google.common.collect.FluentIterable.from;
import java.util.Collection;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.data.Sone;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
/**
* Compares the contents of two {@link Sone}s and fires events for new and
* removed elements.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
public class SoneChangeDetector {
private final Sone oldSone;
private Optional<PostProcessor> newPostProcessor = absent();
private Optional<PostProcessor> removedPostProcessor = absent();
private Optional<PostReplyProcessor> newPostReplyProcessor = absent();
private Optional<PostReplyProcessor> removedPostReplyProcessor = absent();
public SoneChangeDetector(Sone oldSone) {
this.oldSone = oldSone;
}
public void onNewPosts(PostProcessor newPostProcessor) {
this.newPostProcessor = fromNullable(newPostProcessor);
}
public void onRemovedPosts(PostProcessor removedPostProcessor) {
this.removedPostProcessor = fromNullable(removedPostProcessor);
}
public void onNewPostReplies(PostReplyProcessor newPostReplyProcessor) {
this.newPostReplyProcessor = fromNullable(newPostReplyProcessor);
}
public void onRemovedPostReplies(
PostReplyProcessor removedPostReplyProcessor) {
this.removedPostReplyProcessor = fromNullable(removedPostReplyProcessor);
}
public void detectChanges(Sone newSone) {
processPosts(from(newSone.getPosts()).filter(
notContainedIn(oldSone.getPosts())), newPostProcessor);
processPosts(from(oldSone.getPosts()).filter(
notContainedIn(newSone.getPosts())), removedPostProcessor);
processPostReplies(from(newSone.getReplies()).filter(
notContainedIn(oldSone.getReplies())), newPostReplyProcessor);
processPostReplies(from(oldSone.getReplies()).filter(
notContainedIn(newSone.getReplies())), removedPostReplyProcessor);
}
private void processPostReplies(FluentIterable<PostReply> postReplies,
Optional<PostReplyProcessor> postReplyProcessor) {
for (PostReply postReply : postReplies) {
notifyPostReplyProcessor(postReplyProcessor, postReply);
}
}
private void notifyPostReplyProcessor(
Optional<PostReplyProcessor> postReplyProcessor,
PostReply postReply) {
if (postReplyProcessor.isPresent()) {
postReplyProcessor.get()
.processPostReply(postReply);
}
}
private void processPosts(FluentIterable<Post> posts,
Optional<PostProcessor> newPostProcessor) {
for (Post post : posts) {
notifyPostProcessor(newPostProcessor, post);
}
}
private void notifyPostProcessor(Optional<PostProcessor> postProcessor,
Post newPost) {
if (postProcessor.isPresent()) {
postProcessor.get().processPost(newPost);
}
}
private <T> Predicate<T> notContainedIn(final Collection<T> posts) {
return new Predicate<T>() {
@Override
public boolean apply(T element) {
return !posts.contains(element);
}
};
}
public interface PostProcessor {
void processPost(Post post);
}
public interface PostReplyProcessor {
void processPostReply(PostReply postReply);
}
}