package xapi.dev.ui;
import com.github.javaparser.ASTHelper;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.UiAttrExpr;
import com.github.javaparser.ast.expr.UiContainerExpr;
import com.github.javaparser.ast.expr.UiExpr;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
/**
* Created by James X. Nelson (james @wetheinter.net) on 6/28/16.
*/
public class InterestingNodeFinder {
public static class InterestingNodeResults {
private Map<ComponentGraph, UiAttrExpr> dataNodes;
private Map<ComponentGraph, UiAttrExpr> refNodes;
private Map<ComponentGraph, UiExpr> cssNodes;
private boolean hasClassname;
private Map<ComponentGraph, List<NameExpr>> templateNames;
public InterestingNodeResults() {
dataNodes = new IdentityHashMap<>();
refNodes = new IdentityHashMap<>();
templateNames = new IdentityHashMap<>();
cssNodes = new IdentityHashMap<>();
}
public void addTemplateName(ComponentGraph g, NameExpr n) {
templateNames.computeIfAbsent(g, i -> new ArrayList<>())
.add(n);
}
public void addRefNode(ComponentGraph g, UiAttrExpr n) {
refNodes.put(g, n);
}
public void addDataNode(ComponentGraph g, UiAttrExpr n) {
dataNodes.put(g, n);
}
public void addCssNode(ComponentGraph g, UiExpr n) {
cssNodes.put(g, n);
}
public void foundClassnameFeature() {
hasClassname = true;
}
public boolean hasDataNodes() {
return !dataNodes.isEmpty();
}
public boolean hasCssNodes() {
return !cssNodes.isEmpty();
}
public boolean hasCssOrClassname() {
return !cssNodes.isEmpty() || hasClassname;
}
public boolean hasTemplateReferences() {
return !templateNames.isEmpty();
}
public Map<ComponentGraph, UiAttrExpr> getDataNodes() {
return dataNodes;
}
public Map<ComponentGraph, UiAttrExpr> getRefNodes() {
return refNodes;
}
public Map<ComponentGraph, UiExpr> getCssNodes() {
return cssNodes;
}
public boolean hasClassname() {
return hasClassname;
}
public Map<ComponentGraph, List<NameExpr>> getTemplateNames() {
return templateNames;
}
public Set<UiContainerExpr> getDataParents() {
if (!hasDataNodes()) {
return Collections.emptySet();
}
Map<UiContainerExpr, Boolean> map = new IdentityHashMap<>();
dataNodes.keySet().forEach(containerFinder(map));
return map.keySet();
}
public Set<UiContainerExpr> getCssParents() {
if (!hasCssNodes()) {
return Collections.emptySet();
}
Map<UiContainerExpr, Boolean> map = new IdentityHashMap<>();
cssNodes.keySet().forEach(containerFinder(map));
return map.keySet();
}
public Set<UiContainerExpr> getTemplateNameParents() {
if (!hasTemplateReferences()) {
return Collections.emptySet();
}
Map<UiContainerExpr, Boolean> map = new IdentityHashMap<>();
templateNames.keySet().forEach(containerFinder(map));
return map.keySet();
}
private Consumer<? super ComponentGraph> containerFinder(Map<UiContainerExpr, Boolean> map) {
return n -> {
UiContainerExpr c = n.getDeepestContainer();
while (c != null) {
if (map.get(c) != null) {
break;
}
map.put(c, true);
c = ASTHelper.getContainerParent(c);
}
};
}
}
public InterestingNodeResults findInterestingNodes(UiContainerExpr container) {
InterestingNodeResults results = new InterestingNodeResults();
ComponentMetadataFinder finder = new ComponentMetadataFinder();
final ComponentMetadataQuery query = new ComponentMetadataQuery();
query
.setVisitChildContainers(true)
.setVisitAttributeContainers(true)
.addDataFeatureListener(results::addDataNode)
.addRefFeatureListener(results::addRefNode)
.addCssFeatureListener(results::addCssNode)
.addAllFeatureListener((scope, attr) ->{
if ("class".equalsIgnoreCase(attr.getNameString())) {
results.foundClassnameFeature();
results.addCssNode(scope, attr);
}
})
.addNameListener((g, n) -> {
if (query.isTemplateName(n.getName())) {
results.addTemplateName(g, n);
}
});
container.accept(finder, query);
return results;
}
}