/**
   * Try to visit possible class name for PsiElements with text like "Foo\|Bar", "Foo|\Bar",
   * "\Foo|\Bar" Cursor must have position in PsiElement
   *
   * @param psiElement the element context, cursor should be in it
   * @param cursorOffset current cursor editor eg from completion context
   * @param visitor callback on matching class
   */
  public static void visitNamespaceClassForCompletion(
      PsiElement psiElement, int cursorOffset, ClassForCompletionVisitor visitor) {

    int cursorOffsetClean = cursorOffset - psiElement.getTextOffset();
    if (cursorOffsetClean < 1) {
      return;
    }

    String content = psiElement.getText();
    int length = content.length();
    if (!(length >= cursorOffsetClean)) {
      return;
    }

    String beforeCursor = content.substring(0, cursorOffsetClean);
    boolean isValid;

    // espend\|Container, espend\Cont|ainer <- fallback to last full namespace
    // espend|\Container <- only on known namespace "espend"
    String namespace = beforeCursor;

    // if no backslash or its equal in first position, fallback on namespace completion
    int lastSlash = beforeCursor.lastIndexOf("\\");
    if (lastSlash <= 0) {
      isValid = PhpIndexUtil.hasNamespace(psiElement.getProject(), beforeCursor);
    } else {
      isValid = true;
      namespace = beforeCursor.substring(0, lastSlash);
    }

    if (!isValid) {
      return;
    }

    // format namespaces and add prefix for fluent completion
    String prefix = "";
    if (namespace.startsWith("\\")) {
      prefix = "\\";
    } else {
      namespace = "\\" + namespace;
    }

    // search classes in current namespace and child namespaces
    for (PhpClass phpClass :
        PhpIndexUtil.getPhpClassInsideNamespace(psiElement.getProject(), namespace)) {
      String presentableFQN = phpClass.getPresentableFQN();
      if (presentableFQN != null
          && fr.adrienbrault.idea.symfony2plugin.util.StringUtils.startWithEqualClassname(
              presentableFQN, beforeCursor)) {
        visitor.visit(phpClass, presentableFQN, prefix);
      }
    }
  }
  @Nullable
  public static PsiElement getArrayKeyValueInsideSignaturePsi(
      PsiElement psiElementInsideClass, String callTo[], String methodName, String keyName) {
    PhpClass phpClass = PsiTreeUtil.getParentOfType(psiElementInsideClass, PhpClass.class);
    if (phpClass == null) {
      return null;
    }

    String className = phpClass.getPresentableFQN();
    if (className == null) {
      return null;
    }

    for (String s : callTo) {
      // @TODO: replace signature
      PsiElement arrayKeyValueInsideSignature =
          PhpElementsUtil.getArrayKeyValueInsideSignaturePsi(
              psiElementInsideClass.getProject(),
              "#M#C\\" + className + "." + s,
              methodName,
              keyName);
      if (arrayKeyValueInsideSignature != null) {
        return arrayKeyValueInsideSignature;
      }
    }

    return null;
  }
  /** "DateTime", DateTime::class */
  @Nullable
  public static PhpClass resolvePhpClassOnPsiElement(@NotNull PsiElement psiElement) {

    String dataClass = null;
    if (psiElement instanceof ClassConstantReference) {
      PsiElement lastChild = psiElement.getLastChild();
      // @TODO: FOO::class find PhpElementTyp: toString provides "class"
      if ("class".equals(lastChild.getText())) {
        PhpExpression classReference = ((ClassConstantReference) psiElement).getClassReference();
        if (classReference instanceof PhpReference) {
          dataClass = ((PhpReference) classReference).getFQN();
        }
      }
    } else {
      dataClass = getStringValue(psiElement);
    }

    if (dataClass == null) {
      return null;
    }

    return getClassInterface(psiElement.getProject(), dataClass);
  }