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

import be.iminds.ilabt.jfed.experimenter_gui.timeline.controller.TimelineController;
import be.iminds.ilabt.jfed.experimenter_gui.util.ui.UIUtils;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecNode;
import be.iminds.ilabt.jfed.ui.javafx.FXMLUtil;
import be.iminds.ilabt.jfed.ui.javafx.GlyphUtils;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Window;
import org.controlsfx.glyphfont.FontAwesome;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class InstantCommandDialog extends GridPane {
    private final TimelineController controller;
    @FXML
    private TextField commandTextField;
    @FXML
    private TextField tagTextField;
    @FXML
    private TreeView<String> treeView;

    private final Map<CheckBoxTreeItem<String>, FXRspecNode> nodesMap = new HashMap<>();

    private final Dialog<ButtonType> dialog;

    private InstantCommandDialog(Window parentWindow, final TimelineController controller, List<FXRspecNode> nodes) {
        this.controller = controller;

        //initialize the Scene
        FXMLUtil.injectFXML(this);

        CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<>("Your experiment");
        rootItem.setExpanded(true);
        treeView.setRoot(rootItem);
        treeView.setEditable(false);

        treeView.setCellFactory(CheckBoxTreeCell.forTreeView());

        for (FXRspecNode n : nodes) {
            CheckBoxTreeItem<String> cb = new CheckBoxTreeItem<>(n.getClientId());
            rootItem.getChildren().add(cb);
            nodesMap.put(cb, n);
        }

        tagTextField.setText("Instant command " + controller.getModel().nextInstantCommandNumber());

        setOnKeyPressed(keyEvent -> {
            if (keyEvent.getCode() == KeyCode.ENTER) {
                launchInstantCommands();
                keyEvent.consume();
            }
        });

        Platform.runLater(tagTextField::requestFocus);

        //initialize dialog
        dialog = new Dialog<>();
        dialog.initOwner(parentWindow);
        dialog.setTitle("Instant command");
        dialog.setHeaderText("Execute a command instantly and off the record on the selected nodes");
        dialog.setGraphic(GlyphUtils.createDialogGlyph(FontAwesome.Glyph.BOLT, Color.YELLOW));
        dialog.getDialogPane().setContent(UIUtils.wrapWithDecorationPane(this));

        dialog.getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL);

        dialog.resultProperty().addListener(observable -> {
            if (dialog.getResult() == ButtonType.OK)
                launchInstantCommands();
        });

        ValidationSupport validationSupport = new ValidationSupport();
        validationSupport.registerValidator(tagTextField, Validator.createEmptyValidator("Tag is required!"));
        validationSupport.registerValidator(commandTextField, Validator.createEmptyValidator("Command is required!"));


        BooleanBinding atLeastOneItemSelected = rootItem.selectedProperty().or(rootItem.indeterminateProperty());

        Node okButton = dialog.getDialogPane().lookupButton(ButtonType.OK);
        okButton.disableProperty().bind(validationSupport.invalidProperty().or(atLeastOneItemSelected.not()));
    }

    public static void showSimpleInstantCommandDialog(Window parentWindow, TimelineController controller, List<FXRspecNode> nodes) {
        new InstantCommandDialog(parentWindow, controller, nodes).showDialog();
    }

    private void showDialog() {
        dialog.show();
    }


    public void launchInstantCommands() {
        List<String> selectedNodes = nodesMap.entrySet().stream()
                .filter(entry -> entry.getKey().isSelected())
                .map(Map.Entry::getValue)
                .map(FXRspecNode::getUniqueId)
                .collect(Collectors.toList());
        assert !selectedNodes.isEmpty();

        controller.instantCommand(tagTextField.getText(), commandTextField.getText(), selectedNodes);
    }
}
