package fr.adrienbrault.idea.symfony2plugin.templating.path;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtension;
import fr.adrienbrault.idea.symfony2plugin.extension.TwigNamespaceExtensionParameter;
import fr.adrienbrault.idea.symfony2plugin.templating.dict.TwigConfigJson;
import fr.adrienbrault.idea.symfony2plugin.templating.path.dict.TwigPathJson;
import fr.adrienbrault.idea.symfony2plugin.util.VfsExUtil;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class JsonFileIndexTwigNamespaces implements TwigNamespaceExtension {
private static final Key<CachedValue<Collection<TwigPath>>> CACHE = new Key<>("TWIG_JSON_INDEX_CACHE");
@NotNull
@Override
public Collection<TwigPath> getNamespaces(final @NotNull TwigNamespaceExtensionParameter parameter) {
CachedValue<Collection<TwigPath>> cache = parameter.getProject().getUserData(CACHE);
if (cache == null) {
cache = CachedValuesManager.getManager(parameter.getProject()).createCachedValue(() ->
CachedValueProvider.Result.create(getNamespacesInner(parameter), PsiModificationTracker.MODIFICATION_COUNT),
false
);
parameter.getProject().putUserData(CACHE, cache);
}
return cache.getValue();
}
@NotNull
private Collection<TwigPath> getNamespacesInner(@NotNull TwigNamespaceExtensionParameter parameter) {
Collection<TwigPath> twigPaths = new ArrayList<>();
for (final PsiFile psiFile : FilenameIndex.getFilesByName(parameter.getProject(), "ide-twig.json", GlobalSearchScope.allScope(parameter.getProject()))) {
Collection<TwigPath> cachedValue = CachedValuesManager.getCachedValue(psiFile, new MyJsonCachedValueProvider(psiFile));
if(cachedValue != null) {
twigPaths.addAll(cachedValue);
}
}
return twigPaths;
}
private static class MyJsonCachedValueProvider implements CachedValueProvider<Collection<TwigPath>> {
private final PsiFile psiFile;
public MyJsonCachedValueProvider(PsiFile psiFile) {
this.psiFile = psiFile;
}
@Nullable
@Override
public Result<Collection<TwigPath>> compute() {
Collection<TwigPath> twigPaths = new ArrayList<>();
String text = psiFile.getText();
TwigConfigJson configJson = null;
try {
configJson = new Gson().fromJson(text, TwigConfigJson.class);
} catch (JsonSyntaxException | JsonIOException | IllegalStateException ignored) {
}
if(configJson == null) {
return Result.create(twigPaths, psiFile, psiFile.getVirtualFile());
}
for(TwigPathJson twigPath : configJson.getNamespaces()) {
String path = twigPath.getPath();
if(path == null) {
path = "";
}
path = StringUtils.stripStart(path.replace("\\", "/"), "/");
PsiDirectory parent = psiFile.getParent();
if(parent == null) {
continue;
}
// current directory check and subfolder
VirtualFile twigRoot;
if(path.length() > 0) {
twigRoot = VfsUtil.findRelativeFile(parent.getVirtualFile(), path.split("/"));
} else {
twigRoot = psiFile.getParent().getVirtualFile();
}
if(twigRoot == null) {
continue;
}
String relativePath = VfsExUtil.getRelativeProjectPath(psiFile.getProject(), twigRoot);
if(relativePath == null) {
continue;
}
String namespace = twigPath.getNamespace();
TwigPathIndex.NamespaceType pathType = TwigPathIndex.NamespaceType.ADD_PATH;
String type = twigPath.getType();
if("bundle".equalsIgnoreCase(type)) {
pathType = TwigPathIndex.NamespaceType.BUNDLE;
}
String namespacePath = StringUtils.stripStart(relativePath, "/");
if(StringUtils.isNotBlank(namespace)) {
twigPaths.add(new TwigPath(namespacePath, namespace, pathType, true));
} else {
twigPaths.add(new TwigPath(namespacePath, TwigPathIndex.MAIN, pathType, true));
}
}
return Result.create(twigPaths, psiFile, psiFile.getVirtualFile());
}
}
}