package xapi.dev.ui;
import com.github.javaparser.ast.expr.UiAttrExpr;
import com.github.javaparser.ast.expr.UiBodyExpr;
import com.github.javaparser.ast.expr.UiContainerExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import xapi.dev.ui.UiVisitScope.ScopeType;
import xapi.fu.In1Out1;
import xapi.fu.Lazy;
import xapi.fu.Out1;
import xapi.util.api.RemovalHandler;
/**
* @author James X. Nelson (james@wetheinter.net)
* Created on 5/4/16.
*/
public class UiGeneratorVisitor extends VoidVisitorAdapter<UiGeneratorTools> {
interface ScopeHandler extends In1Out1<UiVisitScope, RemovalHandler> { }
final Lazy<ContainerMetadata> root;
private ScopeHandler onScope;
ContainerMetadata parent;
private UiComponentGenerator generator;
private UiFeatureGenerator feature;
public UiGeneratorVisitor(ScopeHandler onScope) {
this.onScope = onScope;
root = Lazy.deferred1(this.createRoot());
}
public UiGeneratorVisitor(ScopeHandler onScope, Out1<ContainerMetadata> source) {
this.onScope = onScope;
root = Lazy.deferred1(source);
}
public UiGeneratorVisitor(ScopeHandler onScope, ContainerMetadata source) {
this.onScope = onScope;
root = Lazy.immutable1(source);
}
protected Out1<ContainerMetadata> createRoot() {
return ContainerMetadata::new;
}
public void wrapScope(In1Out1<ScopeHandler, ScopeHandler> mapper) {
onScope = mapper.io(onScope);
}
@Override
public void visit(UiContainerExpr n, UiGeneratorTools service) {
boolean isRoot = parent == null;
final ContainerMetadata myParent = getParent();
final ContainerMetadata me;
if (isRoot) {
me = parent = myParent;
} else {
me = parent = myParent.createChild(n, service);
}
final UiComponentGenerator oldGenerator = generator;
try {
final UiComponentGenerator myGenerator = generator = service.getComponentGenerator(n, me);
if (myGenerator != null) {
final UiVisitScope scope = generator.startVisit(service, me, n);
assert scope.getType() == ScopeType.CONTAINER : "Expected container scope " + scope;
final RemovalHandler undo = onScope.io(scope);
if (scope.isVisitChildren()) {
super.visit(n, service);
}
undo.remove();
myGenerator.endVisit(service, me, n, scope);
}
} finally {
parent = myParent;
generator = oldGenerator;
}
}
@Override
public void visit(
UiAttrExpr n, UiGeneratorTools service
) {
final UiComponentGenerator myGenerator = generator;
final UiFeatureGenerator oldFeature = feature;
try {
final UiFeatureGenerator myFeature = feature = service.getFeatureGenerator(n, generator);
if (myFeature != null) {
final UiVisitScope scope = myFeature.startVisit(service, myGenerator, parent, n);
assert scope.getType() == ScopeType.FEATURE : "Expected feature scope " + scope;
final RemovalHandler undo = onScope.io(scope);
if (scope.isVisitChildren()) {
super.visit(n, service);
}
undo.remove();
myFeature.finishVisit(service, myGenerator, parent, n, scope);
if (myFeature.hasSideEffects()) {
myGenerator.getMetadata().recordSideEffects(service, myFeature);
}
}
} finally {
feature = oldFeature;
}
}
@Override
public void visit(
UiBodyExpr n, UiGeneratorTools arg
) {
if (n.isNotEmpty()) {
}
super.visit(n, arg);
}
private ContainerMetadata getParent() {
if (parent == null) {
parent = root.out1();
}
return parent;
}
}