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

com.netopyr.reduxfx.component.impl.ComponentDriver Maven / Gradle / Ivy

package com.netopyr.reduxfx.component.impl;

import com.netopyr.reduxfx.component.ComponentBase;
import com.netopyr.reduxfx.component.command.FireEventCommand;
import com.netopyr.reduxfx.component.command.IntegerChangedCommand;
import com.netopyr.reduxfx.component.command.ObjectChangedCommand;
import com.netopyr.reduxfx.driver.Driver;
import com.netopyr.reduxfx.updater.Command;
import io.reactivex.Flowable;
import io.reactivex.processors.FlowableProcessor;
import io.reactivex.processors.PublishProcessor;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.Event;
import javafx.event.EventHandler;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;

import java.util.Objects;
import java.util.function.BiConsumer;

public class ComponentDriver implements Driver {

    private static final String BEAN_MUST_NOT_BE_NULL = "Bean must not be null";
    private static final String NAME_MUST_NOT_BE_NULL = "Name must not be null";

    private final FlowableProcessor commandProcessor = PublishProcessor.create();
    private final FlowableProcessor actionProcessor = PublishProcessor.create();

    private Flowable> fireEventCommandFlowable;
    private Flowable integerChangedCommandFlowable;
    private Flowable> objectChangedCommandFlowable;


    @Override
    public Subscriber getCommandSubscriber() {
        return commandProcessor;
    }

    @Override
    public Publisher getActionPublisher() {
        return actionProcessor;
    }


    private Flowable getIntegerChangedCommandFlowable() {
        if (integerChangedCommandFlowable == null) {
            final FlowableProcessor processor = PublishProcessor.create();
            commandProcessor
                    .filter(command -> command instanceof IntegerChangedCommand)
                    .map(command -> (IntegerChangedCommand) command)
                    .subscribe(processor);
            integerChangedCommandFlowable = processor;
        }
        return integerChangedCommandFlowable;
    }

    private Flowable> getObjectChangedCommandFlowable() {
        if (objectChangedCommandFlowable == null) {
            final FlowableProcessor> processor = PublishProcessor.create();
            commandProcessor
                    .filter(command -> command instanceof ObjectChangedCommand)
                    .map(command -> (ObjectChangedCommand) command)
                    .subscribe(processor);
            objectChangedCommandFlowable = processor;
        }
        return objectChangedCommandFlowable;
    }

    private Flowable> getFireEventCommandFlowable() {
        if (fireEventCommandFlowable == null) {
            final FlowableProcessor> processor = PublishProcessor.create();
            commandProcessor
                    .filter(command -> command instanceof FireEventCommand)
                    .map(command -> (FireEventCommand) command)
                    .subscribe(processor);
            fireEventCommandFlowable = processor;
        }
        return fireEventCommandFlowable;
    }


    public ReadOnlyIntegerProperty createReadOnlyIntegerProperty(Object bean, String name) {
        Objects.requireNonNull(bean, BEAN_MUST_NOT_BE_NULL);
        Objects.requireNonNull(name, NAME_MUST_NOT_BE_NULL);

        final Publisher propertyPublisher =
                getIntegerChangedCommandFlowable().filter(command -> name.equals(command.getPropertyName()));
        return new ReduxFXReadOnlyIntegerProperty(bean, name, propertyPublisher);
    }

    public  ReadOnlyObjectProperty createReadOnlyObjectProperty(Object bean, String name) {
        Objects.requireNonNull(bean, BEAN_MUST_NOT_BE_NULL);
        Objects.requireNonNull(name, NAME_MUST_NOT_BE_NULL);

        final Publisher> propertyObervable =
                getObjectChangedCommandFlowable().filter(command -> name.equals(command.getPropertyName()));
        return new ReduxFXReadOnlyObjectProperty<>(bean, name, propertyObervable);
    }


    public  ObjectProperty createObjectProperty(Object bean, String name, ComponentBase.ChangeListener listener) {
        Objects.requireNonNull(bean, BEAN_MUST_NOT_BE_NULL);
        Objects.requireNonNull(name, NAME_MUST_NOT_BE_NULL);
        Objects.requireNonNull(listener, "Listener must not be null");

        final Publisher> propertyObervable =
                getObjectChangedCommandFlowable().filter(command -> name.equals(command.getPropertyName()));
        final BiConsumer dispatcher = (oldValue, newValue) -> actionProcessor.onNext(listener.onChange(oldValue, newValue));
        return new ReduxFXObjectProperty<>(bean, name, propertyObervable, dispatcher);
    }


    @SuppressWarnings("unchecked")
    public  ObjectProperty> createEventHandlerProperty(Object bean, String name) {
        Objects.requireNonNull(bean, BEAN_MUST_NOT_BE_NULL);
        Objects.requireNonNull(name, NAME_MUST_NOT_BE_NULL);

        final ObjectProperty> property = new SimpleObjectProperty<>(bean, name);
        getFireEventCommandFlowable()
                .filter(command -> name.equals(command.getEventName()))
                .forEach(command -> {
                    final EventHandler eventHandler = property.get();
                    if (eventHandler != null) {
                        eventHandler.handle((E) command.getEvent());
                    }
                });

        return property;
    }
}