// Copyright 2014 takahashikzn
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package jp.root42.indolently.ref;

import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;

import jp.root42.indolently.Indolently;
import jp.root42.indolently.function.Expression;
import jp.root42.indolently.trait.Identical;


/**
 * @param <T> value type
 * @param <S> self type
 * @author takahashikzn
 */
public interface ValueReference<T, S extends ValueReference<T, S>>
    extends Supplier<T>, Consumer<T>, Identical<S> {

    /**
     * get value then do something with this instance.
     *
     * @param f any operation
     * @return the value
     */
    default T getThen(final Consumer<? super S> f) {
        final T curr = this.get();
        f.accept(this.identity());
        return curr;
    }

    /**
     * get value as optional representation.
     *
     * @return optional representation of the value
     */
    default Optional<T> opt() {
        return Indolently.optional(this.get());
    }

    /**
     * get value if exists, otherwise use the value from supplier as this reference's value.
     *
     * @param f value supplier
     * @return the value
     */
    default T orAccept(final Expression<? extends T> f) {

        return this.opt().orElseGet(() -> {
            final T val = f.get();
            this.accept(val);
            return val;
        });
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static BoolRef of(final boolean val) {
        return new BoolRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static IntRef of(final int val) {
        return new IntRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static LongRef of(final long val) {
        return new LongRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static DoubleRef of(final double val) {
        return new DoubleRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static FloatRef of(final float val) {
        return new FloatRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static ShortRef of(final short val) {
        return new ShortRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static ByteRef of(final byte val) {
        return new ByteRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static CharRef of(final char val) {
        return new CharRef(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static <T> Ref<T> of(final T val) {
        return new Ref<>(val);
    }

    /**
     * create a reference of value.
     *
     * @param val initial value
     * @return reference of value
     */
    static <T extends Comparable<T>> CmpRef<T> of(final T val) {
        return new CmpRef<>(val);
    }
}

@@ -1245,23 +1245,312 @@
         
-final T
+return this.optThen(f).get();%0A    %7D%0A%0A    /**%0A     * get value if exists, then do something with this instance.%0A     *%0A     * @param f any operation%0A     * @return optional representation of the value%0A     */%0A    default Optional%3CT%3E optThen(final Consumer%3C? super S%3E f) %7B%0A        final Optional%3CT%3E
  curr = 
@@ -1554,18 +1554,18 @@
  = this.
-ge
+op
 t();%0A   

add optThen