package cyclops.control;

import cyclops.free.Free;
import cyclops.function.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import org.jooq.lambda.tuple.Tuple;
import org.jooq.lambda.tuple.Tuple2;
import org.jooq.lambda.tuple.Tuple3;

import java.util.function.BiFunction;
import java.util.function.Function;


@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ReaderWriterState<R,W,S,T>  {

    Monoid<W> monoid;
    BiFunction<R,S, Free<Fn0.SupplierKind.µ,Tuple3<W, S, T>>> runState;

    public Tuple3<W,S,T> run(R r,S s) {
        return Fn0.run(runState.apply(r,s));
    }

    public <R2> ReaderWriterState<R,W,S,R2> map(Function<? super T,? extends R2> mapper) {

        return mapState(t -> Tuple.tuple(t.v1, t.v2, mapper.apply(t.v3)));
    }
    public <R2> ReaderWriterState<R,W,S,R2> mapState(Function<Tuple3<W,S,T>, Tuple3<W,S, R2>> fn) {
        return suspended((r,s) -> runState.apply(r,s).map(t3 -> fn.apply(t3)),monoid);
    }
    private static <R,W,S,T> ReaderWriterState<R,W,S,T> suspended(BiFunction<? super R, ? super S, Free<Fn0.SupplierKind.µ,Tuple3<W,S, T>>> runF,
                                                                  Monoid<W> monoid) {

        return new ReaderWriterState<R, W, S, T>(monoid,(R r ,S s) -> Fn0.suspend(Lambda.λK(()->runF.apply(r,s))));

    }

    public <R2> ReaderWriterState<R,W,S,R2> flatMap(Function<? super T,? extends  ReaderWriterState<R,W,S,R2>> f) {

        return suspended((r,s) -> runState.apply(r, s)
                .flatMap(result -> Free.done(f.apply(result.v3).run(r, result.v2))),monoid);
    }

    public static <R,W,S,T> ReaderWriterState<R,W,S,T> rws(BiFunction<? super R, ? super S,? extends Tuple3<W,S, T>> runF, Monoid<W> monoid) {

        return new ReaderWriterState<R, W, S, T>(monoid,(r,s) -> Free.done(runF.apply(r,s)));
    }
}

@@ -593,32 +593,307 @@
 y(r,s));%0A    %7D%0A%0A
+    public  ReaderWriterState%3CR,W,S,T%3E write(W value) %7B%0A        BiFunction%3C? super R, ? super S, Free%3CFn0.SupplierKind.%C2%B5,Tuple3%3CW,S, T%3E%3E%3E fn = (r,s)-%3ErunState.apply(r,s).map(t3-%3ETuple.tuple(monoid.apply(t3.v1,value),t3.v2,t3.v3));%0A        return suspended(fn,monoid);%0A    %7D%0A%0A
     public %3CR2%3E 
@@ -1863,32 +1863,34 @@
 monoid);%0A    %7D%0A%0A
+%0A%0A
     public stati

add write to rws