package com.dgex.offspring.ui.messaging; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import nxt.Account; import nxt.Transaction; import nxt.TransactionType; import nxt.util.DbIterator; import com.dgex.offspring.nxtCore.core.TransactionDB; import com.dgex.offspring.nxtCore.service.INxtService; public class MessageScanner { /** * The assumption is that all messages are scanned in order, whenever a * message is scanned that references another transaction, that other * transaction must be scanned before the current transaction. * * Presentation in the tree is such that 'root' messages are sorted * ASCENDENING, meaning the most recent message is at the top. * * Sub messages (messages in reply to another message) are sorted in * DESCENDING order, meaning that the reply to a message always comes below * the message that was replied to. */ private final IMessageNode rootNode = new MessageNodeImpl(null, null); private final Map<Long, IMessageNode> rootMap = new HashMap<Long, IMessageNode>(); private final Account account; private final String secretPhrase; private final INxtService nxt; public MessageScanner(Account account, String secretPhrase, INxtService nxt) { this.account = account; this.secretPhrase = secretPhrase; this.nxt = nxt; } public IMessageNode getNode() { return rootNode; } public void scan() { /* Scan the database */ TransactionType[] types = { TransactionType.Messaging.ARBITRARY_MESSAGE }; DbIterator<? extends Transaction> iterator = TransactionDB .getTransactionIterator(account.getId(), types, types, 0, Boolean.TRUE, null); while (iterator.hasNext()) { processTransaction(iterator.next()); } /* Add all pending transactions not yet in the database */ addPendingTransactions(); } private void addPendingTransactions() { /* Collect all pending Transactions that match */ List<Transaction> pending = new ArrayList<Transaction>(); for (Transaction t : nxt.getPendingTransactions()) { if (account.getId().equals(t.getSenderId()) || account.getId().equals(t.getRecipientId())) { if (t.getType().equals(TransactionType.Messaging.ARBITRARY_MESSAGE)) { pending.add(t); } } } if (pending.size() == 0) return; /* Collect pending transtactions that should no longer be pending */ List<Transaction> remove = new ArrayList<Transaction>(); List<Transaction> really_pending = new ArrayList<Transaction>(); for (Transaction t : pending) { if (rootMap.containsKey(t.getId())) { remove.add(t); } else { really_pending.add(t); } } /* Remove no-longer pending transactions */ for (Transaction t : remove) { nxt.getPendingTransactions().remove(t); pending.remove(t); } /* Add all really pending transactions */ for (Transaction t : really_pending) { processTransaction(t); } } private void processTransaction(Transaction transaction) { IMessageNode node; if (transaction.getReferencedTransactionId() == null) { node = new MessageNodeImpl(rootNode, new MessageWrapper(transaction, account, secretPhrase)); rootNode.getChildren().add(0, node); // sorted ASCENDENING } else { IMessageNode referencedNode = rootMap.get(transaction .getReferencedTransactionId()); if (referencedNode == null) { node = new MessageNodeImpl(rootNode, new MessageWrapper(transaction, account, secretPhrase)); rootNode.getChildren().add(0, node); // sorted ASCENDENING } else { node = new MessageNodeImpl(referencedNode, new MessageWrapper( transaction, account, secretPhrase)); referencedNode.getChildren().add(node); // sorted DESCENDING } } rootMap.put(transaction.getId(), node); } }