/**
   * Highlights this paragraph as a string of given type
   *
   * @param stringIndex the type
   * @return true if we have found a string-end
   */
  public boolean highlightAsString(Object stringIndex) {
    Highlighter hl = getHighlighter();
    String pText = _para.getText();
    Map strTypes = hl.getStringQuotes();
    TextAttributes attributes = hl.getStringAttributes(stringIndex);

    // clear all types because we determine them again
    _hlTypes.clear();

    char c = ((Character) strTypes.get(stringIndex)).charValue();
    int p = 0;
    int eIndex;
    do {
      eIndex = pText.indexOf(c, p);

      // search for string-end
      if (eIndex >= 0 && !StringUtils.isEscaped(pText, eIndex, hl.getEscapeChar())) {
        _hlTypes.add(new HighlightType(HighlightType.CONTAINS_STRING_END, stringIndex));

        // mark visible area
        _visibleArea.setStart(eIndex + 1);
        _visibleArea.setEnd();
        highlightText(0, eIndex + 1, attributes, pText);

        // mark paragraph-content as dirty (highlightDefault() might do nothing)
        _para.getTextField().getViewManager().markParagraphDirty(_para);

        // highlight the rest, by default
        highlightDefault();
        return true;
      }

      p = eIndex + 1;
    } while (eIndex >= 0);

    // ok, no string-end, so we are in the string
    _visibleArea.setInvisible();
    highlightText(0, _para.getElementLength(), attributes, pText);
    _para.getTextField().getViewManager().markParagraphDirty(_para);

    _hlTypes.add(new HighlightType(HighlightType.CONTAINS_STRING, stringIndex));
    return false;
  }
  /**
   * Highlights this paragraph as a comment of given type
   *
   * @param commentId the type
   * @return true if we have found a comment-end
   */
  public boolean highlightAsComment(Object commentId) {
    Highlighter hl = getHighlighter();
    String pText = _para.getText();
    Map mlTypes = hl.getMultiCommentLimiters();
    TextAttributes attributes = hl.getMLCommentAttributes(commentId);

    // clear all types because we determine them again
    _hlTypes.clear();

    Pair p = (Pair) mlTypes.get(commentId);

    String end = (String) p.getValue();
    int eIndex = pText.indexOf(end);

    // have we found the comment-end?
    if (eIndex >= 0) {
      _hlTypes.add(new HighlightType(HighlightType.CONTAINS_COMMENT_END, commentId));

      // mark the visible area
      _visibleArea.setStart(eIndex + end.length());
      _visibleArea.setEnd();
      highlightText(0, eIndex + end.length(), attributes, pText);

      // mark paragraph-content as dirty (highlightDefault() might do nothing)
      _para.getTextField().getViewManager().markParagraphDirty(_para);

      // highlight the rest by default
      highlightDefault();
      return true;
    }

    // ok, no comment-end, so we are in a comment
    _visibleArea.setInvisible();
    highlightText(0, _para.getElementLength(), attributes, pText);
    _para.getTextField().getViewManager().markParagraphDirty(_para);

    _hlTypes.add(new HighlightType(HighlightType.CONTAINS_COMMENT, commentId));
    return false;
  }
  /** Performs the default-highlighting. */
  private void highlightDefault() {
    // is there nothing to do?
    if (_visibleArea.isInvisible() || _para.getElementLength() == 0) return;

    Highlighter hl = getHighlighter();
    String pText = _para.getText();

    List deniedAreas = new ArrayList();
    TextAttributes attributes;

    // grab some vars from the highlighter
    Map mlTypes = hl.getMultiCommentLimiters();
    Map slTypes = hl.getSingleComments();
    Map strQuotes = hl.getStringQuotes();
    char escChar = hl.getEscapeChar();
    Point area = _visibleArea.getArea(_para);

    // at first we clear the not-denied intervals
    attributes = new TextAttributes();
    highlightText(area.x, area.y, attributes, pText);

    // init some flags and vars
    int cStart = -1;
    int sStart = -1;
    char sStartChar = 0;
    Object stringId = null;
    Object commentId = null;
    boolean inStr = false;
    boolean inComment = false;
    boolean foundSLC = false;

    // search for multiline comments and strings
    for (int i = area.x, len = area.y; i < len; i++) {
      char c = pText.charAt(i);

      // search for strings
      Object strId = null;
      if (!inComment
          && (strId = getStringId(strQuotes, c)) != null
          && !StringUtils.isEscaped(pText, i, escChar)) {
        // is it a closing char?
        if (c == sStartChar && inStr) {
          inStr = false;
          TextAttributes strAttrs = hl.getStringAttributes(strId);
          highlightText(sStart, i + 1, strAttrs, pText);
          deniedAreas.add(new Point(sStart, i + 1));
        }
        // just add the start if it is a real start (not in other elements)
        else if (!inStr) {
          sStart = i;
          sStartChar = c;
          stringId = strId;
          inStr = true;
        }

        continue;
      }

      // don't search comments in strings
      if (!inStr) {
        if (!inComment) {
          // search for single-line-comments
          Object slStartId = getSLCommentStart(slTypes, pText, i);
          if (slStartId != null) {
            // if there is one, highlight it and break here
            TextAttributes slAttrs = hl.getSLCommentAttributes(slStartId);
            highlightText(i, _para.getElementLength(), slAttrs, pText);
            foundSLC = true;
            deniedAreas.add(new Point(i, _para.getElementLength()));
            break;
          }

          // search for comment-start-tags
          Object startTagId = getCommentStart(mlTypes, pText, i);
          if (startTagId != null) {
            cStart = i;
            inComment = true;
            commentId = startTagId;
            continue;
          }
        }

        // search for comment-end-tags
        Object endTagId = getCommentEnd(mlTypes, pText, i);
        if (endTagId != null) {
          // is the comment-start also in this paragraph?
          if (inComment) {
            if (mlTypes.get(commentId).equals(mlTypes.get(endTagId))) {
              inComment = false;
              TextAttributes mlAttrs = hl.getMLCommentAttributes(endTagId);
              highlightText(cStart, i + 2, mlAttrs, pText);
              deniedAreas.add(new Point(cStart, i + 2));
            }
          }
        }
      }
    }

    // is a comment not closed?
    if (inComment && (!inStr || sStart > cStart)) {
      _visibleArea.setEnd(cStart);
      TextAttributes mlAttrs = hl.getMLCommentAttributes(commentId);
      highlightText(cStart, _para.getElementLength(), mlAttrs, pText);
    }
    // is a string not closed?
    else if (inStr) {
      _visibleArea.setEnd(sStart);
      TextAttributes strAttrs = hl.getStringAttributes(stringId);
      highlightText(sStart, _para.getElementLength(), strAttrs, pText);
    }

    String pLower = pText.toLowerCase();

    // replace keywords
    Map keywords = hl.getKeywords();
    Iterator it = keywords.entrySet().iterator();
    while (it.hasNext()) {
      Entry e = (Entry) it.next();
      StringTreeMap treeMap = (StringTreeMap) e.getValue();
      KeywordSettings settings = hl.getKeywordSettings(e.getKey());
      replaceWords(
          treeMap,
          settings.isCaseSensitive() ? pText : pLower,
          hl.getKeywordAttributes(e.getKey()),
          deniedAreas,
          settings.isCaseSensitive(),
          settings.requireWord());
    }

    // numbers
    if (hl.highlightNumbers()) {
      attributes = hl.getAttributes(Highlighter.NUMBER);
      Pattern p = _numberPattern;
      if (p == null) {
        p = Pattern.compile("\\b-?(\\d+|\\d*\\.\\d+)\\b");
        _numberPattern = p;
      }

      Matcher m = p.matcher(pText);
      while (m.find()) {
        String match = m.group();
        int start = m.start();
        int end = start + match.length();

        // highlight, if the area is not denied
        if (!isInDeniedArea(deniedAreas, start, end)) {
          highlightText(start, end, attributes, pText);
          deniedAreas.add(new Point(start, end));
        }
      }
    }

    // symbols
    replaceWords(
        hl.getSymbols(), pLower, hl.getAttributes(Highlighter.SYMBOL), deniedAreas, true, false);

    // other regeexps
    if (hl.getRegexps().size() > 0) {
      Map regexps = hl.getRegexps();
      it = regexps.entrySet().iterator();
      while (it.hasNext()) {
        Entry e = (Entry) it.next();
        attributes = hl.getRegexpAttributes(e.getKey());
        RegExDesc regex = (RegExDesc) e.getValue();

        // find matches
        Matcher m = regex.getPattern().matcher(pText);
        while (m.find()) {
          String match = m.group(regex.getGroup());
          int start = m.start(regex.getGroup());
          int end = start + match.length();

          // highlight, if the area is not denied
          if (!isInDeniedArea(deniedAreas, start, end)) {
            highlightText(start, end, attributes, pText);
          }
        }
      }
    }

    removeStrings();
    removeStringStarts();
    removeComments();
    removeCommentStarts();

    // mark the paragraph-content as dirty, because applyAttributes() does not
    // mark the sections as dirty!
    _para.getTextField().getViewManager().markParagraphDirty(_para);

    // comment-start?
    if (inComment && (!inStr || sStart > cStart)) {
      if (_visibleArea.isVisible(cStart))
        _hlTypes.add(new HighlightType(HighlightType.CONTAINS_OTHER));

      _hlTypes.add(new HighlightType(HighlightType.CONTAINS_COMMENT_START, commentId));
      return;
    }

    // open string?
    if (inStr && !foundSLC) {
      if (_visibleArea.isVisible(sStart))
        _hlTypes.add(new HighlightType(HighlightType.CONTAINS_OTHER));

      _hlTypes.add(
          new HighlightType(
              HighlightType.CONTAINS_STRING_START, getStringId(strQuotes, sStartChar)));
      return;
    }

    // default
    removeOther();
    _hlTypes.add(new HighlightType(HighlightType.CONTAINS_OTHER));
    _visibleArea.setEnd();
  }