@Override
  public void handleInsert(InsertionContext context) {
    final Document document = context.getEditor().getDocument();
    document.replaceString(context.getStartOffset(), context.getTailOffset(), ";");
    final InsertionContext qualifierContext =
        CompletionUtil.emulateInsertion(context, context.getStartOffset(), myQualifier);
    OffsetKey oldStart = context.trackOffset(context.getStartOffset(), false);

    int start =
        CharArrayUtil.shiftForward(
            context.getDocument().getCharsSequence(), context.getStartOffset(), " \t\n");
    if (shouldParenthesizeQualifier(context.getFile(), start, qualifierContext.getTailOffset())) {
      final String space =
          CodeStyleSettingsManager.getSettings(qualifierContext.getProject())
                  .SPACE_WITHIN_PARENTHESES
              ? " "
              : "";
      document.insertString(start, "(" + space);
      document.insertString(qualifierContext.getTailOffset(), space + ")");
    }

    final char atTail = document.getCharsSequence().charAt(context.getTailOffset() - 1);
    if (atTail != ';') {
      LOG.error(
          LogMessageEx.createEvent(
              "Unexpected character",
              "atTail="
                  + atTail
                  + "\n"
                  + "offset="
                  + context.getTailOffset()
                  + "\n"
                  + "item="
                  + this
                  + "\n"
                  + "item.class="
                  + this.getClass()
                  + "\n"
                  + DebugUtil.currentStackTrace(),
              AttachmentFactory.createAttachment(context.getDocument())));
    }
    document.replaceString(context.getTailOffset() - 1, context.getTailOffset(), ".");

    CompletionUtil.emulateInsertion(getDelegate(), context.getTailOffset(), context);
    context.commitDocument();

    int formatStart = context.getOffset(oldStart);
    int formatEnd = context.getTailOffset();
    if (formatStart >= 0 && formatEnd >= 0) {
      CodeStyleManager.getInstance(context.getProject())
          .reformatText(context.getFile(), formatStart, formatEnd);
    }
  }
  private static void qualifyFieldReference(InsertionContext context, PsiField field) {
    context.commitDocument();
    PsiFile file = context.getFile();
    final PsiReference reference = file.findReferenceAt(context.getStartOffset());
    if (reference instanceof PsiJavaCodeReferenceElement
        && ((PsiJavaCodeReferenceElement) reference).isQualified()) {
      return;
    }

    PsiClass containingClass = field.getContainingClass();
    if (containingClass != null && containingClass.getName() != null) {
      OffsetKey oldStart = context.trackOffset(context.getStartOffset(), true);
      JavaCompletionUtil.insertClassReference(containingClass, file, context.getStartOffset());
      context.getDocument().insertString(context.getOffsetMap().getOffset(oldStart), ".");
      PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
    }
  }
  public static boolean promptTypeArgs(InsertionContext context, int offset) {
    if (offset < 0) {
      return false;
    }

    OffsetKey key = context.trackOffset(offset, false);
    PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting();
    offset = context.getOffset(key);
    if (offset < 0) {
      return false;
    }

    String open = escapeXmlIfNeeded(context, "<");
    context.getDocument().insertString(offset, open);
    context.getEditor().getCaretModel().moveToOffset(offset + open.length());
    context.getDocument().insertString(offset + open.length(), escapeXmlIfNeeded(context, ">"));
    context.setAddCompletionChar(false);
    return true;
  }
  public void handleInsert(
      final InsertionContext context, final JavaPsiClassReferenceElement item) {
    final char c = context.getCompletionChar();

    int offset = context.getTailOffset() - 1;
    final PsiFile file = context.getFile();
    if (PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiImportStatementBase.class, false)
        != null) {
      final PsiJavaCodeReferenceElement ref =
          PsiTreeUtil.findElementOfClassAtOffset(
              file, offset, PsiJavaCodeReferenceElement.class, false);
      final String qname = item.getQualifiedName();
      if (qname != null && (ref == null || !qname.equals(ref.getCanonicalText()))) {
        AllClassesGetter.INSERT_FQN.handleInsert(context, item);
      }
      return;
    }

    PsiElement position = file.findElementAt(offset);
    PsiClass psiClass = item.getObject();
    final Project project = context.getProject();
    final boolean annotation = insertingAnnotation(context, item);

    final Editor editor = context.getEditor();
    if (c == '#') {
      context.setLaterRunnable(
          new Runnable() {
            public void run() {
              new CodeCompletionHandlerBase(CompletionType.BASIC).invokeCompletion(project, editor);
            }
          });
    } else if (c == '.' && PsiTreeUtil.getParentOfType(position, PsiParameterList.class) == null) {
      AutoPopupController.getInstance(context.getProject())
          .autoPopupMemberLookup(context.getEditor(), null);
    }

    if (position != null) {
      PsiElement parent = position.getParent();
      if (parent instanceof PsiJavaCodeReferenceElement) {
        final PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement) parent;
        if (PsiTreeUtil.getParentOfType(position, PsiDocTag.class) != null
            && ref.isReferenceTo(psiClass)) {
          return;
        }
      }
    }

    OffsetKey refEnd = context.trackOffset(context.getTailOffset(), false);

    boolean fillTypeArgs = context.getCompletionChar() == '<';
    if (fillTypeArgs) {
      context.setAddCompletionChar(false);
    }

    if (shouldInsertParentheses(psiClass, position)) {
      if (ConstructorInsertHandler.insertParentheses(context, item, psiClass, false)) {
        fillTypeArgs |=
            psiClass.hasTypeParameters()
                && PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_5);
      }
    } else if (insertingAnnotationWithParameters(context, item)) {
      JavaCompletionUtil.insertParentheses(context, item, false, true);
      AutoPopupController.getInstance(project).autoPopupParameterInfo(editor, null);
    }

    LOG.assertTrue(context.getTailOffset() >= 0);
    String docText = context.getDocument().getText();
    DefaultInsertHandler.addImportForItem(context, item);
    if (context.getTailOffset() < 0) {
      LOG.error(
          LogMessageEx.createEvent(
              "Tail offset degraded after insertion",
              "start=" + context.getStartOffset(),
              new Attachment(
                  context.getFile().getViewProvider().getVirtualFile().getPath(), docText)));
    }

    if (annotation) {
      // Check if someone inserts annotation class that require @
      PsiElement elementAt = file.findElementAt(context.getStartOffset());
      final PsiElement parentElement = elementAt != null ? elementAt.getParent() : null;

      if (elementAt instanceof PsiIdentifier
          && (PsiTreeUtil.getParentOfType(elementAt, PsiAnnotationParameterList.class) != null
              || parentElement instanceof PsiErrorElement
                  && parentElement.getParent()
                      instanceof PsiJavaFile // top level annotation without @
          )
          && isAtTokenNeeded(context)) {
        int expectedOffsetForAtToken = elementAt.getTextRange().getStartOffset();
        context.getDocument().insertString(expectedOffsetForAtToken, "@");
      }
    }

    if (fillTypeArgs) {
      PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();
      int typeArgs = context.getOffset(refEnd);
      if (typeArgs >= 0) {
        context.getDocument().insertString(typeArgs, "<>");
        context.getEditor().getCaretModel().moveToOffset(typeArgs + 1);
      }
    }
  }