/**
  * Called after top level methods (and other items) have been moved from entries to
  * ruleInstanceList. Task now is to scan ruleInstanceList looking for MethodEntry objects with
  * dependent (related, extracted) methods. Move these from the entries list to the correct place
  * in the ruleInstanceList list.
  *
  * @param entries Remaining (unarranged) items, including all dependent (extracted) methods.
  * @param ruleInstance Rule containing parents (callers) of potentially related methods
  */
 public static void rearrangeRelatedItems(
     List<ClassContentsEntry> entries, RuleInstance ruleInstance, RelatedMethodsSettings rms) {
   List<RangeEntry> parentEntries = new ArrayList<RangeEntry>(ruleInstance.getMatches());
   for (RangeEntry o : parentEntries) {
     if (o instanceof RelatableEntry) {
       MethodEntry me = (MethodEntry) o;
       if (me.isGetter()) {
         if (me.myKeptWithProperty) {
           if (me.getMatchedRule() != null && me.getMatchedRule().getMatches() != null) {
             // prevent the getter from appearing under a rule it matches; it will be placed under
             // the property
             me.getMatchedRule().getMatches().remove(me);
           }
         }
         for (MethodEntry theSetter : me.myCorrespondingGetterSetters) {
           final RuleInstance theRule = theSetter.getMatchedRule();
           LOG.debug(
               "rearrangeRelatedItems: for getter method "
                   + me
                   + ", corresponding setter is "
                   + theSetter);
           if (theRule != null && theRule.getMatches() != null) {
             LOG.debug(
                 "remove entry "
                             + theSetter.myEnd
                             + " from matched rule"
                             + theRule
                             + "; matches = "
                             + ((java.util.List) theRule.getMatches())
                         == null
                     ? "null"
                     : "");
             theRule.getMatches().remove(theSetter);
           }
         }
       }
       if (me.myCalledMethods.size() > 0) {
         List<MethodEntry> parents = new LinkedList<MethodEntry>();
         parents.add(me);
         moveRelatedItems(
             entries,
             parents,
             rms,
             ((PsiMethod) me.myEnd).getName(),
             ((PsiMethod) me.myEnd).getName() + "()",
             1);
         if (LOG.isDebugEnabled()) {
           // dump sorted children recursively
           me.dumpChild(0);
         }
         me.assignComments(rms);
       }
     }
   }
 }
 /**
  * Set preceding and/or trailing comments on the appropriate methods, based on the comment type.
  *
  * @param rms
  * @param allMethodNames contains a list of methods invoked to reach this point. Top level is
  *     empty string.
  * @param level current nesting level; top level is 1.
  */
 private void assignComments(
     RelatedMethodsSettings rms,
     List<MethodEntry> allCallingMethods,
     String allMethodNames,
     int level) {
   final String currentMethodName = ((PsiMethod) myEnd).getName();
   String[] callingNames = new String[allCallingMethods.size()];
   for (int i = 0; i < allCallingMethods.size(); i++) {
     MethodEntry me = allCallingMethods.get(i);
     callingNames[i] = ((PsiMethod) me.myEnd).getName();
   }
   MethodEntry topLevel = this;
   while (topLevel.myCalledByMethods.size() > 0) {
     topLevel = (topLevel.myCalledByMethods.get(0));
   }
   switch (rms.getCommentType()) {
     case RelatedMethodsSettings.COMMENT_TYPE_TOP_LEVEL:
       customizedPrecedingComment =
           expandComment(
               rms.getPrecedingComment(),
               currentMethodName,
               allMethodNames,
               currentMethodName,
               level);
       MethodEntry last = this;
       while (last.sortedMethods.size() > 0) {
         last = (last.sortedMethods.get(last.sortedMethods.size() - 1));
       }
       last.customizedTrailingComment =
           expandComment(
               rms.getTrailingComment(),
               currentMethodName,
               allMethodNames,
               currentMethodName,
               level);
       break;
     case RelatedMethodsSettings.COMMENT_TYPE_EACH_METHOD:
       customizedPrecedingComment =
           expandComment(
               rms.getPrecedingComment(),
               currentMethodName,
               allMethodNames,
               ((PsiMethod) topLevel.myEnd).getName(),
               level);
       customizedTrailingComment =
           expandComment(
               rms.getTrailingComment(),
               currentMethodName,
               allMethodNames,
               ((PsiMethod) topLevel.myEnd).getName(),
               level);
       // recursively assign comments.
       for (MethodEntry methodEntry : sortedMethods) {
         String newAllMethodNames =
             appendMN(allMethodNames, callingNames, allCallingMethods, this, rms);
         methodEntry.assignComments(rms, sortedMethods, newAllMethodNames, level + 1);
       }
       break;
     case RelatedMethodsSettings.COMMENT_TYPE_NEW_FAMILY:
       {
         /**
          * Specialized routine to assign comments to "families" of methods. Insert a preceding
          * comment before every sibling except: when it is the first, and when the prior sibling
          * had no children and this sibling has no children.
          */
         MethodEntry firstEntry = null;
         MethodEntry previousEntry = null;
         for (MethodEntry methodEntry : allCallingMethods) {
           if (firstEntry == null) {
             firstEntry = methodEntry;
           } else if (methodEntry.sortedMethods.size() != 0
               || previousEntry.sortedMethods.size() != 0) {
             methodEntry.customizedPrecedingComment =
                 expandComment(
                     rms.getPrecedingComment(),
                     currentMethodName,
                     allMethodNames,
                     ((PsiMethod) topLevel.myEnd).getName(),
                     level);
           }
           previousEntry = methodEntry;
           if (methodEntry.sortedMethods.size() != 0) {
             String newAllMethodNames =
                 appendMN(allMethodNames, callingNames, allCallingMethods, methodEntry, rms);
             methodEntry.assignComments(
                 rms, methodEntry.sortedMethods, newAllMethodNames, level + 1);
           }
         }
       }
       break;
     case RelatedMethodsSettings.COMMENT_TYPE_EACH_LEVEL:
       {
         MethodEntry beginLevel = allCallingMethods.get(0);
         MethodEntry endLevel = allCallingMethods.get(allCallingMethods.size() - 1);
         beginLevel.customizedPrecedingComment =
             expandComment(
                 rms.getPrecedingComment(),
                 currentMethodName,
                 allMethodNames,
                 ((PsiMethod) topLevel.myEnd).getName(),
                 level);
         // recursively assign comments for each level.
         for (MethodEntry methodEntry : allCallingMethods) {
           if (methodEntry.sortedMethods.size() > 0) {
             String newAllMethodNames =
                 appendMN(allMethodNames, callingNames, allCallingMethods, methodEntry, rms);
             methodEntry.assignComments(
                 rms, methodEntry.sortedMethods, newAllMethodNames, level + 1);
           }
         }
         while (endLevel.sortedMethods.size() > 0) {
           endLevel = endLevel.sortedMethods.get(endLevel.sortedMethods.size() - 1);
         }
         if (endLevel.customizedTrailingComment.length() > 0) {
           endLevel.customizedTrailingComment += "\n";
         }
         endLevel.customizedTrailingComment +=
             expandComment(
                 rms.getTrailingComment(),
                 currentMethodName,
                 allMethodNames,
                 ((PsiMethod) topLevel.myEnd).getName(),
                 level);
       }
       break;
   }
 }