package fr.adrienbrault.idea.symfony2plugin.completion;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProviderLookupArguments;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.utils.GotoCompletionUtil;
import fr.adrienbrault.idea.symfony2plugin.dic.ContainerService;
import fr.adrienbrault.idea.symfony2plugin.dic.ServiceCompletionProvider;
import fr.adrienbrault.idea.symfony2plugin.dic.ServiceStringLookupElement;
import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil;
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
abstract public class DecoratedServiceCompletionProvider extends GotoCompletionProvider {
public DecoratedServiceCompletionProvider(PsiElement psiElement) {
super(psiElement);
}
@Override
public void getLookupElements(@NotNull GotoCompletionProviderLookupArguments arguments) {
ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector = new ContainerCollectionResolver.LazyServiceCollector(getProject());
Map<String, ContainerService> services = lazyServiceCollector.getCollector().getServices();
Collection<String> servicesMatches = collectDecorateServiceSuggestions(lazyServiceCollector);
Collection<LookupElement> collect = services.values().stream()
.map((Function<ContainerService, LookupElement>)
service -> new ServiceStringLookupElement(service, servicesMatches.contains(service.getName())))
.collect(Collectors.toList());
ServiceCompletionProvider.addPrioritizedServiceLookupElements(
arguments.getParameters(),
arguments.getResultSet(),
new ServiceCompletionProvider.PrioritizedLookupResult(
collect,
ServiceContainerUtil.getSortedServiceId(getProject(), servicesMatches)
)
);
}
@NotNull
@Override
public Collection<LookupElement> getLookupElements() {
return Collections.emptyList();
}
@NotNull
@Override
public Collection<PsiElement> getPsiTargets(PsiElement element) {
String decoratesId = GotoCompletionUtil.getTextValueForElement(element);
if(decoratesId == null) {
return Collections.emptyList();
}
return Collections.singletonList(ServiceUtil.getResolvedClassDefinition(getProject(), decoratesId));
}
@Nullable
abstract public String findClassForElement(@NotNull PsiElement psiElement);
@Nullable
abstract public String findIdForElement(@NotNull PsiElement psiElement);
@NotNull
private Collection<String> collectDecorateServiceSuggestions(@NotNull ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector) {
String classForElement = findClassForElement(getElement());
if(classForElement == null) {
return Collections.emptyList();
}
return createSuggestions(lazyServiceCollector, classForElement, findIdForElement(getElement()));
}
@NotNull
private Collection<String> createSuggestions(@NotNull ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector, @NotNull String aClass, @Nullable String myId) {
Set<String> servicesMatches = new HashSet<>();
PhpClass phpClass = ServiceUtil.getResolvedClassDefinition(getProject(), aClass, lazyServiceCollector);
if(phpClass != null) {
for (PhpClass serviceClass : ServiceUtil.getSuperClasses(phpClass)) {
servicesMatches.addAll(ServiceUtil.getServiceSuggestionForPhpClass(serviceClass, lazyServiceCollector.getCollector().getServices()).stream()
.map(ContainerService::getName).collect(Collectors.toSet())
);
}
}
servicesMatches.remove(myId);
return servicesMatches;
}
}