/**
  * Finds the parent of a blip. The parent is the preceding blip in the thread, or the blip to
  * which the thread is a reply for the first blip in a thread. The first blip of the root thread
  * has no parent.
  *
  * @param blip the blip.
  * @return the blip's parent, or {@code null} if the blip is the first blip in a conversation.
  */
 @Override
 public ConversationBlip findBlipParent(ConversationBlip blip) {
   ConversationThread containingThread = blip.getThread();
   if (containingThread.getFirstBlip() == blip
       && containingThread != blip.getConversation().getRootThread()) {
     return containingThread.getParentBlip();
   }
   return findPreviousSibling(blip);
 }
 /**
  * Retrieves the title of a {@link Wavelet}.
  *
  * @param wavelet The {@link Wavelet} to retrieve the title from.
  * @param conversation The wavelet conversation
  * @return the title of the {@link Wavelet}, or an empty string if it has no title.
  */
 private static String getTitle(Wavelet wavelet, Conversation conversation) {
   ConversationThread rootThread = conversation.getRootThread();
   if (rootThread == null) {
     return "";
   }
   ConversationBlip firstBlip = rootThread.getFirstBlip();
   if (firstBlip == null) {
     return "";
   }
   Document doc = firstBlip.getContent();
   return TitleHelper.extractTitle(doc);
 }
 /**
  * Finds the next sibling of a blip in a thread. The last blip in a thread has no next sibling.
  *
  * @param blip the blip.
  * @return the next sibling of the blip, or {@code null} if blip is the last blip in a thread.
  */
 @VisibleForTesting
 static ConversationBlip findNextSibling(ConversationBlip blip) {
   ConversationThread thread = blip.getThread();
   Iterator<? extends ConversationBlip> blips = thread.getBlips().iterator();
   boolean foundBlip = false;
   while (!foundBlip && blips.hasNext()) {
     if (blips.next() == blip) {
       foundBlip = true;
     }
   }
   return blips.hasNext() ? blips.next() : null;
 }
 /**
  * Finds the previous sibling of a blip in a thread. The first blip in a thread has no previous
  * sibling.
  *
  * @param blip the blip.
  * @return the previous sibling of the blip, or {@code null}.
  */
 @VisibleForTesting
 static ConversationBlip findPreviousSibling(ConversationBlip blip) {
   ConversationThread thread = blip.getThread();
   ConversationBlip previous = null;
   for (ConversationBlip sibling : thread.getBlips()) {
     if (sibling == blip) {
       break;
     }
     previous = sibling;
   }
   return previous;
 }
 /**
  * Finds the children of a blip, defined as the next sibling blip and the first blip in each reply
  * thread.
  *
  * @param blip the blip.
  * @return the children of the given blip.
  */
 @Override
 public List<ConversationBlip> findBlipChildren(ConversationBlip blip) {
   List<ConversationBlip> siblings = Lists.newArrayList();
   ConversationBlip nextSibling = findNextSibling(blip);
   if (nextSibling != null) {
     siblings.add(nextSibling);
   }
   for (ConversationThread reply : blip.getReplyThreads()) {
     if (reply.getFirstBlip() != null) {
       siblings.add(reply.getFirstBlip());
     }
   }
   return siblings;
 }