package com.intellij.codeInsight.intention;

import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * @author dsl
 */
@NonNls
public class ConditionalOperatorConvertor extends PsiElementBaseIntentionAction implements IntentionAction {

  @NotNull
  public String getText() {
    return "Convert ternary operator to if statement";
  }

  @NotNull
  public String getFamilyName() {
    return getText();
  }

  public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) {
    if (element == null) return false;
    if (!element.isWritable()) return false;

    if (element instanceof PsiJavaToken) {
      final PsiJavaToken token = (PsiJavaToken) element;
      if (token.getTokenType() != JavaTokenType.QUEST) return false;
      if (token.getParent() instanceof PsiConditionalExpression) {
        final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression) token.getParent();
        if (conditionalExpression.getThenExpression() == null
            || conditionalExpression.getElseExpression() == null) {
          return false;
        }
        return true;
      }
      return false;
    }
    return false;
  }

  public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
    final int offset = editor.getCaretModel().getOffset();
    final PsiElement element = file.findElementAt(offset);
    PsiConditionalExpression conditionalExpression = PsiTreeUtil.getParentOfType(element,
                                                                                 PsiConditionalExpression.class, false);
    if (conditionalExpression == null) return;
    if (conditionalExpression.getThenExpression() == null || conditionalExpression.getElseExpression() == null) return;

    final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();

    PsiElement originalStatement = PsiTreeUtil.getParentOfType(conditionalExpression, PsiStatement.class, false);
    while (originalStatement instanceof PsiForStatement) {
      originalStatement = PsiTreeUtil.getParentOfType(originalStatement, PsiStatement.class, true);
    }
    if (originalStatement == null) return;

    // Maintain declrations
    if (originalStatement instanceof PsiDeclarationStatement) {
      final PsiDeclarationStatement declaration = (PsiDeclarationStatement) originalStatement;
      final PsiElement[] declaredElements = declaration.getDeclaredElements();
      PsiLocalVariable variable = null;
      for (PsiElement declaredElement : declaredElements) {
        if (declaredElement instanceof PsiLocalVariable &&
            PsiTreeUtil.isAncestor(declaredElement, conditionalExpression, true)) {
          variable = (PsiLocalVariable) declaredElement;
          break;
        }
      }
      if (variable == null) return;
      variable.normalizeDeclaration();
      final Object marker = new Object();
      PsiTreeUtil.mark(conditionalExpression, marker);
      PsiExpressionStatement statement =
          (PsiExpressionStatement) factory.createStatementFromText(variable.getName() + " = 0;", null);
      statement = (PsiExpressionStatement) CodeStyleManager.getInstance(project).reformat(statement);
      ((PsiAssignmentExpression) statement.getExpression()).getRExpression().replace(variable.getInitializer());
      variable.getInitializer().delete();
      final PsiElement variableParent = variable.getParent();
      originalStatement = variableParent.getParent().addAfter(statement, variableParent);
      conditionalExpression = (PsiConditionalExpression) PsiTreeUtil.releaseMark(originalStatement, marker);
    }

    // create then and else branches
    final PsiElement[] originalElements = new PsiElement[]{originalStatement, conditionalExpression};
    final PsiExpression condition = (PsiExpression) conditionalExpression.getCondition().copy();
    final PsiElement[] thenElements = PsiTreeUtil.copyElements(originalElements);
    final PsiElement[] elseElements = PsiTreeUtil.copyElements(originalElements);
    thenElements[1].replace(conditionalExpression.getThenExpression());
    elseElements[1].replace(conditionalExpression.getElseExpression());

    PsiIfStatement statement = (PsiIfStatement) factory.createStatementFromText("if (true) { a = b } else { c = d }",
                                                                                null);
    statement = (PsiIfStatement) CodeStyleManager.getInstance(project).reformat(statement);
    statement.getCondition().replace(condition);
    statement = (PsiIfStatement) originalStatement.replace(statement);

    ((PsiBlockStatement) statement.getThenBranch()).getCodeBlock().getStatements()[0].replace(thenElements[0]);
    ((PsiBlockStatement) statement.getElseBranch()).getCodeBlock().getStatements()[0].replace(elseElements[0]);
  }

  public boolean startInWriteAction() {
    return true;
  }
}

@@ -1583,17 +1583,23 @@
  Psi
-File file
+Element element
 ) th
@@ -1696,67 +1696,8 @@
 ();%0A
-    final PsiElement element = file.findElementAt(offset);%0A
     

Fix some platform API change