package org.requirementsascode;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.requirementsascode.predicate.After;

/**
 * A use case step, as part of a use case. The use case steps define the
 * behavior of the use case.
 *
 * <p>
 * A use case step is the core class of requirementsascode, providing all the
 * necessary configuration information to the {@link UseCaseModelRunner} to
 * cause the system to react to events.
 *
 * @author b_muth
 */
public class TrailingStep extends Step implements Serializable {
    private static final long serialVersionUID = -2926490717985964131L;

    /**
     * Creates a use case step with the specified name as the last step of the
     * specified use case flow.
     *
     * @param stepName
     *            the name of the step to be created
     * @param useCaseFlow
     *            the use case flow that will contain the new use case
     */
    TrailingStep(String stepName, UseCase useCase, Flow useCaseFlow) {
	super(stepName, useCase, useCaseFlow);
	appendToLastStepOfFlow();
	setFlowPosition(new After(previousStepInFlow));
    }

    private void appendToLastStepOfFlow() {
	List<Step> flowSteps = getFlow().getSteps();
	Step lastFlowStep = flowSteps.size() > 0 ? flowSteps.get(flowSteps.size() - 1) : null;
	setPreviousStepInFlow(lastFlowStep);
    }

    @Override
    public Predicate<UseCaseModelRunner> getPredicate() {
	Predicate<UseCaseModelRunner> predicate;
	Predicate<UseCaseModelRunner> reactWhile = getReactWhile();

	if (reactWhile != null) {
	    predicate = reactWhile;
	} else {
	    predicate = getFlowPosition().get().and(noConditionalStepInterrupts());
	}

	return predicate;
    }

    private Predicate<UseCaseModelRunner> noConditionalStepInterrupts() {
	return useCaseModelRunner -> {
	    Class<?> theStepsEventClass = getUserEventClass();
	    UseCaseModel useCaseModel = getUseCaseModel();

	    Stream<Step> stepsStream = useCaseModel.getModifiableSteps().stream();
	    Stream<Step> stepsWithDefinedPredicatesStream = stepsStream
		    .filter(isConditionalStep().and(isOtherStepThan(this)));

	    Set<Step> stepsWithDefinedConditionsThatCanReact = useCaseModelRunner
		    .stepsInStreamThatCanReactTo(theStepsEventClass, stepsWithDefinedPredicatesStream);
	    return stepsWithDefinedConditionsThatCanReact.size() == 0;
	};
    }

    private Predicate<Step> isConditionalStep() {
	return step -> ConditionalStep.class.equals(step.getClass());
    }

    private Predicate<Step> isOtherStepThan(Step theStep) {
	return step -> !step.equals(theStep);
    }
}

@@ -2077,33 +2077,23 @@
 ep%3E 
-stepsWithDefinedPredica
+conditionalS
 te
+p
 sStr
@@ -2109,23 +2109,16 @@
 psStream
-%0A%09%09    
 .filter(
@@ -2186,33 +2186,17 @@
 ep%3E 
-stepsWithDefinedC
+c
 ondition
 sTha
@@ -2183,32 +2183,38 @@
 %3CStep%3E condition
+alStep
 sThatCanReact = 
@@ -2235,15 +2235,8 @@
 nner
-%0A%09%09    
 .ste
@@ -2283,34 +2283,30 @@
 ass,
- stepsWithDefinedPredica
+%0A%09%09    conditionalS
 te
+p
 sStr
@@ -2327,33 +2327,17 @@
 urn 
-stepsWithDefinedC
+c
 ondition
 sTha
@@ -2332,16 +2332,22 @@
 ondition
+alStep
 sThatCan

Clean up variable names