@Nullable
  public static PsiClass createSubclassGroovy(
      final GrTypeDefinition psiClass, final PsiDirectory targetDirectory, final String className) {
    final Project project = psiClass.getProject();
    final Ref<GrTypeDefinition> targetClass = new Ref<GrTypeDefinition>();

    new WriteCommandAction(project, getTitle(psiClass), getTitle(psiClass)) {
      @Override
      protected void run(Result result) throws Throwable {
        IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();

        final GrTypeParameterList oldTypeParameterList = psiClass.getTypeParameterList();

        try {
          targetClass.set(
              CreateClassActionBase.createClassByType(
                  targetDirectory,
                  className,
                  PsiManager.getInstance(project),
                  psiClass,
                  NewGroovyClassAction.GROOVY_CLASS));
        } catch (final IncorrectOperationException e) {
          ApplicationManager.getApplication()
              .invokeLater(
                  new Runnable() {
                    @Override
                    public void run() {
                      Messages.showErrorDialog(
                          project,
                          CodeInsightBundle.message(
                                  "intention.error.cannot.create.class.message", className)
                              + "\n"
                              + e.getLocalizedMessage(),
                          CodeInsightBundle.message("intention.error.cannot.create.class.title"));
                    }
                  });
          return;
        }
        startTemplate(oldTypeParameterList, project, psiClass, targetClass.get(), false);
        GrReferenceAdjuster.shortenReferences(targetClass.get());
      }
    }.execute();
    if (targetClass.get() == null) return null;
    if (!ApplicationManager.getApplication().isUnitTestMode() && !psiClass.hasTypeParameters()) {

      final Editor editor =
          CodeInsightUtil.positionCursor(
              project, targetClass.get().getContainingFile(), targetClass.get().getLBrace());
      if (editor == null) return targetClass.get();
      chooseAndImplement(psiClass, project, targetClass.get(), editor);
    }
    return targetClass.get();
  }
  private static void startTemplate(
      GrTypeParameterList oldTypeParameterList,
      final Project project,
      final GrTypeDefinition psiClass,
      final GrTypeDefinition targetClass,
      boolean includeClassName) {
    PsiElementFactory jfactory = JavaPsiFacade.getElementFactory(project);
    final GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(project);
    GrCodeReferenceElement ref = elementFactory.createCodeReferenceElementFromClass(psiClass);
    try {
      if (psiClass.isInterface()) {
        GrImplementsClause clause = targetClass.getImplementsClause();
        if (clause == null) {
          clause =
              (GrImplementsClause)
                  targetClass.addAfter(
                      elementFactory.createImplementsClause(),
                      targetClass.getNameIdentifierGroovy());
        }
        ref = (GrCodeReferenceElement) clause.add(ref);
      } else {
        GrExtendsClause clause = targetClass.getExtendsClause();
        if (clause == null) {
          clause =
              (GrExtendsClause)
                  targetClass.addAfter(
                      elementFactory.createExtendsClause(), targetClass.getNameIdentifierGroovy());
        }
        ref = (GrCodeReferenceElement) clause.add(ref);
      }
      if (psiClass.hasTypeParameters() || includeClassName) {
        final Editor editor =
            CodeInsightUtil.positionCursor(
                project, targetClass.getContainingFile(), targetClass.getLBrace());
        final TemplateBuilderImpl templateBuilder =
            editor == null || ApplicationManager.getApplication().isUnitTestMode()
                ? null
                : (TemplateBuilderImpl)
                    TemplateBuilderFactory.getInstance().createTemplateBuilder(targetClass);

        if (includeClassName && templateBuilder != null) {
          templateBuilder.replaceElement(targetClass.getNameIdentifier(), targetClass.getName());
        }

        if (oldTypeParameterList != null) {
          for (PsiTypeParameter parameter : oldTypeParameterList.getTypeParameters()) {
            final PsiElement param =
                ref.getTypeArgumentList()
                    .add(elementFactory.createTypeElement(jfactory.createType(parameter)));
            if (templateBuilder != null) {
              templateBuilder.replaceElement(param, param.getText());
            }
          }
        }

        final GrTypeParameterList typeParameterList = targetClass.getTypeParameterList();
        assert typeParameterList != null;
        typeParameterList.replace(oldTypeParameterList);

        if (templateBuilder != null) {
          templateBuilder.setEndVariableBefore(ref);
          final Template template = templateBuilder.buildTemplate();
          template.addEndVariable();

          final PsiFile containingFile = targetClass.getContainingFile();

          PsiDocumentManager.getInstance(project)
              .doPostponedOperationsAndUnblockDocument(editor.getDocument());

          final TextRange textRange = targetClass.getTextRange();
          final int startClassOffset = textRange.getStartOffset();
          editor.getDocument().deleteString(textRange.getStartOffset(), textRange.getEndOffset());
          CreateFromUsageBaseFix.startTemplate(
              editor,
              template,
              project,
              new TemplateEditingAdapter() {
                @Override
                public void templateFinished(Template template, boolean brokenOff) {
                  chooseAndImplement(
                      psiClass,
                      project,
                      PsiTreeUtil.getParentOfType(
                          containingFile.findElementAt(startClassOffset), GrTypeDefinition.class),
                      editor);
                }
              },
              getTitle(psiClass));
        }
      }
    } catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }