package org.elixir_lang.structure_view.element;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.ElementDescriptionLocation;
import com.intellij.psi.PsiElement;
import com.intellij.usageView.UsageViewTypeLocation;
import org.elixir_lang.navigation.item_presentation.Parent;
import org.elixir_lang.psi.AtUnqualifiedNoParenthesesCall;
import org.elixir_lang.psi.ElixirMatchedWhenOperation;
import org.elixir_lang.psi.call.Call;
import org.elixir_lang.psi.impl.ElixirPsiImplUtil;
import org.elixir_lang.psi.operation.Type;
import org.elixir_lang.structure_view.element.modular.Modular;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.openapi.util.Pair.pair;
/**
* A call definition @spec
*/
public class CallDefinitionSpecification extends Element<AtUnqualifiedNoParenthesesCall> {
/*
* Fields
*/
private final boolean callback;
@NotNull
private final Modular modular;
@NotNull
private final Timed.Time time;
/*
* Static Methods
*/
public static String elementDescription(Call call, ElementDescriptionLocation location) {
String elementDescription = null;
if (location == UsageViewTypeLocation.INSTANCE) {
elementDescription = "specification";
}
return elementDescription;
}
@Contract(pure = true)
public static boolean is(@NotNull final Call call) {
boolean is = false;
if (call instanceof AtUnqualifiedNoParenthesesCall) {
AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall = (AtUnqualifiedNoParenthesesCall) call;
String moduleAttributeName = ElixirPsiImplUtil.moduleAttributeName(atUnqualifiedNoParenthesesCall);
if (moduleAttributeName.equals("@spec")) {
is = true;
}
}
return is;
}
@Nullable
public static Pair<String, Integer> moduleAttributeNameArity(AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall) {
Call specification = specification(atUnqualifiedNoParenthesesCall);
Pair<String, Integer> nameArity = null;
if (specification != null) {
Call type = specificationType(specification);
if (type != null) {
nameArity = typeNameArity(type);
}
}
return nameArity;
}
@Nullable
public static Pair<String, Integer> moduleAttributeNameArity(Call call) {
Pair<String, Integer> nameArity = null;
if (call instanceof AtUnqualifiedNoParenthesesCall) {
nameArity = moduleAttributeNameArity((AtUnqualifiedNoParenthesesCall) call);
}
return nameArity;
}
@Nullable
public static PsiElement nameIdentifier(AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall) {
Call specification = specification(atUnqualifiedNoParenthesesCall);
PsiElement nameIdentifier = null;
if (specification != null) {
Call type = specificationType(specification);
if (type != null) {
nameIdentifier = typeNameIdentifier(type);
}
}
return nameIdentifier;
}
@Nullable
public static PsiElement nameIdentifier(Call call) {
PsiElement nameIdentifier = null;
if (call instanceof AtUnqualifiedNoParenthesesCall) {
nameIdentifier = nameIdentifier((AtUnqualifiedNoParenthesesCall) call);
}
return nameIdentifier;
}
@Nullable
public static Call specification(AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall) {
PsiElement[] arguments = atUnqualifiedNoParenthesesCall.getNoParenthesesOneArgument().arguments();
Call specification = null;
if (arguments.length == 1) {
PsiElement argument = arguments[0];
if (argument instanceof Call) {
specification = (Call) argument;
}
}
return specification;
}
@Nullable
public static Call specificationType(Call specification) {
Call type = null;
if (specification instanceof Type) {
type = type((Type) specification);
} else if (specification instanceof ElixirMatchedWhenOperation) {
type = type((ElixirMatchedWhenOperation) specification);
}
return type;
}
@Nullable
public static Call type(Type typeOperation) {
PsiElement leftOperand = typeOperation.leftOperand();
Call type = null;
if (leftOperand instanceof Call) {
type = (Call) leftOperand;
}
return type;
}
@Nullable
public static Call type(ElixirMatchedWhenOperation matchedWhenOperation) {
PsiElement lefOperand = matchedWhenOperation.leftOperand();
Call type = null;
if (lefOperand instanceof Type) {
type = type((Type) lefOperand);
}
return type;
}
@NotNull
public static Pair<String, Integer> typeNameArity(@NotNull Call type) {
String name = type.functionName();
int arity = type.resolvedFinalArity();
return pair(name, arity);
}
@Nullable
public static PsiElement typeNameIdentifier(@NotNull Call type) {
return type.functionNameElement();
}
/*
* Constructors
*/
public CallDefinitionSpecification(@NotNull Modular modular,
@NotNull AtUnqualifiedNoParenthesesCall moduleAttributeDefinition,
boolean callback,
@NotNull Timed.Time time) {
super(moduleAttributeDefinition);
this.callback = callback;
this.modular = modular;
this.time = time;
}
/*
* Instance Methods
*/
/**
* No children.
*
* @return empty array
*/
@NotNull
@Override
public TreeElement[] getChildren() {
return new TreeElement[0];
}
/**
* Returns the presentation of the tree element.
*
* @return the element presentation.
*/
@NotNull
@Override
public ItemPresentation getPresentation() {
Parent parentPresentation = (Parent) modular.getPresentation();
String location = parentPresentation.getLocatedPresentableText();
return new org.elixir_lang.navigation.item_presentation.CallDefinitionSpecification(
location,
specification(navigationItem),
callback,
time
);
}
}