package iamrescue.communication;
import iamrescue.communication.messages.Message;
import iamrescue.communication.messages.MessageChannel;
import iamrescue.communication.messages.filter.IsSentMessageFilter;
import iamrescue.communication.messages.filter.NonZeroTTLFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections15.Predicate;
import org.apache.commons.collections15.functors.AndPredicate;
import org.apache.commons.collections15.functors.NotPredicate;
/**
* A class that is responsible for storing outgoing messages, without any
* intelligence.
*
* @author Ruben Stranders
*
*/
public class Outbox {
// /**
// * A queue of messages to be shouted
// */
// private List<Message> shoutMessageQ = new ArrayList<Message>();
/**
* For each channel, a queue of messages to be sent over radio
*/
private Map<MessageChannel, List<Message>> messageQs = new HashMap<MessageChannel, List<Message>>();
private Map<Integer, MessageChannel> channelNumbers = new HashMap<Integer, MessageChannel>();
private boolean sorted = false;
// private static Log log = LogFactory.getLog(Outbox.class);
/**
* Sorts messages based on priority. Messages with high priority go at the
* start of the list
*/
private static Comparator<Message> messagePriorityComparator = new Comparator<Message>() {
public int compare(Message o1, Message o2) {
return o2.getPriority().compareTo(o1.getPriority());
}
};
private static Predicate<Message> retentionFilter = AndPredicate
.getInstance(new NonZeroTTLFilter(), NotPredicate
.getInstance(new IsSentMessageFilter()));
public Outbox(List<MessageChannel> channels) {
initializeChannels(channels);
}
/**
* Enqueues a message for transmission
*/
public void enqueueMessage(Message message, MessageChannel channel) {
sorted = false;
messageQs.get(channel).add(message);
}
public Collection<Message> getMessageQ(MessageChannel channel) {
List<Message> list = messageQs.get(channel);
if (!sorted) {
Collections.sort(list, messagePriorityComparator);
}
// Mark as dirty, since other parts of the code modify this.
sorted = false;
return list;
}
public void removeSentAndStaleMessages() {
// decrease TTL for all remaining messages by 1
for (List<Message> messageQ : messageQs.values()) {
for (Message message : messageQ) {
message.setTTL(message.getTTL() - 1);
}
}
for (List<Message> messageQ : messageQs.values()) {
Iterator<Message> iterator = messageQ.iterator();
while (iterator.hasNext()) {
Message message = iterator.next();
if (message.getTTL() <= 0 || message.isSent()) {
iterator.remove();
}
}
}
}
private void initializeChannels(List<MessageChannel> channels) {
for (MessageChannel channel : channels) {
messageQs.put(channel, new ArrayList<Message>());
channelNumbers.put(channel.getChannelNumber(), channel);
}
}
public Map<MessageChannel, List<Message>> getMessageQs() {
sortByPriority();
// Mark as dirty, since other parts of the code modify this.
sorted = false;
return messageQs;
}
public Set<MessageChannel> getChannels() {
return messageQs.keySet();
}
public Object getMessagesToString(boolean verbose) {
sortByPriority();
StringBuilder builder = new StringBuilder();
for (MessageChannel queue : messageQs.keySet()) {
builder.append("\nQueue: ");
builder.append(queue.getChannelNumber());
builder.append(':');
if (verbose) {
builder.append('\n');
}
for (Message message : messageQs.get(queue)) {
builder.append(" ");
if (verbose) {
builder.append(message.toString());
builder.append('\n');
} else {
builder.append(message.toShortString());
builder.append(',');
}
}
}
return builder.toString();
}
public MessageChannel getChannel(int channelNumber) {
return channelNumbers.get(channelNumber);
}
public void sortByPriority() {
if (!sorted) {
for (List<Message> radioMessageQ : messageQs.values()) {
Collections.sort(radioMessageQ, messagePriorityComparator);
}
sorted = true;
}
}
}