package com.queen.counter.clock;

import com.queen.animator.Animator;
import com.queen.configuration.SceneConfiguration;
import com.queen.counter.cache.InMemoryCachedServiceLocator;
import com.queen.counter.domain.AnimationMetadata;
import com.queen.counter.service.Populator;
import com.queen.counter.service.Scroller;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import org.reactfx.*;

import javax.inject.Inject;
import java.net.URL;
import java.time.Duration;
import java.time.LocalTime;
import java.util.List;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

public class ClockPresenter implements Initializable {

    public final static int cellsize = 60;
    public final static int blockCount = 4;

    @FXML
    GridPane gridPane;

    @FXML
    Pane seconds;

    @FXML
    Button start, stop;

    @FXML
    Group group;

    @FXML
    Group minutesgroup;

    @FXML
    Pane minutes;

    @Inject
    private SceneConfiguration sceneConfiguration;

    @Inject
    private Animator animator;

    @Inject
    private Populator populator;

    @Inject
    private Scroller scroller;

    @Inject
    private InMemoryCachedServiceLocator locator;

    private Subscription subscribe;

    private List<Node> rectangles;
    private List<Node> minutesRectangles;

    private IntegerProperty clock = new SimpleIntegerProperty();
    public static LocalTime userTime;
    public static LocalTime userTimeMinutes;
    public static LocalTime userTimeSeconds;
    public static LocalTime time;
    public static LocalTime minutesTime;

    private List<Text> labels;
    private List<Text> minuteslabels;
    private boolean first = true;

    private BooleanProperty delta = new SimpleBooleanProperty(true);

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        userTime = LocalTime.of(0, 16, 12);
        userTimeMinutes = LocalTime.of(0, 16, 12);;
        userTimeSeconds = LocalTime.of(0, 16, 12);;
        populator.populateSeconds(userTime, group, "seconds");
        populator.populateSeconds(userTime, minutesgroup, "minutes");
        this.rectangles = group.getChildren().stream().filter(n -> n.getClass().equals(Rectangle.class)).collect(Collectors.toList());
        this.minutesRectangles = minutesgroup.getChildren().stream().filter(n -> n.getClass().equals(Rectangle.class)).collect(Collectors.toList());
        this.labels = group.getChildren().stream().filter(t -> t.getClass().equals(Text.class)).map(m -> (Text) m).collect(Collectors.toList());
        this.minuteslabels = minutesgroup.getChildren().stream().filter(n -> n.getClass().equals(Text.class)).map(m -> (Text) m).collect(Collectors.toList());

        seconds.setStyle("-fx-background-color: #FFFFFF;");
        minutes.setStyle("-fx-background-color: #FFFFFF;");

        delta.addListener((observable, oldValue, newValue) -> {
            first = true;
        });

        EventStream<MouseEvent> buttonClicks = EventStreams.eventsOf(start, MouseEvent.MOUSE_CLICKED).suppressWhen(animator.isTicking());
        EventStream<MouseEvent>stopClicks = EventStreams.eventsOf(stop, MouseEvent.MOUSE_CLICKED).suppressWhen(animator.isTicking().not());
        EventStream<ScrollEvent> minutesscroll = EventStreams.eventsOf(minutesgroup, ScrollEvent.SCROLL).suppressWhen(animator.isMinutesRunning());
        EventStream<?> ticks = EventStreams.ticks(Duration.ofMillis(1000));
        EventStream<ScrollEvent> scroll = EventStreams.eventsOf(group, ScrollEvent.SCROLL).suppressWhen(animator.isRunning().or(animator.isTicking()));

        scroll.subscribe(scrollEvent -> {
            scroller.scroll(this.rectangles, this.labels, scrollEvent.getDeltaY());
        });

        minutesscroll.subscribe(scrollEvent -> {
            scroller.scroll(this.minutesRectangles, this.minuteslabels, scrollEvent.getDeltaY());
        });

        buttonClicks.subscribe(click -> {
            animator.setRunning(true);
            animator.setMinutesRunning(true);
            animator.setTicking(true);
            userTime = userTime.minusSeconds(1);
            time = userTime.minusSeconds(1);
            clock.set(time.getSecond());

            this.rectangles.stream().filter(r -> r.getTranslateY() == 0).forEach(r -> {
                this.labels.stream().filter(lbl -> lbl.getId().equals(r.getId())).findFirst().ifPresent(l -> l.setText(clock.get() + ""));
            });

            List<AnimationMetadata> l1 = this.rectangles.stream().map(r -> (AnimationMetadata) locator.get(AnimationMetadata.class, r)).collect(Collectors.toList());
            animator.animate(l1, 0, locator);
            this.subscribe  = ticks.subscribe((something) -> {
                    animator.setRunning(true);
                    animator.setMinutesRunning(true);
                    animator.setTicking(true);
                    userTime = userTime.minusSeconds(1);
                    time = userTime.minusSeconds(1);
                    if (userTime.getSecond() == 0) {
                        List<AnimationMetadata> l = this.minutesRectangles.stream()
                                                        .map(r -> (AnimationMetadata) locator.get(AnimationMetadata.class, r))
                                                        .collect(Collectors.toList());

                        this.minutesRectangles.stream().filter(r -> r.getTranslateY() == 0).forEach(r -> {
                            this.minuteslabels.stream().filter(lbl -> lbl.getId().equals(r.getId())).findFirst().ifPresent(lbl -> lbl.setText(userTime.getMinute() -  2 + ""));
                        });
                        userTimeMinutes = userTime.minusMinutes(1);
                        animator.animate(l, 0, locator);
                    }
                    clock.set(time.getSecond());

                    List<AnimationMetadata> l = this.rectangles.stream()
                        .map(r -> (AnimationMetadata) locator.get(AnimationMetadata.class, r))
                        .collect(Collectors.toList());

                    this.rectangles.stream().filter(r -> r.getTranslateY() == 0).forEach(r -> {
                        this.labels.stream().filter(lbl -> lbl.getId().equals(r.getId())).findFirst().ifPresent(lbl -> lbl.setText(clock.get() + ""));
                    });
                    animator.animate(l, 0, locator);
                }
            );

        });

        stopClicks.subscribe(click -> {
            ClockPresenter.userTimeSeconds = ClockPresenter.userTimeSeconds.withSecond(ClockPresenter.userTime.getSecond());
            ClockPresenter.userTimeMinutes = ClockPresenter.userTimeMinutes.withSecond(ClockPresenter.userTime.getMinute());

            this.animator.setMinutesRunning(false);
            this.animator.setRunning(false);
            this.animator.setTicking(false);
            this.subscribe.unsubscribe();
        });
    }
}

@@ -346,113 +346,15 @@
 rty.
-BooleanProperty;%0Aimport javafx.beans.property.IntegerProperty;%0Aimport javafx.beans.property.SimpleBoolean
+Integer
 Prop
@@ -797,9 +797,85 @@
 tfx.
-*
+EventStream;%0Aimport org.reactfx.EventStreams;%0Aimport org.reactfx.Subscription
 ;%0A%0Ai
@@ -2010,49 +2010,8 @@
 ime;
-%0A    public static LocalTime minutesTime;
 %0A%0A  
@@ -2080,112 +2080,8 @@
 els;
-%0A    private boolean first = true;%0A%0A    private BooleanProperty delta = new SimpleBooleanProperty(true);
 %0A%0A  
@@ -3088,24 +3088,24 @@
 #FFFFFF;%22);%0A
+
         minu
@@ -3157,111 +3157,8 @@
 );%0A%0A
-        delta.addListener((observable, oldValue, newValue) -%3E %7B%0A            first = true;%0A        %7D);%0A%0A
     

Clean up in the Presenter.