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

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.experimenter_gui.util.ImageSize;
import be.iminds.ilabt.jfed.experimenter_gui.util.ImageUtil;
import be.iminds.ilabt.jfed.rspec.model.controller.ExperimentCommand;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecNode;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.scene.control.Tab;
import javafx.scene.control.TextArea;
import javafx.scene.image.ImageView;

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

/**
 * @author Cedric
 */
public class NodeOutputTab extends Tab implements TimelineComponent {

    private final TextArea output;

    private final Map<ExperimentCommand, ChangeListener<Boolean>> startedListeners = new HashMap<>();
    private final Map<ExperimentCommand, ChangeListener<Boolean>> finishedListeners = new HashMap<>();
    private final Map<ExperimentCommand, ChangeListener<String>> outputListeners = new HashMap<>();
    private final Map<ExperimentCommand, ChangeListener<String>> errListeners = new HashMap<>();
    private final ImageUtil imageUtil;

    public NodeOutputTab(FXRspecNode n, ImageUtil imageUtil) {
        this.imageUtil = imageUtil;
        this.setText(n.getClientId());
        output = new TextArea();
        output.setEditable(false);
        this.setContent(output);

        ImageView icon = new ImageView(this.imageUtil.getRspecNodeImage(n, ImageSize.X_SMALL));
        icon.setFitHeight(16);
        icon.setFitWidth(16);
        this.setGraphic(icon);
    }

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

    @Override
    public void update(UpdateEvent event, Object o) {
        if (event == UpdateEvent.ADD_COMMAND) {
            final ExperimentCommand command = (ExperimentCommand) o;
            if (Objects.equals(command.getNodeUniqueID(), this.getText())) {
                ChangeListener<Boolean> startedListener = (ov, t, t1) -> {
                    if (!command.isSkipped() && command.isStarted()) {
                        output.appendText(getTime() + " " + command.getTag() + ":\tYour command has started.\n");
                    }
                };
                command.getStartedProperty().addListener(startedListener);
                startedListeners.put(command, startedListener);

                ChangeListener<Boolean> finishedListener = (ov, t, t1) -> {
                    if (!command.isSkipped() && command.isFinished()) {
                        output.appendText(getTime() + " " + command.getTag() + ":\t" + "Your command has finished.\n");
                    }
                };
                command.getFinishedProperty().addListener(finishedListener);
                finishedListeners.put(command, finishedListener);

                ChangeListener<String> outputListener = (ov, t, t1) -> {
                    if (!Objects.equals(t1, "")) {
                        Platform.runLater(() -> output.appendText(getTime() + " " + command.getTag() + ":\t" + t1.substring(t.length())));

                    }
                };

                command.getResultProperty().addListener(outputListener);
                outputListeners.put(command, outputListener);

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

                    }
                };
                command.getErrorProperty().addListener(errListener);
                errListeners.put(command, errListener);
            }
        }
    }

    public void unregister() {
        for (ExperimentCommand c : startedListeners.keySet()) {
            c.getStartedProperty().removeListener(startedListeners.get(c));
        }
        for (ExperimentCommand c : finishedListeners.keySet()) {
            c.getFinishedProperty().removeListener(finishedListeners.get(c));
        }
        for (ExperimentCommand c : outputListeners.keySet()) {
            c.getResultProperty().removeListener(outputListeners.get(c));
        }
        for (ExperimentCommand c : errListeners.keySet()) {
            c.getErrorProperty().removeListener(errListeners.get(c));
        }
    }
}
