package be.iminds.ilabt.jfed.experimenter_gui.timeline.view;

import be.iminds.ilabt.jfed.experimenter_gui.timeline.controller.TimelineController;
import be.iminds.ilabt.jfed.experimenter_gui.timeline.model.TimelineModel;
import be.iminds.ilabt.jfed.rspec.model.controller.ExperimentBarrierSegment;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.HBox;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: Cedric
 * Date: 19/02/14
 * Time: 14:02
 */
public class TimelineTimeline extends ScrollPane implements TimelineComponent {
    private final TimelineModel model;
    private final TimelineController controller;
    private final List<TimelineComponent> components;
    private final Map<ExperimentBarrierSegment, TimelineBarrierSegment> segments = new HashMap<>();
    private final Map<ExperimentBarrierSegment, TimelineBarrier> barriers = new HashMap<>();

    private final HBox root;

    //Status
    private final StringProperty statusProperty = new SimpleStringProperty();

    public TimelineTimeline(TimelineModel model, final TimelineController controller) {
        this.model = model;
        this.controller = controller;
        components = new ArrayList<>();

        getStylesheets().add(TimelineTimeline.class.getResource("Controller.css").toExternalForm());
        setStyle("-fx-focus-color: transparent;");
        setHbarPolicy(ScrollBarPolicy.ALWAYS);

        root = new HBox();
        root.setStyle("-fx-padding: 0px;");
        this.setContent(root);
        this.setFitToHeight(true);

        //Zoom-listener
        setOnScroll(t -> {
            //Zoom out
            if (t.getDeltaY() < 0) {
                controller.zoomOut();
            }
            //Zoom in
            else if (t.getDeltaY() > 0) {
                controller.zoomIn();
            }
        });

    }

    @Override
    public void resize(double d, double d1) {
        super.resize(d, d1);

        //-2: 1 pixel border top/bottom has to be deducted to prevent a scrollbar from showing up at the scrollpane
        //-10 for the HScrollBar height
        for (TimelineBarrierSegment b : segments.values())
            b.resize(d, d1 - 2 - 10);

        updateSegmentsDefaultWidth();
    }

    public void setStatus(String status) {
        statusProperty.set(status);
    }

    public StringProperty statusProperty() {
        return statusProperty;
    }

    public void updateComponents(UpdateEvent event, Object o) {
        for (TimelineComponent c : components) {
            c.update(event, o);
        }
    }

    @Override
    public void update(UpdateEvent event, Object o) {
        if (event == UpdateEvent.ADD_BARRIER) {
            TimelineBarrierSegment segment =
                    new TimelineBarrierSegment(model, controller, (ExperimentBarrierSegment) o);
            TimelineBarrier barrier = new TimelineBarrier(model, (ExperimentBarrierSegment) o);
            barrier.heightProperty().bind(segment.heightProperty());

            root.getChildren().addAll(segment, barrier);
            components.add(segment);
            components.add(barrier);
            segments.put((ExperimentBarrierSegment) o, segment);
            barriers.put((ExperimentBarrierSegment) o, barrier);

            updateSegmentsDefaultWidth();
        }

        if (event == UpdateEvent.DELETE_BARRIER) {
            ExperimentBarrierSegment b = (ExperimentBarrierSegment) o;

            segments.get(b).update(UpdateEvent.UNREGISTER, null);
            barriers.get(b).update(UpdateEvent.UNREGISTER, null);

            root.getChildren().removeAll(segments.get(b), barriers.get(b));

            segments.remove(b);
            barriers.remove(b);

            updateSegmentsDefaultWidth();
        }

        updateComponents(event, o);
    }

    /**
     * This method will make sure the children will fill up all the available space.
     * I.e. when the present segments combined are smaller than the width of the scrollPane's ViewPort,
     * then the segments should be widened a little to fill up the leftover space.
     */
    private void updateSegmentsDefaultWidth() {
        if (!segments.isEmpty()) {

            double newSegmentDefaultWidth = ((getWidth() - 2) / segments.size()) - TimelineBarrier.DEFAULT_WIDTH;

            if (newSegmentDefaultWidth < 100)
                newSegmentDefaultWidth = 100;

            for (TimelineBarrierSegment s : segments.values()) {
                s.setDefaultWidth(newSegmentDefaultWidth);
            }

        }
    }
}
