protected void toString(StringBuffer buffer) {
   boolean inlined = (this.flags & INLINED) != 0;
   if (inlined) buffer.append("	{"); // $NON-NLS-1$
   buffer.append('@');
   if (this.tagValue == TAG_OTHERS_VALUE) {
     buffer.append("others_tag"); // $NON-NLS-1$
   } else {
     buffer.append(TAG_NAMES[this.tagValue]);
   }
   super.toString(buffer);
   if (this.reference == null) {
     buffer.append('\n');
   } else {
     buffer.append(" ("); // $NON-NLS-1$
     this.reference.toString(buffer);
     buffer.append(")\n"); // $NON-NLS-1$
   }
   StringBuffer flagsBuffer = new StringBuffer();
   if (isDescription()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("description"); // $NON-NLS-1$
   }
   if (isFirst()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("first"); // $NON-NLS-1$
   }
   if (isHeaderLine()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("header line"); // $NON-NLS-1$
   }
   if (isImmutable()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("immutable"); // $NON-NLS-1$
   }
   if (isInDescription()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("in description"); // $NON-NLS-1$
   }
   if (isInlined()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("inlined"); // $NON-NLS-1$
   }
   if (isInParamTag()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("in param tag"); // $NON-NLS-1$
   }
   if (isOneLineTag()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("one line tag"); // $NON-NLS-1$
   }
   if (isParamTag()) {
     if (flagsBuffer.length() > 0) flagsBuffer.append(',');
     flagsBuffer.append("param tag"); // $NON-NLS-1$
   }
   if (flagsBuffer.length() > 0) {
     if (inlined) buffer.append('\t');
     buffer.append("	flags: "); // $NON-NLS-1$
     buffer.append(flagsBuffer);
     buffer.append('\n');
   }
   if (this.nodesPtr > -1) {
     for (int i = 0; i <= this.nodesPtr; i++) {
       if (inlined) buffer.append('\t');
       this.nodes[i].toString(buffer);
     }
   }
 }
 /*
  * 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;
 }