package brainslug.flow.path;
import brainslug.flow.definition.FlowDefinition;
import brainslug.flow.definition.Identifier;
import brainslug.flow.node.ChoiceDefinition;
import brainslug.flow.node.EventDefinition;
import brainslug.flow.node.FlowNodeDefinition;
import brainslug.flow.node.ParallelDefinition;
import brainslug.flow.node.event.AbstractEventDefinition;
import brainslug.flow.node.event.EndEvent;
import brainslug.flow.node.event.IntermediateEvent;
import brainslug.flow.node.task.AbstractTaskDefinition;
import java.util.LinkedList;
public class FlowPathDefinition<Self extends FlowPathDefinition> {
protected final FlowDefinition definition;
protected final FlowNodeDefinition startNode;
LinkedList<FlowNodeDefinition> pathNodes = new LinkedList<FlowNodeDefinition>();
public FlowPathDefinition(FlowDefinition definition, FlowNodeDefinition startNode) {
this.definition = definition;
this.startNode = startNode;
}
public ChoiceDefinition choice(Identifier id) {
return appendNode(new ChoiceDefinition(definition)).id(id).self();
}
public AndDefinition parallel(Identifier id) {
return appendNode(new ParallelDefinition(definition).id(id)).self().fork();
}
public Self execute(AbstractTaskDefinition taskDefinition) {
appendNode(taskDefinition);
return then();
}
public Self waitFor(AbstractEventDefinition eventDefinition) {
if (!eventDefinition.is(IntermediateEvent.class)) {
eventDefinition.with(new IntermediateEvent());
}
appendNode(eventDefinition);
return then();
}
public Self end(Identifier endId) {
return end(new EventDefinition().id(endId));
}
public Self end(FlowNodeDefinition<EventDefinition> eventDefinition) {
if (definition.contains(eventDefinition)) {
addToPath(eventDefinition);
connect(pathNodes.getLast(), definition.getNode(eventDefinition.getId()));
return then();
}
if (!eventDefinition.is(EndEvent.class)) {
eventDefinition.with(new EndEvent());
}
appendNode(eventDefinition);
return then();
}
protected <T extends FlowNodeDefinition> T appendNode(T flowNodeDefinition) {
if (definition.contains(flowNodeDefinition)) {
throw new IllegalStateException("Node already exists");
}
if (pathNodes.isEmpty()) {
connect(getStartNode(), flowNodeDefinition);
} else {
connect(getPathNodes().getLast(), flowNodeDefinition);
}
addToPath(flowNodeDefinition);
definition.addNode(flowNodeDefinition);
return flowNodeDefinition;
}
protected <T extends FlowNodeDefinition> void addToPath(T flowNodeDefinition) {
pathNodes.add(flowNodeDefinition);
}
protected <T extends FlowNodeDefinition> void connect(FlowNodeDefinition previousNode, T flowNodeDefinition) {
previousNode.addOutgoing(flowNodeDefinition);
flowNodeDefinition.addIncoming(previousNode);
}
public Self then() {
return (Self) this;
}
public Self then(FlowNodeDefinition<?> flowNodeDefinition) {
this.appendNode(flowNodeDefinition);
return then();
}
public LinkedList<FlowNodeDefinition> getPathNodes() {
return pathNodes;
}
public FlowNodeDefinition getStartNode() {
return startNode;
}
public FlowNodeDefinition getFirstPathNode() {
return getPathNodes().peekFirst();
}
public FlowDefinition getDefinition() {
return definition;
}
}