/**
   * Skips the scope opened by <code>token</code>.
   *
   * @param scanner the scanner
   * @param start the start position
   * @param token the token
   * @return the position after the scope or <code>JavaHeuristicScanner.NOT_FOUND</code>
   */
  private static int skipScope(JavaHeuristicScanner scanner, int start, int token) {
    int openToken = token;
    int closeToken;
    switch (token) {
      case Symbols.TokenLPAREN:
        closeToken = Symbols.TokenRPAREN;
        break;
      case Symbols.TokenLBRACKET:
        closeToken = Symbols.TokenRBRACKET;
        break;
      case Symbols.TokenLBRACE:
        closeToken = Symbols.TokenRBRACE;
        break;
      default:
        Assert.isTrue(false);
        return -1; // dummy
    }

    int depth = 1;
    int p = start;

    while (true) {
      int tok = scanner.nextToken(p, JavaHeuristicScanner.UNBOUND);
      p = scanner.getPosition();

      if (tok == openToken) {
        depth++;
      } else if (tok == closeToken) {
        depth--;
        if (depth == 0) return p + 1;
      } else if (tok == Symbols.TokenEOF) {
        return JavaHeuristicScanner.NOT_FOUND;
      }
    }
  }
  private int getPeerPosition(IDocument document, DocumentCommand command) {
    if (document.getLength() == 0) return 0;
    /*
     * Search for scope closers in the pasted text and find their opening peers
     * in the document.
     */
    Document pasted = new Document(command.text);
    installJavaStuff(pasted);
    int firstPeer = command.offset;

    JavaHeuristicScanner pScanner = new JavaHeuristicScanner(pasted);
    JavaHeuristicScanner dScanner = new JavaHeuristicScanner(document);

    // add scope relevant after context to peer search
    int afterToken =
        dScanner.nextToken(command.offset + command.length, JavaHeuristicScanner.UNBOUND);
    try {
      switch (afterToken) {
        case Symbols.TokenRBRACE:
          pasted.replace(pasted.getLength(), 0, "}"); // $NON-NLS-1$
          break;
        case Symbols.TokenRPAREN:
          pasted.replace(pasted.getLength(), 0, ")"); // $NON-NLS-1$
          break;
        case Symbols.TokenRBRACKET:
          pasted.replace(pasted.getLength(), 0, "]"); // $NON-NLS-1$
          break;
      }
    } catch (BadLocationException e) {
      // cannot happen
      Assert.isTrue(false);
    }

    int pPos = 0; // paste text position (increasing from 0)
    int dPos = Math.max(0, command.offset - 1); // document position (decreasing from paste offset)
    while (true) {
      int token = pScanner.nextToken(pPos, JavaHeuristicScanner.UNBOUND);
      pPos = pScanner.getPosition();
      switch (token) {
        case Symbols.TokenLBRACE:
        case Symbols.TokenLBRACKET:
        case Symbols.TokenLPAREN:
          pPos = skipScope(pScanner, pPos, token);
          if (pPos == JavaHeuristicScanner.NOT_FOUND) return firstPeer;
          break; // closed scope -> keep searching
        case Symbols.TokenRBRACE:
          int peer = dScanner.findOpeningPeer(dPos, '{', '}');
          dPos = peer - 1;
          if (peer == JavaHeuristicScanner.NOT_FOUND) return firstPeer;
          firstPeer = peer;
          break; // keep searching
        case Symbols.TokenRBRACKET:
          peer = dScanner.findOpeningPeer(dPos, '[', ']');
          dPos = peer - 1;
          if (peer == JavaHeuristicScanner.NOT_FOUND) return firstPeer;
          firstPeer = peer;
          break; // keep searching
        case Symbols.TokenRPAREN:
          peer = dScanner.findOpeningPeer(dPos, '(', ')');
          dPos = peer - 1;
          if (peer == JavaHeuristicScanner.NOT_FOUND) return firstPeer;
          firstPeer = peer;
          break; // keep searching
        case Symbols.TokenCASE:
        case Symbols.TokenDEFAULT:
          JavaIndenter indenter = new JavaIndenter(document, dScanner, fProject);
          peer = indenter.findReferencePosition(dPos, false, false, false, true);
          if (peer == JavaHeuristicScanner.NOT_FOUND) return firstPeer;
          firstPeer = peer;
          break; // keep searching

        case Symbols.TokenEOF:
          return firstPeer;
        default:
          // keep searching
      }
    }
  }
  private void smartIndentUponE(IDocument d, DocumentCommand c) {
    if (c.offset < 4 || d.getLength() == 0) return;

    try {
      String content = d.get(c.offset - 3, 3);
      if (content.equals("els")) { // $NON-NLS-1$
        JavaHeuristicScanner scanner = new JavaHeuristicScanner(d);
        int p = c.offset - 3;

        // current line
        int line = d.getLineOfOffset(p);
        int lineOffset = d.getLineOffset(line);

        // make sure we don't have any leading comments etc.
        if (d.get(lineOffset, p - lineOffset).trim().length() != 0) return;

        // line of last Java code
        int pos = scanner.findNonWhitespaceBackward(p - 1, JavaHeuristicScanner.UNBOUND);
        if (pos == -1) return;
        int lastLine = d.getLineOfOffset(pos);

        // only shift if the last java line is further up and is a braceless block candidate
        if (lastLine < line) {

          JavaIndenter indenter = new JavaIndenter(d, scanner, fProject);
          int ref = indenter.findReferencePosition(p, true, false, false, false);
          if (ref == JavaHeuristicScanner.NOT_FOUND) return;
          int refLine = d.getLineOfOffset(ref);
          String indent = getIndentOfLine(d, refLine);

          if (indent != null) {
            c.text = indent.toString() + "else"; // $NON-NLS-1$
            c.length += c.offset - lineOffset;
            c.offset = lineOffset;
          }
        }

        return;
      }

      if (content.equals("cas")) { // $NON-NLS-1$
        JavaHeuristicScanner scanner = new JavaHeuristicScanner(d);
        int p = c.offset - 3;

        // current line
        int line = d.getLineOfOffset(p);
        int lineOffset = d.getLineOffset(line);

        // make sure we don't have any leading comments etc.
        if (d.get(lineOffset, p - lineOffset).trim().length() != 0) return;

        // line of last Java code
        int pos = scanner.findNonWhitespaceBackward(p - 1, JavaHeuristicScanner.UNBOUND);
        if (pos == -1) return;
        int lastLine = d.getLineOfOffset(pos);

        // only shift if the last java line is further up and is a braceless block candidate
        if (lastLine < line) {

          JavaIndenter indenter = new JavaIndenter(d, scanner, fProject);
          int ref = indenter.findReferencePosition(p, false, false, false, true);
          if (ref == JavaHeuristicScanner.NOT_FOUND) return;
          int refLine = d.getLineOfOffset(ref);
          int nextToken = scanner.nextToken(ref, JavaHeuristicScanner.UNBOUND);
          String indent;
          if (nextToken == Symbols.TokenCASE || nextToken == Symbols.TokenDEFAULT)
            indent = getIndentOfLine(d, refLine);
          else // at the brace of the switch
          indent = indenter.computeIndentation(p).toString();

          if (indent != null) {
            c.text = indent.toString() + "case"; // $NON-NLS-1$
            c.length += c.offset - lineOffset;
            c.offset = lineOffset;
          }
        }

        return;
      }

    } catch (BadLocationException e) {
      JavaPlugin.log(e);
    }
  }