package be.iminds.ilabt.jfed.experimenter_gui.slice.errors;

import be.iminds.ilabt.jfed.call_log_output.SerializableApiCallDetails;
import be.iminds.ilabt.jfed.experiment.tasks.TaskExecutionFinishedListener;
import be.iminds.ilabt.jfed.experimenter_gui.call_gui.TasksWindow;
import be.iminds.ilabt.jfed.highlevel.controller.TaskExecution;
import be.iminds.ilabt.jfed.log.cache.ApiCallDetailsCache;
import be.iminds.ilabt.jfed.log.cache.ApiCallDetailsRef;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * User: twalcari
 * Date: 2/22/2017
 * Time: 16:14
 */
@Singleton
public class ErrorDialogs implements TaskExecutionFinishedListener {

    private final TasksWindow tasksWindow;
    private final ApiCallDetailsCache apiCallDetailsCache;

    @Inject
    public ErrorDialogs(TasksWindow tasksWindow, ApiCallDetailsCache apiCallDetailsCache) {
        this.tasksWindow = tasksWindow;
        this.apiCallDetailsCache = apiCallDetailsCache;
    }

    @Override
    public void onTaskExecutionFinished(TaskExecution<?> taskExecution) {


        for (ApiCallDetailsRef apiCallDetailsRef : taskExecution.getApiCallHistory()) {

            final SerializableApiCallDetails details = apiCallDetailsCache.getApiCallDetails(apiCallDetailsRef);
            if (details.getGeniResponseCodeIsSuccess() != null
                    && !details.getGeniResponseCodeIsSuccess()
                    && details.getGeniResponseOutput() != null) {

                processCallError(details);

            }
        }
    }

    private void processCallError(SerializableApiCallDetails details) {

        for (ErrorDialogDefinition errorDialogDef : ERROR_DIALOG_DEFS) {
            if (errorDialogDef.matchesCallError(details)) {
                Platform.runLater(() -> {
                    Alert error = new Alert(Alert.AlertType.ERROR);
                    error.setTitle(errorDialogDef.getDialogTitle(details));
                    error.setHeaderText(error.getTitle());
                    error.setContentText(errorDialogDef.getDialogMessage(details));


                    ButtonType moreInfoButton = new ButtonType("More Info");

                    error.getButtonTypes().setAll(ButtonType.OK, moreInfoButton);
                    error.showAndWait()
                            .filter(buttonType -> buttonType == moreInfoButton)
                            .ifPresent(buttonType -> tasksWindow.showApiCall(details));
                });
            }
        }

    }

    private static ErrorDialogDefinition[] ERROR_DIALOG_DEFS = {
            new DuplicateSlicenameErrorDialogDef(),
            new CouldNotMapToResourcesDef(),
            };


    private interface ErrorDialogDefinition {
        boolean matchesCallError(SerializableApiCallDetails details);

        String getDialogTitle(SerializableApiCallDetails details);

        String getDialogMessage(SerializableApiCallDetails details);
    }

    private static class DuplicateSlicenameErrorDialogDef implements ErrorDialogDefinition {

        @Override
        public boolean matchesCallError(SerializableApiCallDetails details) {
            return details.getXmlRpcGeniResponseOutput().contains("already a registered slice") ||
                    details.getXmlRpcGeniResponseOutput().contains("has the same name as the slice you are trying to create");
        }

        @Override
        public String getDialogTitle(SerializableApiCallDetails details) {
            return "Experiment name already in use";
        }

        @Override
        public String getDialogMessage(SerializableApiCallDetails details) {
            return "The requested experiment name is already in use. Please create your experiment with a different name.";
        }
    }

    private static class CouldNotMapToResourcesDef implements ErrorDialogDefinition {

        @Override
        public boolean matchesCallError(SerializableApiCallDetails details) {
            return details.getXmlRpcGeniResponseValue().toLowerCase().contains("could not map to resources");
        }

        @Override
        public String getDialogTitle(SerializableApiCallDetails details) {
            return "Request could not be mapped to resources";
        }

        @Override
        public String getDialogMessage(SerializableApiCallDetails details) {
            return "Your request could not be mapped to resources on the testbed. " +
                    "Either your requested topology is impossible, " +
                    "or not enough resources are currently available.\n\nDetails:\n" +
                    details.getXmlRpcGeniResponseOutput().replace("\\n", "\n").trim();
        }
    }
}
