package org.requirementsascode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;

import org.requirementsascode.exception.ElementAlreadyExistsException;
import org.requirementsascode.exception.NoSuchElementExistsException;

public class UseCase extends UseCaseModelElement{
	private List<UseCaseFlow> flows;
	private LinkedList<UseCaseStep> steps;
	private UseCaseFlow basicFlow;

	UseCase(String name, UseCaseModel useCaseModel) {
		super(name, useCaseModel);
		this.flows = new ArrayList<>();
		this.steps = new LinkedList<>();
		this.basicFlow = newFlow("Basic Flow");
	} 

	public UseCaseFlow basicFlow() {
		return basicFlow;
	}
	
	public UseCaseFlow newFlow(String flowName) {
		Objects.requireNonNull(flowName);

		if(hasFlow(flowName)){
			throw new ElementAlreadyExistsException(flowName);
		}
		UseCaseFlow flow = new UseCaseFlow(flowName, this);
		flows.add(flow);
		return flow;
	}
	
	public UseCaseFlow getFlow(String flowName) {
		Objects.requireNonNull(flowName);

		Optional<UseCaseFlow> optionalFlow = flows.stream().filter(flow -> flowName.equals(flow.getName())).findAny();
		if(!optionalFlow.isPresent()){
			throw new NoSuchElementExistsException(flowName);
		}
		return optionalFlow.get();
	}
	
	public List<UseCaseFlow> getFlows() {
		return Collections.unmodifiableList(flows);
	}
	
	public UseCaseStep getStep(String stepName) {
		Objects.requireNonNull(stepName);

		Optional<UseCaseStep> optionalStep = steps.stream().filter(step -> stepName.equals(step.getName())).findAny();
		if(!optionalStep.isPresent()){
			throw new NoSuchElementExistsException(stepName);
		}
		return optionalStep.get();
	}
	
	UseCaseStep newStep(String stepName, UseCaseFlow flow, UseCaseStep previousStep, Predicate<UseCaseRunner> predicate) {
		Objects.requireNonNull(stepName);
		Objects.requireNonNull(flow);
		
		if(hasStep(stepName)){
			throw new ElementAlreadyExistsException(stepName);
		}
		UseCaseStep newStep = new UseCaseStep(stepName, flow, previousStep, predicate);
		steps.add(newStep);
		return newStep;
	}
	
	public boolean hasStep(String stepName) {
		Objects.requireNonNull(stepName);
		
		boolean hasStep = steps.stream().anyMatch(step -> stepName.equals(step.getName()));
		return hasStep;
	}
	
	public boolean hasFlow(String flowName) {
		Objects.requireNonNull(flowName);
		
		boolean hasStep = flows.stream().anyMatch(flow -> flowName.equals(flow.getName()));
		return hasStep;
	}

	public List<UseCaseStep> getSteps() {
		return Collections.unmodifiableList(steps);
	}
}

@@ -50,24 +50,53 @@
 .ArrayList;%0A
+import java.util.Collection;%0A
 import java.
@@ -1152,33 +1152,24 @@
 owName);%0A%0A%09%09
-Optional%3C
 UseCaseFlow%3E
@@ -1171,216 +1171,76 @@
 Flow
-%3E optionalFlow = flows.stream().filter(flow -%3E flowName.equals(flow.getName())).findAny();%0A%09%09if(!optionalFlow.isPresent())%7B%0A%09%09%09throw new NoSuchElementExistsException(flowName);%0A%09%09%7D%0A%09%09return optionalFlow.get()
+ flow = getUseCaseModelElementByName(flowName, flows);%0A%09%09return flow
 ;%0A%09%7D
@@ -1422,17 +1422,8 @@
 %0A%0A%09%09
-Optional%3C
 UseC
@@ -1433,189 +1433,63 @@
 Step
-%3E optionalStep = steps.stream().filter(step -%3E stepName.equals(step.getName())).findAny();%0A%09%09if(!optionalStep.isPresent())%7B%0A%09%09%09throw new NoSuchElementExistsException(stepName
+ step = getUseCaseModelElementByName(stepName, steps
 );%0A
-%09%09%7D%0A
 %09%09re
@@ -1497,26 +1497,12 @@
 urn 
-optionalStep.get()
+step
 ;%0A%09%7D
@@ -2226,46 +2226,24 @@
 tch(
-flow -%3E flowName.equals
+hasName
 (flow
-.get
 Name
-()
 ));%0A
@@ -2352,10 +2352,595 @@
 ps);%0A%09%7D%0A
+%09%0A%09private %3CT extends UseCaseModelElement%3E T getUseCaseModelElementByName(String useCaseModelElementName, Collection%3CT%3E useCaseModelElements) %7B%0A%09%09Optional%3CT%3E optionalUseCaseModelElement = useCaseModelElements.stream().filter(hasName(useCaseModelElementName)).findAny();%0A%09%09T useCaseModelElement = optionalUseCaseModelElement.orElseThrow(() -%3E new NoSuchElementExistsException(useCaseModelElementName));%0A%09%09return useCaseModelElement;%0A%09%7D%0A%09private Predicate%3C? super UseCaseModelElement%3E hasName(String name) %7B%0A%09%09return useCaseModelElement -%3E name.equals(useCaseModelElement.getName());%0A%09%7D%0A
 %7D%0A

Refactor UseCase