package com.jetbrains.python.findUsages;

import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;

/**
 * @author yole
 */
public class PythonFindUsagesProvider implements FindUsagesProvider {
  public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
    return psiElement instanceof PsiNamedElement || psiElement instanceof PyReferenceExpression;
  }

  public String getHelpId(@NotNull PsiElement psiElement) {
    if (psiElement instanceof PyClass) {
      return "reference.dialogs.findUsages.class";
    }
    if (psiElement instanceof PyFunction) {
      return "reference.dialogs.findUsages.method";
    }
    if (psiElement instanceof PyReferenceExpression || psiElement instanceof PyTargetExpression) {
      return "reference.dialogs.findUsages.variable";
    }
    return null;
  }

  @NotNull
  public String getType(@NotNull PsiElement element) {
    if (element instanceof PyNamedParameter) return "parameter";  //TODO: replace strings to messages
    if (element instanceof PyFunction) {
      if (((PyFunction) element).getContainingClass() != null) {
        return "method";
      }
      return "function";
    }
    if (element instanceof PyClass) return "class";
    if (element instanceof PyReferenceExpression || element instanceof PyTargetExpression) return "variable";
    return "";
  }

  @NotNull
  public String getDescriptiveName(@NotNull PsiElement element) {
    if (element instanceof PsiNamedElement) {
      return ((PsiNamedElement)element).getName();
    }
    if (element instanceof PyReferenceExpression) {
      String referencedName = ((PyReferenceExpression)element).getReferencedName();
      if (referencedName == null) {
        return "";
      }
      return referencedName;
    }
    return "";
  }

  @NotNull
  public String getNodeText(@NotNull PsiElement element, boolean useFullName) {
    if (element instanceof PyNamedParameter) {
      StringBuilder result = new StringBuilder(((PyNamedParameter)element).getName());
      final PyFunction function = PsiTreeUtil.getParentOfType(element, PyFunction.class);
      if (function != null) {
        result.append(" of ");
        appendFunctionDescription(result, function);
      }
      return result.toString();
    }
    if (element instanceof PyFunction) {
      StringBuilder result = new StringBuilder();
      appendFunctionDescription(result, (PyFunction)element);
      return result.toString();
    }
    return getDescriptiveName(element);
  }

  private static void appendFunctionDescription(StringBuilder result, PyFunction function) {
    result.append(function.getName()).append("()");
    final PyClass containingClass = function.getContainingClass();
    if (containingClass != null) {
      result.append(" of class ").append(containingClass.getName());
    }
  }

  public WordsScanner getWordsScanner() {
    return new PyWordsScanner();
  }
}

@@ -1694,22 +1694,35 @@
 %7B%0A      
-return
+final String name =
  ((PsiNa
@@ -1748,24 +1748,72 @@
 .getName();%0A
+      return name == null ? %22%3Cunnamed%3E%22 : name;%0A
     %7D%0A    if
@@ -1990,24 +1990,33 @@
     return %22
+%3Cunnamed%3E
 %22;%0A      %7D%0A 

return non-null descriptive name for elements that don't have a name (PY-1552)