package org.sakaiproject.tool.messageforums.entityproviders.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.sakaiproject.api.app.messageforums.ui.DiscussionForumManager;
import org.sakaiproject.tool.messageforums.entityproviders.sparsepojos.SparseMessage;
import org.sakaiproject.tool.messageforums.entityproviders.sparsepojos.SparseThread;
/**
* A helper class for arranging messages into their proper parent child relationships.
*
* @author Adrian Fish <adrian.r.fish@gmail.com>
*/
public class MessageUtils {
/**
* Extracts the threads (messages with no parent) from the supplied messages and sets
* the message totals up on each of them.
*
* @param sparseForum The SparseForum to extract the threads from
* @param forumManager We need this to the get the read stati for the accumulated message ids.
* @param userId We need this to the get the read stati for the accumulated message ids.
*/
public List<SparseThread> getThreadsWithCounts(List<SparseMessage> messages,DiscussionForumManager forumManager, String userId) {
List<Long> messageIds = new ArrayList<Long>();
// Find the top level threads, the messages with no parent, basically.
List<SparseThread> threads = new ArrayList<SparseThread>();
for (SparseMessage message : messages) {
if(message.isDraft() || message.isDeleted()) {
continue;
}
messageIds.add(message.getMessageId());
if(message.getReplyTo() == null) {
threads.add(new SparseThread(message));
}
}
Map<Long,Boolean> readStati = forumManager.getReadStatusForMessagesWithId(messageIds, userId);
for(SparseMessage thread : threads) {
boolean read = readStati.get(thread.getMessageId());
Counts counts = new Counts(1,(read) ? 1 : 0);
thread.setRead(read);
// We don't want to add the messages and bulk up the resulting JSON feed. We
// still want the total and unread messages counts for this thread though.
setupCounts(thread,messages,readStati,counts);
thread.setTotalMessages(counts.total);
thread.setReadMessages(counts.read);
}
return threads;
}
/**
* Sets up the message hierarchy for topMessage.
*
* @param topMessage The topmost message that we want to setup the message graph for
* @param messages The flat list of messages that we want to insert into the hierarchy
* @param forumManager We need this to the get the read stati for the accumulated message ids.
* @param userId We need this to the get the read stati for the accumulated message ids.
*/
public void attachReplies(SparseMessage topMessage, List<SparseMessage> messages,DiscussionForumManager forumManager, String userId) {
List<Long> messageIds = new ArrayList<Long>();
for (SparseMessage message : messages) {
messageIds.add(message.getMessageId());
}
Map<Long,Boolean> readStati = forumManager.getReadStatusForMessagesWithId(messageIds, userId);
boolean read = readStati.get(topMessage.getMessageId());
topMessage.setRead(read);
Counts counts = new Counts(1,(read) ? 1 : 0);
addReplies(topMessage,messages,readStati,counts);
topMessage.setTotalMessages(counts.total);
topMessage.setReadMessages(counts.read);
}
/**
* Does a depth first recursion into the messages list, looking for replies
* to the specified parent.
*
* @param parent
* @param messages
*/
private void addReplies(SparseMessage parent,List<SparseMessage> messages, Map<Long,Boolean> readStati,Counts counts) {
for (SparseMessage message : messages) {
if(message.isDraft() || message.isDeleted()) {
continue;
}
if(message.getReplyTo() != null
&& message.getReplyTo().equals(parent.getMessageId())) {
counts.total = counts.total + 1;
boolean read = readStati.get(message.getMessageId());
message.setRead(read);
if(read) {
counts.read = counts.read + 1;
}
parent.addReply(message);
// Recurse
addReplies(message,messages, readStati,counts);
}
}
}
/**
* Recursively iterates over the messages and increments the counts accumulator if any of them
* are a reply to the parent. The idea is to finally exit with a set of totals for an ancestor.
*
* @param parent The message for which to look for replies.
* @param messages The flatted list of messages to search.
* @param readStati The pre-retrieved list of read stati for the messsage list.
* @param counts An accumulator of message counts
*/
private void setupCounts(SparseMessage parent,List<SparseMessage> messages, Map<Long,Boolean> readStati,Counts counts) {
for (SparseMessage message : messages) {
if(message.isDraft() || message.isDeleted()) {
continue;
}
if(message.getReplyTo() != null
&& message.getReplyTo().equals(parent.getMessageId())) {
counts.total = counts.total + 1;
if(readStati.get(message.getMessageId())) {
counts.read = counts.read + 1;
}
// Recurse
setupCounts(message,messages, readStati,counts);
}
}
}
public class Counts {
public int total = 0;
public int read = 0;
public Counts(int total,int read) {
this.total = total;
this.read = read;
}
}
}