package be.iminds.ilabt.jfed.experimenter_gui.ui.progressbar;

import be.iminds.ilabt.jfed.experimenter_gui.ExperimenterGUI;
import be.iminds.ilabt.jfed.experimenter_gui.bugreporting.BugReportToServerTask;
import be.iminds.ilabt.jfed.experimenter_gui.slice.actions.SaveManifestAction;
import be.iminds.ilabt.jfed.experimenter_gui.tasks.DeleteDiskImageTask;
import be.iminds.ilabt.jfed.experimenter_gui.tasks.RecoverSliceTask;
import be.iminds.ilabt.jfed.ui.javafx.GlyphUtils;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.collections.ListChangeListener;
import javafx.concurrent.Task;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
import javafx.util.Duration;
import org.controlsfx.control.PopOver;
import org.controlsfx.control.TaskProgressView;
import org.controlsfx.glyphfont.FontAwesome;

/**
 * User: twalcari
 * Date: 11/28/2014
 * Time: 11:48
 */
public class TasksProgressIndicator extends HBox {
    private final Label progressLabel = new Label();
    private final ProgressBar progressBar = new ProgressBar();

    private final PopOver popOver = new PopOver();
    private final TaskProgressView<Task<?>> taskProgressView = new TaskProgressView<>();

    private final InvalidationListener progressInvalidationListener = invalidated -> progressBar.setProgress(taskProgressView.getTasks().stream().mapToDouble(Task::getProgress).average().orElse(0));


    public TasksProgressIndicator() {
        setAlignment(Pos.CENTER);
        setVisible(false);
        setSpacing(5);

        progressBar.setProgress(0);
        progressBar.setPrefWidth(100);

        getChildren().addAll(progressLabel, progressBar);
        HBox.setHgrow(progressBar, Priority.ALWAYS);

        popOver.setContentNode(taskProgressView);
        popOver.setArrowLocation(PopOver.ArrowLocation.BOTTOM_RIGHT);
        popOver.setAutoHide(true);


        taskProgressView.setGraphicFactory(task -> {
            if (task instanceof RecoverSliceTask) {
                return GlyphUtils.createDialogGlyph(FontAwesome.Glyph.AMBULANCE, Color.GREEN);
            } else if (task instanceof DeleteDiskImageTask) {
                return GlyphUtils.createDialogGlyph(FontAwesome.Glyph.TIMES, Color.RED);
            } else if (task instanceof SaveManifestAction.SaveManifestTask) {
                return GlyphUtils.createDialogGlyph(FontAwesome.Glyph.SAVE, Color.BLUE);
            } else if (task instanceof SaveManifestAction.SaveCSVTask) {
                return GlyphUtils.createDialogGlyph(FontAwesome.Glyph.SAVE, Color.ORANGERED);
            } else if (task instanceof ExperimenterGUI.CreateExperimentTask) {
                return GlyphUtils.createDialogGlyph(FontAwesome.Glyph.PLAY, Color.GREEN);
            } else if (task instanceof BugReportToServerTask) {
                return GlyphUtils.createDialogGlyph(FontAwesome.Glyph.BUG, Color.ORANGE);
            } else {
                return null;
            }
        });


        progressBar.setOnMouseEntered(event -> {
            if (!taskProgressView.getTasks().isEmpty()) {
                Point2D locationOnScreen = localToScreen(getWidth() / 2, 0);
                popOver.show(TasksProgressIndicator.this, locationOnScreen.getX(), locationOnScreen.getY(), Duration.seconds(0.5));
            }
        });


        visibleProperty().bind(Bindings.isNotEmpty(taskProgressView.getTasks()));
        taskProgressView.prefHeightProperty().bind(Bindings.min(300, Bindings.size(taskProgressView.getTasks()).multiply(70)));

        taskProgressView.getTasks().addListener((InvalidationListener) observable -> updateText());
        taskProgressView.getTasks().addListener((ListChangeListener<Task<?>>) c -> {
            while (c.next()) {
                if (c.wasAdded()) {
                    for (Task t : c.getAddedSubList()) {
                        t.progressProperty().addListener(new WeakInvalidationListener(progressInvalidationListener));
                    }
                }
            }
        });
    }

    private void updateText() {
        if (taskProgressView.getTasks().size() == 1) {
            Task<?> task = taskProgressView.getTasks().get(0);
            progressLabel.setText(task.getTitle());
        } else {
            progressLabel.setText(String.format("%d tasks running", taskProgressView.getTasks().size()));
        }
    }


    public void followTaskProgress(Task<?> task) {
        taskProgressView.getTasks().add(task);
    }
}
