package reactfx;

import java.util.function.Supplier;

import javafx.beans.InvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableBooleanValue;


public class Indicator implements ObservableBooleanValue {

    private ListHelper<InvalidationListener> iListeners;
    private ListHelper<ChangeListener<? super Boolean>> cListeners;

    private boolean on = false;

    public Hold on() {
        if(on) {
            return Hold.EMPTY_HOLD;
        } else {
            set(true);
            return this::release;
        }
    }

    /**
     * Runs the given computation, making sure this indicator is on.
     * When done, this indicator is reset to the previous state.
     *
     * <p>Equivalent to
     * <pre>
     * try(Hold h = on()) {
     *     r.run();
     * }
     * </pre>
     */
    public void onWhile(Runnable r) {
        try(Hold h = on()) {
            r.run();
        }
    }

    /**
     * Runs the given computation, making sure this indicator is on.
     * When done, this indicator is reset to the previous state.
     *
     * <pre>
     * T t = indicator.onWhile(f);
     * </pre>
     *
     * is equivalent to
     *
     * <pre>
     * T t;
     * try(Hold h = on()) {
     *     t = f.get();
     * }
     * </pre>
     */
    public <T> T onWhile(Supplier<T> f) {
        try(Hold h = on()) {
            return f.get();
        }
    }

    public boolean isOn() {
        return on;
    }

    @Override
    public boolean get() {
        return on;
    }

    @Override
    public Boolean getValue() {
        return on;
    }

    private void release() {
        assert on;
        set(false);
    }

    private void set(boolean value) {
        on = value;
        ListHelper.forEach(iListeners, l -> l.invalidated(this));
        ListHelper.forEach(cListeners, l -> l.changed(this, !value, value));
    }

    @Override
    public void addListener(ChangeListener<? super Boolean> listener) {
        cListeners = ListHelper.add(cListeners, listener);
    }

    @Override
    public void removeListener(ChangeListener<? super Boolean> listener) {
        cListeners = ListHelper.remove(cListeners, listener);
    }

    @Override
    public void addListener(InvalidationListener listener) {
        iListeners = ListHelper.add(iListeners, listener);
    }

    @Override
    public void removeListener(InvalidationListener listener) {
        iListeners = ListHelper.remove(iListeners, listener);
    }
}

@@ -1598,32 +1598,276 @@
 turn on;%0A    %7D%0A%0A
+    public EventStream%3CVoid%3E ons() %7B%0A        return EventStreams.valuesOf(this).filter(on -%3E on).map(on -%3E null);%0A    %7D%0A%0A    public EventStream%3CVoid%3E offs() %7B%0A        return EventStreams.valuesOf(this).filter(on -%3E !on).map(on -%3E null);%0A    %7D%0A%0A
     private void

Add ons() and offs() event streams to Indicator.