package com.tinkerpop.blueprints.strategy;

import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;
import org.javatuples.Triplet;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.UnaryOperator;

/**
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
public class SequenceGraphStrategy implements GraphStrategy {
    private final List<GraphStrategy> graphStrategySequence;

    public SequenceGraphStrategy(final GraphStrategy... strategies) {
        this.graphStrategySequence = new ArrayList<>(Arrays.asList(strategies));
    }

    @Override
    public UnaryOperator<Object[]> getPreAddVertex() {
        return this.graphStrategySequence.stream().map(s -> s.getPreAddVertex()).reduce(null,
                (acc, next) -> acc == null ? next : toUnaryOp(acc.andThen(next)));
    }

    @Override
    public UnaryOperator<Vertex> getPostAddVertex() {
        return this.graphStrategySequence.stream().map(s -> s.getPostAddVertex()).reduce(null,
                (acc, next) -> acc == null ? next : toUnaryOp(acc.andThen(next)));
    }

    @Override
    public UnaryOperator<Triplet<String, Vertex, Object[]>> getPreAddEdge() {
        return this.graphStrategySequence.stream().map(s -> s.getPreAddEdge()).reduce(null,
                (acc, next) -> acc == null ? next : toUnaryOp(acc.andThen(next)));
    }

    @Override
    public UnaryOperator<Edge> getPostAddEdge() {
        return this.graphStrategySequence.stream().map(s -> s.getPostAddEdge()).reduce(null,
                (acc, next) -> acc == null ? next : toUnaryOp(acc.andThen(next)));
    }

    /**
     * Converts a {@link Function} to a {@link UnaryOperator} since the call to
     * {@link UnaryOperator#andThen(java.util.function.Function)} doesn't return {@link UnaryOperator} and can't
     * be casted to one.
     *
     * @param f a {@link Function} that has the same argument and return type
     * @return a {@link UnaryOperator} of the supplied {@code f}
     */
    private static <T> UnaryOperator<T> toUnaryOp(final Function<T,T> f) {
        return new UnaryOperator<T>() {
            @Override
            public T apply(T t) {
                return f.apply(t);
            }
        };
    }
}
@@ -735,37 +735,39 @@
 return this.
-graph
+compute
 Strategy
 Sequence.str
@@ -758,35 +758,20 @@
 tegy
-Sequence.stream().map
+Function
 (s
- 
 -%3E
- 
 s.ge
@@ -790,103 +790,8 @@
 x())
-.reduce(null,%0A                (acc, next) -%3E acc == null ? next : toUnaryOp(acc.andThen(next)))
 ;%0A  
@@ -879,37 +879,39 @@
 return this.
-graph
+compute
 Strategy
 Sequence.str
@@ -902,35 +902,20 @@
 tegy
-Sequence.stream().map
+Function
 (s
- 
 -%3E
- 
 s.ge
@@ -935,103 +935,8 @@
 x())
-.reduce(null,%0A                (acc, next) -%3E acc == null ? next : toUnaryOp(acc.andThen(next)))
 ;%0A  
@@ -1048,37 +1048,39 @@
 return this.
-graph
+compute
 Strategy
 Sequence.str
@@ -1071,43 +1071,167 @@
 tegy
-Sequence.stream().map
+Function(s-%3Es.getPreAddEdge());%0A    %7D%0A%0A    @Override%0A    public UnaryOperator%3CEdge%3E getPostAddEdge() %7B%0A        return this.computeStrategyFunction
 (s
- 
 -%3E
- 
 s.getP
-re
+ost
 AddE
@@ -1240,172 +1240,497 @@
 e())
-.reduce(null,
+;%0A    %7D%0A%0A    /**%0A     * Compute a new strategy function from the sequence of supplied %7B@link GraphStrategy%7D objects.
 %0A     
+*%0A
      
-      (acc, next) -%3E acc == null ? next : toUnaryOp(acc.andThen(next)));%0A    %7D%0A%0A    @Override%0A    public UnaryOperator%3CEdge%3E getPostAddEdge(
+* @param f a %7B@link Function%7D that extracts a particular strategy implementation from a %7B@link GraphStrategy%7D%0A     * @return a newly constructed %7B@link UnaryOperator%7D that applies each extracted strategy implementation in%0A     *         the order supplied%0A     */%0A    private UnaryOperator computeStrategyFunction(final Function%3CGraphStrategy, UnaryOperator%3E f
 ) %7B%0A
@@ -1788,31 +1788,9 @@
 map(
-s -%3E s.getPostAddEdge()
+f
 ).re

Refactor the SequenceGraphStrategy.