package com.jetbrains.python.codeInsight;

import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyTargetExpression;
import com.jetbrains.python.psi.PyUtil;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * @author Alexey.Ivanov
 */
public class PyGotoSuperHandler implements CodeInsightActionHandler {

  public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
    PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
    PyClass pyClass = PsiTreeUtil.getParentOfType(element, PyClass.class);
    if (pyClass != null) {
      PyFunction function = PsiTreeUtil.getParentOfType(element, PyFunction.class, false, PyClass.class);
      if (function != null) {
        gotoSuperFunctions(editor, function, pyClass);
      }
      else {
        PyTargetExpression classAttr = PsiTreeUtil.getParentOfType(element, PyTargetExpression.class, false, PyClass.class);
        if (classAttr != null) {
          gotoSuperClassAttributes(editor, classAttr, pyClass);
        }
        else {
          navigateOrChoose(editor, PyUtil.getAllSuperClasses(pyClass), "Choose superclass");
        }
      }
    }
  }

  private static void gotoSuperFunctions(Editor editor, PyFunction function, PyClass pyClass) {
    final Collection<PyFunction> superFunctions = getAllSuperMethodsByName(function, pyClass);
    navigateOrChoose(editor, superFunctions, CodeInsightBundle.message("goto.super.method.chooser.title"));
  }

  private static void gotoSuperClassAttributes(Editor editor, PyTargetExpression attr, PyClass pyClass) {
    final Collection<PyTargetExpression> attrs = getAllSuperAttributesByName(attr, pyClass);
    navigateOrChoose(editor, attrs, "Choose superclass attribute");
  }

  private static void navigateOrChoose(Editor editor, Collection<? extends NavigatablePsiElement> superElements, final String title) {
    if (!superElements.isEmpty()) {
      NavigatablePsiElement[] superElementArray = superElements.toArray(new NavigatablePsiElement[superElements.size()]);
      if (superElementArray.length == 1) {
        superElementArray[0].navigate(true);
      }
      else {
        NavigationUtil.getPsiElementPopup(superElementArray, title).showInBestPositionFor(editor);
      }
    }
  }

  private static Collection<PyTargetExpression> getAllSuperAttributesByName(@NotNull final PyTargetExpression classAttr, PyClass pyClass) {
    final String name = classAttr.getName();
    if (name == null) {
      return Collections.emptyList();
    }
    final List<PyTargetExpression> result = new ArrayList<PyTargetExpression>();
    for (PyClass aClass: pyClass.iterateAncestorClasses()) {
      final PyTargetExpression superAttr = aClass.findClassAttribute(name, false);
      if (superAttr != null) {
        result.add(superAttr);
      }
    }
    return result;
  }

  private static Collection<PyFunction> getAllSuperMethodsByName(@NotNull final PyFunction method, PyClass pyClass) {
    final String name = method.getName();
    if (name == null) {
      return Collections.emptyList();
    }
    final List<PyFunction> result = new ArrayList<PyFunction>();
    for (PyClass aClass: pyClass.iterateAncestorClasses()) {
      final PyFunction byName = aClass.findMethodByName(name, false);
      if (byName != null) {
        result.add(byName);
      }
    }
    return result;
  }

  public boolean startInWriteAction() {
    return false;
  }
}

@@ -486,151 +486,9 @@
 psi.
-PyClass;%0Aimport com.jetbrains.python.psi.PyFunction;%0Aimport com.jetbrains.python.psi.PyTargetExpression;%0Aimport com.jetbrains.python.psi.PyUtil
+*
 ;%0Aim
@@ -1264,36 +1264,46 @@
     
-PyTargetExpression classAttr
+final PyAssignmentStatement assignment
  = P
@@ -1340,32 +1340,35 @@
 ment, Py
-TargetExpression
+AssignmentStatement
 .class, 
@@ -1406,25 +1406,26 @@
 if (
-cl
 ass
-Attr
+ignment
  != null
 ) %7B%0A
@@ -1424,64 +1424,162 @@
 null
-) %7B%0A          gotoSuperClassAttributes(editor, classAttr
+ && assignment.getTargets()%5B0%5D instanceof PyTargetExpression) %7B%0A          gotoSuperClassAttributes(editor, (PyTargetExpression) assignment.getTargets()%5B0%5D
 , py

tweak range in which ctrl-u goes to superclass attribute