void addBlock(FormatJavadocBlock block, int htmlLevel) {
   if (this.nodes != null) {
     FormatJavadocText[] textHierarchy = getTextHierarchy(block, htmlLevel);
     if (textHierarchy != null) {
       FormatJavadocText lastText = textHierarchy[htmlLevel];
       if (lastText != null) {
         lastText.appendNode(block);
         for (int i = htmlLevel - 1; i >= 0; i--) {
           textHierarchy[i].sourceEnd = block.sourceEnd;
         }
         this.sourceEnd = block.sourceEnd;
         if (isParamTag()) {
           block.flags |= IN_PARAM_TAG;
         } else if (isDescription()) {
           block.flags |= IN_DESCRIPTION;
         }
         block.flags |= INLINED;
         return;
       }
     }
   }
   addNode(block);
   if (isParamTag()) {
     block.flags |= IN_PARAM_TAG;
   } else if (isDescription()) {
     block.flags |= IN_DESCRIPTION;
   }
   block.flags |= INLINED;
 }
 void addText(FormatJavadocText text) {
   if (this.nodes != null) {
     FormatJavadocText[] textHierarchy = getTextHierarchy(text, text.depth);
     if (textHierarchy != null) {
       FormatJavadocText lastText = textHierarchy[text.depth];
       if (lastText != null) {
         lastText.appendText(text);
         for (int i = text.depth - 1; i >= 0; i--) {
           textHierarchy[i].sourceEnd = text.sourceEnd;
         }
         this.sourceEnd = text.sourceEnd;
         return;
       }
       if (text.depth > 0) {
         FormatJavadocText parentText = textHierarchy[text.depth - 1];
         if (parentText != null) {
           parentText.appendText(text);
           for (int i = text.depth - 2; i >= 0; i--) {
             textHierarchy[i].sourceEnd = text.sourceEnd;
           }
           this.sourceEnd = text.sourceEnd;
           return;
         }
       }
     }
   }
   if (text.isHtmlTag()) {
     switch (text.getHtmlTagID()) {
       case JAVADOC_CODE_TAGS_ID:
         text.linesBefore = this.nodesPtr == -1 ? 0 : 2;
         break;
       case JAVADOC_SEPARATOR_TAGS_ID:
         text.linesBefore = 1;
         break;
         //	    	case JAVADOC_BREAK_TAGS_ID:
         //				if (this.nodesPtr >= 0) text.linesBefore = 1;
     }
   }
   addNode(text);
   if (isImmutable()) {
     text.immutable = true;
   }
 }
 /*
  * Return the text hierarchy for the given node
  */
 FormatJavadocText[] getTextHierarchy(FormatJavadocNode node, int htmlDepth) {
   if (this.nodes == null) return null;
   FormatJavadocText[] textHierarchy = null;
   int ptr = 0;
   FormatJavadocText text = node.isText() ? (FormatJavadocText) node : null;
   FormatJavadocNode lastNode = this.nodes[this.nodesPtr];
   while (lastNode.isText()) {
     FormatJavadocText lastText = (FormatJavadocText) lastNode;
     int lastTagCategory = lastText.getHtmlTagID();
     boolean lastSingleTag = lastTagCategory <= JAVADOC_SINGLE_TAGS_ID;
     boolean lastTextCanHaveChildren =
         lastText.isHtmlTag() && !lastText.isClosingHtmlTag() && !lastSingleTag;
     if (lastText.depth == htmlDepth
         || // found same html tag level => use it
         lastText.htmlNodesPtr == -1) { // no more sub-levels => add one
       // Text breakage
       if (lastText.isHtmlTag() && text != null) {
         // Set some lines before if previous was specific html tag
         // The added text is concerned if the parent has no child yet or is top level and closing
         // html tag
         boolean setLinesBefore =
             lastText.separatorsPtr == -1 || (ptr == 0 && lastText.isClosingHtmlTag());
         if (!setLinesBefore && ptr > 0 && lastText.isClosingHtmlTag()) {
           // for non-top level closing html tag, text is concerned only if no new text has been
           // written after
           FormatJavadocText parentText = textHierarchy[ptr - 1];
           int textStart = (int) parentText.separators[parentText.separatorsPtr];
           if (textStart < lastText.sourceStart) {
             setLinesBefore = true;
           }
         }
         if (setLinesBefore) {
           switch (lastText.getHtmlTagID()) {
             case JAVADOC_CODE_TAGS_ID:
               if (text.linesBefore < 2) {
                 text.linesBefore = 2;
               }
               break;
             case JAVADOC_SEPARATOR_TAGS_ID:
             case JAVADOC_SINGLE_BREAK_TAG_ID:
               if (text.linesBefore < 1) {
                 text.linesBefore = 1;
               }
           }
         }
         // If adding an html tag on same html tag, then close previous one and leave
         if (text.isHtmlTag()
             && !text.isClosingHtmlTag()
             && text.getHtmlTagIndex() == lastText.getHtmlTagIndex()
             && !lastText.isClosingHtmlTag()) {
           lastText.closeTag();
           return textHierarchy;
         }
       }
       // If we have a text after another text, keep the same level to append
       if (lastTextCanHaveChildren
           || (htmlDepth == 0 && !lastText.isHtmlTag() && text != null && !text.isHtmlTag())) {
         if (textHierarchy == null) textHierarchy = new FormatJavadocText[htmlDepth + 1];
         textHierarchy[ptr] = lastText;
         return textHierarchy;
       }
       // Last text cannot have children, so return the built hierarchy
       return textHierarchy;
     }
     if (textHierarchy == null) textHierarchy = new FormatJavadocText[htmlDepth + 1];
     textHierarchy[ptr++] = lastText;
     lastNode = lastText.htmlNodes[lastText.htmlNodesPtr];
   }
   return textHierarchy;
 }