All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.reactfx.SuccessionReducingStream Maven / Gradle / Ivy

There is a newer version: 2.0-M5
Show newest version
package org.reactfx;

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

import javafx.beans.binding.BooleanBinding;
import javafx.beans.value.ObservableBooleanValue;

import org.reactfx.util.Timer;

class SuccessionReducingStream extends EventStreamBase implements AwaitingEventStream {
    private final EventStream input;
    private final Function initial;
    private final BiFunction reduction;
    private final Timer timer;

    private boolean hasEvent = false;
    private BooleanBinding pending = null;
    private O event = null;

    public SuccessionReducingStream(
            EventStream input,
            Function initial,
            BiFunction reduction,
            Function timerFactory) {

        this.input = input;
        this.initial = initial;
        this.reduction = reduction;
        this.timer = timerFactory.apply(this::handleTimeout);
    }

    @Override
    public ObservableBooleanValue pendingProperty() {
        if(pending == null) {
            pending = new BooleanBinding() {
                @Override
                protected boolean computeValue() {
                    return hasEvent;
                }
            };
        }
        return pending;
    }

    @Override
    public boolean isPending() {
        return pending != null ? pending.get() : hasEvent;
    }

    @Override
    protected final Subscription observeInputs() {
        return input.subscribe(this::handleEvent);
    }

    private void handleEvent(I i) {
        if(hasEvent) {
            event = reduction.apply(event, i);
        } else {
            assert event == null;
            event = initial.apply(i);
            hasEvent = true;
            invalidatePending();
        }
        timer.restart();
    }

    private void handleTimeout() {
        assert hasEvent;
        hasEvent = false;
        O toEmit = event;
        event = null;
        emit(toEmit);
        invalidatePending();
    }

    private void invalidatePending() {
        if(pending != null) {
            pending.invalidate();
        }
    }
}