/** * */ package com.sap.furcas.runtime.parser.textblocks.observer; import java.util.List; import com.sap.furcas.metamodel.FURCAS.TCS.SequenceElement; import com.sap.furcas.metamodel.FURCAS.textblocks.AbstractToken; /** * traverses a virtual tree based on events, traces an existing tree where there is an overlap. */ public class TextBlockTraverser { private final Stack<TextBlockProxyTraversationContext> stack = new Stack<TextBlockProxyTraversationContext>(); public TextBlockTraverser() { TextBlockProxyTraversationContext rootContext = new TextBlockProxyTraversationContext(new TextBlockProxy()); stack.push(rootContext); } /** * returns existing or newly created textblockproxy * * @return */ public TextBlockProxy enterNextChild() { TextBlockProxyTraversationContext currentContext = stack.peek(); int lastIndex = currentContext.getLastVisitedChildIndex(); currentContext.setLastVisitedChildIndex(lastIndex + 1); TextBlockProxy newTextBlockProxy = new TextBlockProxy(); TextBlockProxyTraversationContext newContext = new TextBlockProxyTraversationContext(newTextBlockProxy); currentContext.addSubNode(newTextBlockProxy); stack.push(newContext); return newContext.getContextBlock(); } /** * Returns the index of the last visited child. * * @return */ public int getLastVisitedChildIndex() { TextBlockProxyTraversationContext currentContext = stack.peek(); return currentContext.getLastVisitedChildIndex(); } public void leaveChild() { stack.pop(); if (stack.isEmpty()) { throw new IllegalStateException("Cannot leave root context"); } } public TextBlockProxy getCurrent() { return stack.peek().getContextBlock(); } public SequenceElement getCurrentSequenceElement() { return stack.peek().getCurrentSequenceElement(); } public void addSubNode(AbstractToken token) { stack.peek().addSubNode(token); } public void addSubNode(TextBlockProxy token) { stack.peek().addSubNode(token); } public List<?> getSubNodes() { return stack.peek().getSubNodes(); } /** * @param offChannelTokens */ public void addSubNodes(List<? extends AbstractToken> tokens) { stack.peek().addSubNodes(tokens); } /** * this can be used to reset the counter one child back in order to re-enter the last child upon the next call to * {@link #enterNextChild()}. */ public void resetOneChildBack() { // //only reset if we are at least at the first child // if(stack.peek().getLastVisitedChildIndex() > -1) { stack.peek().setLastVisitedChildIndex(stack.peek().getLastVisitedChildIndex() - 1); // } } public void setCurrentSequenceElement(SequenceElement sequenceElement) { stack.peek().setCurrentSequenceElement(sequenceElement); } /** * Adds the given <code>element</code> to the context of the element on top of the stack. * * @param element */ public void addToContext(Object element) { stack.peek().addElementToContext(element); } public void enterAlternative(int choice) { TextBlockProxyTraversationContext context = stack.peek(); context.setCurrentAlternative(choice); } public void exitAlternative() { TextBlockProxyTraversationContext context = stack.peek(); context.exitAlternative(); } public void setOperatorToken(boolean b) { stack.peek().setOperatorToken(b); } public boolean isOperatorToken() { return stack.peek().isOperatorToken(); } /** * Sets the sequence element that was used before a separator sequence. It is stored so * that it can be restored to the current sequence element once the separator sequence * was left. * * @param currentSequenceElement The sequence element to be saved as the one before the * separator. */ public void setSequenceElementOfSeparator( SequenceElement currentSequenceElement) { stack.peek().setSequenceElementOfSeparator(currentSequenceElement); } /** * Returns sequence element that was used before a separator sequence. It is stored so * that it can be restored to the current sequence element once the separator sequence * was left. */ public SequenceElement getSequenceElementOfSeparator() { return stack.peek().getSequenceElementOfSeparator(); } }