/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package vgrechka.phizdetsidea.phizdets.codeInsight.intentions;

import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import vgrechka.phizdetsidea.phizdets.PyBundle;
import vgrechka.phizdetsidea.phizdets.PyTokenTypes;
import vgrechka.phizdetsidea.phizdets.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

/**
 * User: catherine
 * Intention to merge the if clauses in the case of nested ifs where only the inner if contains code (the outer if only contains the inner one)
 * For instance,
 * if a:
 *   if b:
 *    # stuff here
 * into
 * if a and b:
 *   #stuff here
 */
public class PyJoinIfIntention extends PyBaseIntentionAction {
  @NotNull
  public String getFamilyName() {
    return PyBundle.message("INTN.join.if");
  }

  @NotNull
  public String getText() {
    return PyBundle.message("INTN.join.if.text");
  }

  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    if (!(file instanceof PyFile)) {
      return false;
    }

    PyIfStatement expression =
      PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyIfStatement.class);

    PyIfStatement outer = getIfStatement(expression);
    if (outer != null) {
      if (outer.getElsePart() != null || outer.getElifParts().length > 0) return false;
      PyStatement firstStatement = getFirstStatement(outer);
      PyStatementList outerStList = outer.getIfPart().getStatementList();
      if (outerStList != null && outerStList.getStatements().length != 1) return false;
      if (firstStatement instanceof PyIfStatement) {
        final PyIfStatement inner = (PyIfStatement)firstStatement;
        if (inner.getElsePart() != null || inner.getElifParts().length > 0) return false;
        PyStatementList stList = inner.getIfPart().getStatementList();
        if (stList != null)
          if (stList.getStatements().length != 0)
            return true;
      }
    }
    return false;
  }

  public void doInvoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
    PyIfStatement expression =
          PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyIfStatement.class);
    PyIfStatement ifStatement = getIfStatement(expression);

    PyStatement firstStatement = getFirstStatement(ifStatement);
    if (ifStatement == null) return;
    if (firstStatement != null && firstStatement instanceof PyIfStatement) {
      PyExpression condition = ((PyIfStatement)firstStatement).getIfPart().getCondition();
      PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
      PyExpression ifCondition = ifStatement.getIfPart().getCondition();
      if (ifCondition == null || condition == null) return;
      StringBuilder replacementText = new StringBuilder(ifCondition.getText() + " and ");
      if (condition instanceof PyBinaryExpression && ((PyBinaryExpression)condition).getOperator() == PyTokenTypes.OR_KEYWORD) {
        replacementText.append("(").append(condition.getText()).append(")");
      } else
        replacementText.append(condition.getText());

      PyExpression newCondition = elementGenerator.createExpressionFromText(replacementText.toString());
      ifCondition.replace(newCondition);

      PyStatementList stList = ((PyIfStatement)firstStatement).getIfPart().getStatementList();
      PyStatementList ifStatementList = ifStatement.getIfPart().getStatementList();
      if (ifStatementList == null || stList == null) return;
      List<PsiComment> comments = PsiTreeUtil.getChildrenOfTypeAsList(ifStatement.getIfPart(), PsiComment.class);
      comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(((PyIfStatement)firstStatement).getIfPart(), PsiComment.class));
      comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(ifStatementList, PsiComment.class));
      comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(stList, PsiComment.class));

      for (PsiElement comm : comments) {
        ifStatement.getIfPart().addBefore(comm, ifStatementList);
        comm.delete();
      }
      ifStatementList.replace(stList);
    }
  }

  @Nullable
  private static PyStatement getFirstStatement(PyIfStatement ifStatement) {
    PyStatement firstStatement = null;
    if (ifStatement != null) {
      PyStatementList stList = ifStatement.getIfPart().getStatementList();
      if (stList != null) {
        if (stList.getStatements().length != 0) {
          firstStatement = stList.getStatements()[0];
        }
      }
    }
    return firstStatement;
  }

  @Nullable
  private static PyIfStatement getIfStatement(PyIfStatement expression) {
    while (expression != null) {
      PyStatementList stList = expression.getIfPart().getStatementList();
      if (stList != null) {
        if (stList.getStatements().length != 0) {
          PyStatement firstStatement = stList.getStatements()[0];
          if (firstStatement instanceof PyIfStatement) {
            break;
          }
        }
      }
      expression = PsiTreeUtil.getParentOfType(expression, PyIfStatement.class);
    }
    return expression;
  }
}
