package org.sef4j.callstack.event.impl;
import java.util.ArrayList;
import java.util.List;
import org.sef4j.callstack.event.StackEvent;
import org.sef4j.callstack.event.StackEvent.CompoundPopPushStackEvent;
import org.sef4j.callstack.event.StackEventVisitor;
/**
* StackEvent aggregator: accpt sequence of StackEvents and build a corresponding CompoundPopPushStackEvent
*
* design-patterns: Visitor of StackEvent AST class + Builder of CompoundPopPushStackEvent
*/
public class CompoundPopPushStackEventBuilder extends StackEventVisitor {
private Object lock = new Object();
private int levelDiff;
private int skipPushPopEventsCount;
private List<StackEvent.PopStackEvent> popEvents = new ArrayList<StackEvent.PopStackEvent>();
private List<StackEvent.PushStackEvent> pushedEvents = new ArrayList<StackEvent.PushStackEvent>();
private List<StackEvent.ProgressStepStackEvent> lastProgressSteps = new ArrayList<StackEvent.ProgressStepStackEvent>();
// ------------------------------------------------------------------------
public CompoundPopPushStackEventBuilder() {
}
// ------------------------------------------------------------------------
/**
* @return null if empty (no event added), otherwise compound event
*/
public StackEvent.CompoundPopPushStackEvent clearAndBuildOrNull() {
synchronized(lock) {
if (doIsEmpty()) {
return null;
}
StackEvent.CompoundPopPushStackEvent res = build();
doClear();
return res;
}
}
public StackEvent.CompoundPopPushStackEvent build() {
synchronized(lock) {
return doBuild();
}
}
private void doClear() {
levelDiff = 0;
skipPushPopEventsCount = 0;
popEvents.clear();
pushedEvents.clear();
lastProgressSteps.clear();
}
private boolean doIsEmpty() {
return levelDiff == 0
&& skipPushPopEventsCount == 0
&& popEvents.isEmpty()
&& pushedEvents.isEmpty()
&& lastProgressSteps.isEmpty();
}
private StackEvent.CompoundPopPushStackEvent doBuild() {
StackEvent.PopStackEvent[] popEventsArray = popEvents.toArray(new StackEvent.PopStackEvent[popEvents.size()]);
StackEvent.PushStackEvent[] pushedEventsArray = pushedEvents.toArray(new StackEvent.PushStackEvent[pushedEvents.size()]);
StackEvent.ProgressStepStackEvent[] lastProgressStepsArray = lastProgressSteps.toArray(new StackEvent.ProgressStepStackEvent[lastProgressSteps.size()]);
return new CompoundPopPushStackEvent(skipPushPopEventsCount,
popEventsArray, pushedEventsArray, lastProgressStepsArray);
}
@Override
public void acceptPushStackEvent(StackEvent.PushStackEvent pushStackEvent) {
pushedEvents.add(pushStackEvent);
lastProgressSteps.add(null);
levelDiff++;
}
@Override
public void acceptPopStackEvent(StackEvent.PopStackEvent popStackEvent) {
if (levelDiff > 0) {
// pop previously pushed elt ... suppress both
int lastIndex = pushedEvents.size() - 1;
pushedEvents.remove(lastIndex);
lastProgressSteps.remove(lastIndex);
skipPushPopEventsCount += 2;
} else {
popEvents.add(popStackEvent);
}
levelDiff--;
}
@Override
public void acceptProgressStackEvent(StackEvent.ProgressStepStackEvent progressStackEvent) {
int lastIndex = pushedEvents.size() - 1;
lastProgressSteps.set(lastIndex, progressStackEvent);
}
@Override
public void acceptCompoundStackEvent(StackEvent.CompoundPopPushStackEvent compoundStackEvent) {
// merge compound with compound (should not occurs!..)
}
}