package com.cedricziel.idea.typo3.container;
import com.cedricziel.idea.typo3.domain.TYPO3IconDefinition;
import com.cedricziel.idea.typo3.psi.visitor.CoreFlagParserVisitor;
import com.cedricziel.idea.typo3.psi.visitor.CoreIconParserVisitor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.psi.elements.Field;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import java.util.*;
public class IconProvider {
public static String ICON_REGISTRY_CLASS = "TYPO3\\CMS\\Core\\Imaging\\IconRegistry";
private static IconProvider instance;
private Map<Project, Map<String, List<TYPO3IconDefinition>>> icons = new HashMap<>();
public static synchronized IconProvider getInstance(Project project) {
if (instance == null) {
instance = new IconProvider();
}
if (!instance.icons.containsKey(project) || instance.icons.get(project) == null) {
instance.initialize(project);
instance.collect(project);
}
return instance;
}
private void initialize(Project project) {
// Initialize with a larger capacity since core alone has around 400 definitions
this.icons.put(project, new HashMap<>(800));
}
public static void destroyInstance(Project project) {
getInstance(project).destroy(project);
}
public void collect(Project project) {
collectIcons(project);
collectImagesForIcons(project);
}
private void collectImagesForIcons(Project project) {
VfsUtil.processFileRecursivelyWithoutIgnored(
project.getBaseDir(),
virtualFile -> {
if (!"png".equalsIgnoreCase(virtualFile.getExtension()) && !"svg".equalsIgnoreCase(virtualFile.getExtension())) {
return true;
}
getElementMap(project).forEach((psiElement, typo3IconDefinition) -> {
if (typo3IconDefinition.getSource() == null) {
return;
}
String filePath = typo3IconDefinition.getSource().substring(4);
if (virtualFile.getPath().contains(filePath)) {
typo3IconDefinition.setVirtualFile(virtualFile);
}
});
return true;
}
);
}
private void collectIcons(Project project) {
PhpIndex phpIndex = PhpIndex.getInstance(project);
Collection<PhpClass> iconRegistry = phpIndex.getClassesByFQN(ICON_REGISTRY_CLASS);
if (iconRegistry.isEmpty()) {
return;
}
iconRegistry.forEach(iconRegistryClass -> {
// parse static icon map
Collection<Field> fields = iconRegistryClass.getFields();
fields.forEach(field -> {
if ("icons".equals(field.getName())) {
field.accept(new CoreIconParserVisitor(icons.get(project)));
}
});
// parse dynamically registered flag icons
Collection<Method> methods = iconRegistryClass.getMethods();
methods.forEach(method -> {
if ("registerFlags".equals(method.getName())) {
method.accept(new CoreFlagParserVisitor(icons.get(project)));
}
});
});
}
public Map<PsiElement, TYPO3IconDefinition> getElementMap(Project project) {
Map<String, List<TYPO3IconDefinition>> projectIconMap = icons.get(project);
Map<PsiElement, TYPO3IconDefinition> map = new HashMap<>(projectIconMap.size());
projectIconMap.forEach((key, iconList) -> {
if (iconList == null || iconList.isEmpty()) {
return;
}
map.put(iconList.iterator().next().getElement(), iconList.iterator().next());
});
return map;
}
public boolean has(Project project, String value) {
return icons.get(project).containsKey(value);
}
public List<TYPO3IconDefinition> get(Project project, String value) {
return icons.get(project).get(value);
}
public List<TYPO3IconDefinition> all(Project project) {
if (!icons.containsKey(project) || icons.get(project) == null) {
return new ArrayList<>();
}
List<TYPO3IconDefinition> list = new ArrayList<>();
icons.get(project).forEach((icon, definitions) -> list.addAll(definitions));
return list;
}
private void destroy(Project project) {
if (this.icons.containsKey(project)) {
this.icons.remove(project);
}
}
}