package fr.adrienbrault.idea.symfony2plugin.config;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
import com.intellij.psi.PsiPolyVariantReferenceBase;
import com.intellij.psi.ResolveResult;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.completion.PhpClassLookupElement;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
import fr.adrienbrault.idea.symfony2plugin.util.completion.PhpClassReferenceInsertHandler;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class PhpClassReference extends PsiPolyVariantReferenceBase<PsiElement> {
private String classFQN;
private boolean provideVariants = false;
private boolean useClasses = true;
private boolean useInterfaces = false;
public PhpClassReference(@NotNull StringLiteralExpression element) {
super(element);
this.classFQN = PsiElementUtils.getMethodParameter(element);
}
public PhpClassReference(@NotNull PsiElement element, String classFQN) {
super(element);
this.classFQN = classFQN;
}
public PhpClassReference(@NotNull PsiElement element, String classFQN, boolean provideVariants) {
this(element, classFQN);
this.provideVariants = provideVariants;
}
public PhpClassReference(@NotNull StringLiteralExpression element, boolean provideVariants) {
this(element);
this.provideVariants = provideVariants;
}
@NotNull
@Override
public ResolveResult[] multiResolve(boolean incompleteCode) {
List<ResolveResult> results = new ArrayList<ResolveResult>();
PhpIndex phpIndex = PhpIndex.getInstance(getElement().getProject());
if(this.useClasses) {
this.attachPhpClassResolveResults(phpIndex.getClassesByFQN(classFQN), results);
}
if(this.useInterfaces) {
this.attachPhpClassResolveResults(phpIndex.getInterfacesByFQN(classFQN.startsWith("\\") ? classFQN : "\\" + classFQN), results);
}
return results.toArray(new ResolveResult[results.size()]);
}
private void attachPhpClassResolveResults(Collection<PhpClass> phpClasses, List<ResolveResult> results) {
for (PhpClass phpClass : phpClasses) {
results.add(new PsiElementResolveResult(phpClass));
}
}
@NotNull
@Override
public Object[] getVariants() {
List<LookupElement> results = new ArrayList<LookupElement>();
// not break old calls to this
// @TODO: check performance and migrate all custom completion to this method
if(!this.provideVariants) {
return results.toArray();
}
CamelHumpMatcher camelHumpMatcher = new CamelHumpMatcher(this.classFQN);
PhpIndex phpIndex = PhpIndex.getInstance(this.getElement().getProject());
if(this.useClasses) {
for (String name : phpIndex.getAllClassNames(camelHumpMatcher)) {
attachPhpClassToVariants(results, phpIndex.getClassesByName(name));
}
}
// phpindex interface dont support filter
if(this.useInterfaces) {
for (String name : phpIndex.getAllInterfaceNames()) {
if(this.classFQN.length() > 0 && !name.toLowerCase().contains(this.classFQN.toLowerCase())) {
continue;
}
attachPhpClassToVariants(results, phpIndex.getInterfacesByName(name));
}
}
return results.toArray();
}
private void attachPhpClassToVariants(List<LookupElement> results, Collection<PhpClass> phpClasses) {
for(PhpClass phpClass: phpClasses) {
results.add(new PhpClassLookupElement(phpClass, true, PhpClassReferenceInsertHandler.getInstance()));
}
}
public PhpClassReference setUseInterfaces(boolean useInterfaces) {
this.useInterfaces = useInterfaces;
return this;
}
public PhpClassReference setUseClasses(boolean useClasses) {
this.useClasses = useClasses;
return this;
}
}