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

import be.iminds.ilabt.jfed.experimenter_gui.timeline.controller.TimelineController;
import be.iminds.ilabt.jfed.experimenter_gui.timeline.view.TimelineComponent;
import be.iminds.ilabt.jfed.experimenter_gui.timeline.view.UpdateEvent;
import be.iminds.ilabt.jfed.rspec.model.controller.ExperimentCommand;
import be.iminds.ilabt.jfed.ui.javafx.GlyphUtils;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TextArea;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import org.controlsfx.glyphfont.FontAwesome;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;

/**
 * @author Cedric
 */
public class InstantCommandOutputTab extends Tab implements TimelineComponent {
    private final TextArea output;
    private ChangeListener<Boolean> startedListener;
    private ChangeListener<Boolean> finishedListener;
    private ChangeListener<String> outputListener;
    private ChangeListener<String> errListener;
    private final ExperimentCommand command;
    private final TimelineController controller;
    private final Button stopCommand;

    public InstantCommandOutputTab(final TimelineController controller, final ExperimentCommand command) {
        this.controller = controller;
        this.command = command;
        String nodeUniqueId = command.getNodeUniqueID();
        if(nodeUniqueId.contains("@"))
            nodeUniqueId = nodeUniqueId.substring(0, nodeUniqueId.indexOf('@'));

        setText(nodeUniqueId + ": " + command.getTag());
        initListeners();

        GridPane root = new GridPane();
        output = new TextArea();
        output.setEditable(false);
        output.setMaxWidth(Double.MAX_VALUE);
        root.add(output, 0, 0);

        stopCommand = new Button();
        stopCommand.setGraphic(GlyphUtils.createSmallGlyph(FontAwesome.Glyph.STOP,Color.RED));
        root.add(stopCommand, 1, 0);
        stopCommand.setOnAction(t -> {
            controller.stopInstantCommand(command);
            stopCommand.setDisable(true);
        });
        root.getColumnConstraints().add(new ColumnConstraints(100, 200, Double.MAX_VALUE, Priority.ALWAYS, HPos.LEFT, true));
        root.getRowConstraints().add(new RowConstraints(100, 100, Double.MAX_VALUE, Priority.ALWAYS, VPos.TOP, true));

        this.setContent(root);
        this.setClosable(true);

        this.setOnClosed(t -> controller.stopInstantCommand(command));

        this.setGraphic(GlyphUtils.createSmallGlyph(FontAwesome.Glyph.BOLT, Color.YELLOW));
    }

    private String getTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(date);
    }

    private void initListeners() {
        startedListener = (ov, t, t1) -> {
            if (!command.isSkipped() && command.isStarted()) {
                output.appendText(getTime() + ":\t" + "Your command has has started.\n");
            }
        };
        command.getStartedProperty().addListener(startedListener);

        finishedListener = (ov, t, t1) -> {
            if (!command.isSkipped() && command.isFinished()) {
                output.appendText(getTime() + ":\t" + "Your command has finished.\n");
                stopCommand.setDisable(true);
                command.getStartedProperty().removeListener(startedListener);
                command.getFinishedProperty().removeListener(finishedListener);
                command.getResultProperty().removeListener(outputListener);
                command.getErrorProperty().removeListener(errListener);
            }
        };
        command.getFinishedProperty().addListener(finishedListener);

        outputListener = (ov, t, t1) -> {

            if (!Objects.equals(t1, "")) {
                Platform.runLater(() -> output.appendText(getTime() + ":\t" + t1.substring(t.length())));
            }
        };

        command.getResultProperty().addListener(outputListener);

        errListener = (ov, t, t1) -> {
            if (!Objects.equals(t1, "")) {
                Platform.runLater(() -> output.appendText(getTime() + ": ERROR\t" + t1.substring(t.length())));

            }
        };
        command.getErrorProperty().addListener(errListener);
    }

    @Override
    public void update(UpdateEvent event, Object o) {
        if (event == UpdateEvent.UNREGISTER) {
            command.getStartedProperty().removeListener(startedListener);
            command.getFinishedProperty().removeListener(finishedListener);
            command.getResultProperty().removeListener(outputListener);
            command.getErrorProperty().removeListener(errListener);
        }
    }
}
