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

import be.iminds.ilabt.jfed.connectivity_tester.ConnectivityTest;
import be.iminds.ilabt.jfed.experimenter_gui.ui.status.TaskStatusIndicator;
import be.iminds.ilabt.jfed.preferences.GuiPreferenceKey;
import be.iminds.ilabt.jfed.preferences.JFedGuiPreferences;
import be.iminds.ilabt.jfed.ui.javafx.dialogs.JFDialogs;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.value.ObservableObjectValue;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.Pane;
import javafx.stage.FileChooser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * User: twalcari
 * Date: 1/3/14
 * Time: 9:49 AM
 */
public class ConnectivityTesterController {
    private static final Logger LOG = LoggerFactory.getLogger(ConnectivityTesterController.class);
    private static final String TESTRESULT_EXTENSION = ".txt";
    private static final DateTimeFormatter FILE_DATE_TIME_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm").withZone(ZoneId.systemDefault());

    private final ConnectivityTester connectivityTester;
    private final JFedGuiPreferences jFedPreferences;

    @FXML
    public ConnectivityTestPane connectivityTestPane;
    @FXML
    private ListView<ConnectivityTestTask> testsList;

    /*  @FXML
      private StackPane testsStackPane;
      @FXML
      private ScrollPane testsScrollPane;          */
    @FXML
    private Pane testsAccordion;
    @FXML
    private Button saveButton;
    @FXML
    private Button restartButton;

   /* @FXML
    private HBox initializationBox;     */

    @Inject
    public ConnectivityTesterController(ConnectivityTester connectivityTester, JFedGuiPreferences jFedPreferences) {
        this.connectivityTester = connectivityTester;
        this.jFedPreferences = jFedPreferences;
    }

    @FXML
    public void initialize() {
        restartButton.disableProperty().bind(connectivityTester.testsFinishedProperty().not());
        saveButton.disableProperty().bind(connectivityTester.testsFinishedProperty().not());

        testsList.setCellFactory(param -> new ConnectivityTestTaskListCell());

        testsList.setItems(connectivityTester.getTestTasks());

        connectivityTestPane.visibleProperty().bind(testsList.getSelectionModel().selectedItemProperty().isNotNull());
        connectivityTestPane.managedProperty().bind(connectivityTestPane.visibleProperty());
        connectivityTestPane.resultProperty().bind(new ObjectBinding<ConnectivityTest.ConnectivityTestResult>() {

            {
                bind(testsList.getSelectionModel().selectedItemProperty());
            }

            @Override
            protected ConnectivityTest.ConnectivityTestResult computeValue() {
                if (testsList.getSelectionModel().getSelectedItem() != null)
                    return testsList.getSelectionModel().getSelectedItem().getValue();
                else
                    return null;
            }


        });
    }


    @FXML
    private void onRestartAction() {
        connectivityTester.restartTests();
    }

    @FXML
    private void onSaveAction() {
        FileChooser fc = new FileChooser();
        fc.setTitle("Save Connectivity Test Result");
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("Text file (*." + TESTRESULT_EXTENSION + ")", "*" + TESTRESULT_EXTENSION));
        fc.setInitialFileName("connectivity-test-" + FILE_DATE_TIME_FORMATTER.format(connectivityTester.getTestsStartDate()) + ".txt");


        //set the default save dir
        if (System.getProperty("user.home") != null)
            fc.setInitialDirectory(new File(System.getProperty("user.home")));

        if (jFedPreferences.containsPreference(GuiPreferenceKey.PREF_RSPECFOLDER_REQUEST)) {
            File dir = new File(jFedPreferences.getString(GuiPreferenceKey.PREF_RSPECFOLDER_REQUEST));
            if (dir.exists()) {
                fc.setInitialDirectory(dir);
            }
        }

        File file = fc.showSaveDialog(saveButton.getScene().getWindow());

        if (file == null) //user cancelled the dialog
            return;


        //save folder in which the file was saved for future file selector dialogs
        jFedPreferences.setString(GuiPreferenceKey.PREF_RSPECFOLDER_REQUEST,
                file.getParentFile().getAbsolutePath());

        if (!file.getAbsolutePath().endsWith(TESTRESULT_EXTENSION))
            file = new File(file.getAbsolutePath() + TESTRESULT_EXTENSION);

        try {
            connectivityTester.saveResultsToFile(file);

            JFDialogs.create()
                    .owner(saveButton.getScene().getWindow())
                    .message(String.format("The connectivity test results were saved to '%s'", file.toString()))
                    .masthead("Successfully saved connectivity test results")
                    .title(null)
                    .showInformation();

        } catch (IOException e) {
            JFDialogs.create()
                    .owner(saveButton.getScene().getWindow())
                    .message("An error occurred while saving the connectivity test: " + e.getMessage())
                    .masthead("Saving connectivity test results failed")
                    .title("Saving connectivity test results failed")
                    .showException(e);
        }
    }

    public ConnectivityTester getConnectivityTester() {
        return connectivityTester;
    }

    private static class ConnectivityTestTaskListCell extends ListCell<ConnectivityTestTask> {
        private final TaskStatusIndicator taskStatusIndicator = new TaskStatusIndicator();

        {
            setAlignment(Pos.CENTER_LEFT);
            setContentDisplay(ContentDisplay.LEFT);
        }

        @Override
        protected void updateItem(ConnectivityTestTask item, boolean empty) {
            super.updateItem(item, empty);

            taskStatusIndicator.statusProperty().unbind();

            if (!empty) {
                ObservableObjectValue<TaskStatusIndicator.Status> statusBinding =
                        new ObjectBinding<TaskStatusIndicator.Status>() {
                            {
                                bind(item.valueProperty());
                            }

                            @Override
                            protected TaskStatusIndicator.Status computeValue() {
                                if (item.getValue() == null)
                                    return TaskStatusIndicator.Status.INACTIVE;
                                if (item.getValue().getStatus() == null)
                                    return TaskStatusIndicator.Status.FAILED;
                                switch (item.getValue().getStatus()) {
                                    case SUCCEEDED:
                                        return TaskStatusIndicator.Status.SUCCESS;
                                    case FAILED:
                                        return TaskStatusIndicator.Status.FAILED;
                                    case WARNING:
                                        return TaskStatusIndicator.Status.WARNING;
                                    case SKIPPED:
                                        return TaskStatusIndicator.Status.INACTIVE;
                                    default:
                                        throw new RuntimeException("Unexpected status: " + item.getValue().getStatus());
                                }
                            }
                        };


                taskStatusIndicator.statusProperty().bind(Bindings.when(item.runningProperty()).then(TaskStatusIndicator.Status.BUSY).otherwise(statusBinding));

                setGraphic(taskStatusIndicator);
                setText(item.getTest().getName());
            } else {
                setGraphic(null);
                setText(null);
            }
        }
    }
}
