package be.iminds.ilabt.jfed.experimenter_gui.call_gui;

import be.iminds.ilabt.jfed.highlevel.controller.JavaFXTaskThread;
import be.iminds.ilabt.jfed.highlevel.controller.TaskExecution;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
import org.controlsfx.glyphfont.FontAwesome;
import org.controlsfx.glyphfont.Glyph;
import org.controlsfx.glyphfont.GlyphFont;
import org.controlsfx.glyphfont.GlyphFontRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * TaskLabel
 */
public class TaskLabel extends HBox {
    private static final Logger LOG = LoggerFactory.getLogger(TaskLabel.class);

    private static final GlyphFont fontAwesome = GlyphFontRegistry.font("FontAwesome");

    private final Label id;
    private final Label name;
    //private final Label state;
    private final ObjectProperty<JavaFXTaskThread.FXTaskExecution> task = new SimpleObjectProperty<>(null);
    private final ChangeListener<? super be.iminds.ilabt.jfed.highlevel.controller.TaskExecution.TaskState>
            stateChangeListener;

    public TaskLabel() {
        id = new Label("");
        id.getStyleClass().add("task-label-id");
        name = new Label("");
        name.getStyleClass().add("task-label-name");
        //state = new Label("");

        getStylesheets().add(TaskLabel.class.getResource("calls.css").toExternalForm());
        getStyleClass().add("task-label");

        getChildren().addAll(id, name);//, state);

        stateChangeListener = (observableValue, oldTaskState, newTaskState) -> changeState(oldTaskState, newTaskState);

        task.addListener((observableValue, oldFXTaskExecution, newFXTaskExecution) -> {
            be.iminds.ilabt.jfed.highlevel.controller.TaskExecution.TaskState oldTaskState = null;
            if (oldFXTaskExecution != null) {
                //state.textProperty().unbind();
                oldTaskState = oldFXTaskExecution.getState();
                oldFXTaskExecution.stateProperty().removeListener(stateChangeListener);
            }
            if (newFXTaskExecution != null) {
                name.setText(newFXTaskExecution.getName());
                id.setText(newFXTaskExecution.getId());
                //state.textProperty().bind(Bindings.convert(newFXTaskExecution.stateProperty()));
                newFXTaskExecution.stateProperty().addListener(stateChangeListener);
                changeState(oldTaskState, newFXTaskExecution.getState());
            }
        });


    }

    private static final Set<String> allStateStyleClasses = Arrays.stream(TaskExecution.TaskState.values()).
            map(TaskLabel::taskStateToStyleClass).collect(Collectors.toSet());

    private static String taskStateToStyleClass(be.iminds.ilabt.jfed.highlevel.controller.TaskExecution.TaskState state) {
        switch (state) {
            case UNSUBMITTED: {
                return "taskstate-unsubmitted";
            }
            case BLOCKED: {
                return "taskstate-blocked";
            }
            case QUEUED:
            case FUTURE: {
                return "taskstate-queued";
            }
            case RUNNING: {
                return "taskstate-running";
            }
            case FAILED:
            case CANCELLED: {
                return "taskstate-failed";
            }
            case SUCCESS: {
                return "taskstate-success";
            }
            default: {
                LOG.debug("Unexpected state: "+state);
                //pick a default
                return "taskstate-unsubmitted";
                //throw new RuntimeException("Unexpected state: "+state);
            }
        }
    }

    private static FontAwesome.Glyph taskStateToIcon(be.iminds.ilabt.jfed.highlevel.controller.TaskExecution.TaskState state) {
        switch (state) {
            case UNSUBMITTED: {
                return FontAwesome.Glyph.ASTERISK;
            }
            case BLOCKED: {
                return FontAwesome.Glyph.PAUSE;
            }
            case QUEUED: {
                return FontAwesome.Glyph.REORDER; //bars
            }
            case RUNNING: {
                return FontAwesome.Glyph.PLAY;
            }
            case FAILED: {
                return FontAwesome.Glyph.EXCLAMATION_TRIANGLE;
            }
            case SUCCESS: {
                return FontAwesome.Glyph.CHECK_SQUARE;
            }
            default:
                throw new RuntimeException("Unexpected state");
        }
    }

    private void changeState(be.iminds.ilabt.jfed.highlevel.controller.TaskExecution.TaskState oldTaskState, be.iminds.ilabt.jfed.highlevel.controller.TaskExecution.TaskState newTaskState) {

        if (newTaskState != null) {
            String newStyleClass = taskStateToStyleClass(newTaskState);
            getStyleClass().removeAll(allStateStyleClasses);
            getStyleClass().add(newStyleClass);
            Glyph newIcon = fontAwesome.create(taskStateToIcon(newTaskState));
            newIcon.setTooltip(new Tooltip(newTaskState.name()));
            id.setGraphic(newIcon);
        } else {
            id.setGraphic(null);
            id.setText("");
            name.setText("");
        }
    }

    public void setTask(JavaFXTaskThread.FXTaskExecution t) {
        task.set(t);
    }

    public ObjectProperty<JavaFXTaskThread.FXTaskExecution> taskProperty() {
        return task;
    }
}
