package be.iminds.ilabt.jfed.experimenter_gui.editor.properties;

import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Server;
import be.iminds.ilabt.jfed.rspec.model.ExecuteService;
import be.iminds.ilabt.jfed.rspec.model.InstallService;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXExecuteService;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXInstallService;
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 be.iminds.ilabt.jfed.ui.javafx.ImageButton;
import be.iminds.ilabt.jfed.ui.javafx.util.BetterTextFieldTableCell;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import org.controlsfx.glyphfont.FontAwesome;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.net.URL;

/**
 * User: twalcari
 * Date: 9/10/2014
 * Time: 09:44
 */
public class BootScriptsTab extends AdaptivePropertiesTab<FXRspecNode> {
    private static final Logger LOG = LoggerFactory.getLogger(BootScriptsTab.class);
    private final AdaptivePropertiesDialog adaptivePropertiesDialog;


    @FXML
    private TableView<FXInstallService> downloadTableView;
    @FXML
    private TableColumn<FXInstallService, String> urlTableColumn;
    @FXML
    private TableColumn<FXInstallService, String> pathTableColumn;
    @FXML
    private TableColumn<FXInstallService, Boolean> downloadActionsTableColumn;

    @FXML
    private TableView<FXExecuteService> commandsTableView;
    @FXML
    private TableColumn<FXExecuteService, String> commandTableColumn;
    @FXML
    private TableColumn<FXExecuteService, Boolean> commandActionsTableColumn;


    public BootScriptsTab(AdaptivePropertiesDialog adaptivePropertiesDialog) {
        super("Boot scripts");
        this.adaptivePropertiesDialog = adaptivePropertiesDialog;

        setContent(FXMLUtil.createFromFXML(this));

        //add bindings to view
        DoubleBinding widthLeftBinding =
                downloadTableView.widthProperty()
                        .subtract(downloadActionsTableColumn.widthProperty())
                        .subtract(2);
        urlTableColumn.prefWidthProperty().bind(widthLeftBinding.multiply(0.66));
        pathTableColumn.prefWidthProperty().bind(widthLeftBinding.multiply(0.34));

        commandTableColumn.prefWidthProperty().bind(
                commandsTableView.widthProperty()
                        .subtract(commandActionsTableColumn.widthProperty())
                        .subtract(2));

        //setup tableviews
        urlTableColumn.setCellValueFactory(new PropertyValueFactory<>("url"));
        urlTableColumn.setCellFactory(BetterTextFieldTableCell.forTableColumn());
        pathTableColumn.setCellValueFactory(new PropertyValueFactory<>("installPath"));
        pathTableColumn.setCellFactory(BetterTextFieldTableCell.forTableColumn());
        downloadActionsTableColumn.setCellValueFactory(p -> new SimpleObjectProperty<>(p.getValue() != null));
        downloadActionsTableColumn.setCellFactory(ActionsTableCell.forTableColumn());

        commandTableColumn.setCellValueFactory(new PropertyValueFactory<>("command"));
        commandTableColumn.setCellFactory(BetterTextFieldTableCell.forTableColumn());
        commandActionsTableColumn.setCellValueFactory(p -> new SimpleObjectProperty<>(p.getValue() != null));
        commandActionsTableColumn.setCellFactory(ActionsTableCell.forTableColumn());


    }

    private static void installShowTooltipOnClick(Node node, Tooltip tooltip) {
        node.setOnMouseClicked(event -> tooltip.show(node.getScene().getWindow(), event.getScreenX(), event.getScreenY()));
    }

    @Override
    public void load(FXRspecNode rspecNode) {
        //initialize tables with information from node
        downloadTableView.getItems().addAll(rspecNode.getInstallServices());
        commandsTableView.getItems().addAll(rspecNode.getExecuteServices());
    }

    @Override
    public void save(FXRspecNode rspecNode) {
        rspecNode.setInstallServices(downloadTableView.getItems());
        rspecNode.setExecuteServices(commandsTableView.getItems());
    }

    @Override
    public void onTabShown() {

    }

    @Override
    public boolean shouldBeVisible(FXRspecNode rspecNode) {
        if (adaptivePropertiesDialog.getSelectedResource() == null) return false;
        Server authority = adaptivePropertiesDialog.getSelectedResource().getServer();
        if (authority == null) return false;
        //TODO: remove explicit filter for serverType once all these servers have the feature in the DB
        return authority.isServerType("instageni") || authority.isServerType("emulab") || authority.isServerType("orca") /* exogeni */
                || authority.hasFlag(Server.Flag.featureExecuteAndInstallService);
    }

    @Override
    public String validateConfiguration() {
        for (InstallService installService : downloadTableView.getItems()) {

            if (installService.getUrl().isEmpty())
                return "Please define an URL for each download";

            if (installService.getInstallPath().isEmpty()) {
                return "Please define a path where each download should be extracted";
            }

            try {
                new URL(installService.getUrl());
            } catch (MalformedURLException ex) {
                return "'" + installService.getUrl() + "' is not a valid URL";
            }

        }

        for (ExecuteService executeService : commandsTableView.getItems()) {
            if (executeService.getCommand().isEmpty()) {
                return "Please define a command, or remove the empty row.";
            }
        }


        return null;
    }


    private static class ActionsTableCell<S, T> extends TableCell<S, T> {
        private final HBox buttonsBox = new HBox();
        private final ImageButton removeButton;

        {
            removeButton =
                    new ImageButton(GlyphUtils.createSmallGlyph(FontAwesome.Glyph.TIMES_CIRCLE, Color.RED));
            removeButton.setOnAction(actionEvent -> removeRow());

            buttonsBox.getChildren().add(removeButton);
            setGraphic(buttonsBox);
        }

        @Override
        protected void updateItem(T item, boolean empty) {
            super.updateItem(item, empty);
            removeButton.setVisible(!empty);
        }

        @SuppressWarnings("SuspiciousMethodCalls")
        private void removeRow() {
            getTableView().getItems().remove(getTableRow().getItem());
        }

        public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> forTableColumn() {
            return ssTableColumn -> new ActionsTableCell<>();
        }


    }

    @FXML
    private void onAddDownloadAction() {
        FXInstallService newInstallService = new FXInstallService("/", "");
        downloadTableView.getItems().add(newInstallService);
    }

    @FXML
    private void onAddCommandAction() {
        FXExecuteService newExecuteService = new FXExecuteService("sh", "");
        commandsTableView.getItems().add(newExecuteService);
    }
}
