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

import be.iminds.ilabt.jfed.experimenter_gui.dialogs.DialogsFactory;
import be.iminds.ilabt.jfed.experimenter_gui.editor.EditableRspec;

import be.iminds.ilabt.jfed.lowlevel.TestbedInfoSource;
import be.iminds.ilabt.jfed.lowlevel.authority.AuthorityFinder;
import be.iminds.ilabt.jfed.rspec.model.GeantTestbedType;
import be.iminds.ilabt.jfed.rspec.model.ModelRspecType;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXModelRspec;
import be.iminds.ilabt.jfed.rspec.rspec_source.RequestRspecSource;
import be.iminds.ilabt.jfed.ui.javafx.dialogs.JFDialogs;
import be.iminds.ilabt.jfed.util.GeniUrn;
import javafx.stage.Window;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * User: twalcari
 * Date: 5/20/2015
 * Time: 09:14
 */
public class StartExperimentAction extends RspecValidatingEditorAction<Void> {
    private static final Logger LOG = LoggerFactory.getLogger(StartExperimentAction.class);


    private final AuthorityFinder authorityFinder;
    private final DialogsFactory dialogsFactory;

    StartExperimentAction(EditableRspec editableRspec, Window parentWindow,
                          EditorActionsFactory editorActionsFactory, TestbedInfoSource testbedInfoSource, AuthorityFinder authorityFinder, DialogsFactory dialogsFactory) {
        super(editableRspec, parentWindow, editorActionsFactory, testbedInfoSource, authorityFinder);
        this.authorityFinder = authorityFinder;
        this.dialogsFactory = dialogsFactory;
    }


    @Override
    public Void call() {
        if (!prepareAndValidateRequestRspec()) {
            LOG.debug("Starting experiment aborted because validation failed");
            return null;
        }

        RequestRspecSource requestRspecSource = editableRspec.getRequestRspecSource();
        assert (requestRspecSource.getStringRspec() != null);

        if (requestRspecSource.getAllComponentManagerUrns().isEmpty()
                && !hasGtsResources(requestRspecSource)) {
            JFDialogs.create()
                    .owner(parentWindow)
                    .message("jFed could not find component managers in the RSpec XML. " +
                            "Either there is an error in the RSpec, or jFed does not support this RSpec. " +
                            "Either way, it is impossible to continue, \"Run Experiment\" aborted.")
                    .masthead("Fatal Error")
                    .showError();
            return null;
        }

        GeantTestbedType invalidGeantTestbedType= findInvalidGtsResource(requestRspecSource);
        if(invalidGeantTestbedType != null){
            JFDialogs.create()
                    .owner(parentWindow)
                    .message(String.format("The Geant Testbed '%s' does not contain anything. " +
                            "Either remove it, or add resources to the testbed",
                            invalidGeantTestbedType.getName()))
                    .masthead("Fatal GTS Error")
                    .showError();
            return null;
        }


        Set<GeniUrn> unknownComponentManagerUrns = getUnkownComponentManagerUrns(requestRspecSource);

        if (!unknownComponentManagerUrns.isEmpty()) {
            String urns = unknownComponentManagerUrns.stream().map(GeniUrn::toString).collect(Collectors.joining(", "));

            boolean isStitching =
                    requestRspecSource.getStringRspec().isStitching(testbedInfoSource, authorityFinder);
            if (!isStitching) {
                JFDialogs.create()
                        .owner(parentWindow)
                        .message("jFed does not have information about some component managers in the RSpec XML: " + urns + " \n" +
                                "It is impossible to correctly continue, \"Run Experiment\" aborted.")
                        .masthead("Fatal Error")
                        .showError();
                return null;
            } else
                JFDialogs.create()
                        .owner(parentWindow)
                        .message("jFed does not have information about some component managers in the RSpec XML: " + urns + " \n" +
                                "Since the RSpec uses stitching, it is possible to continue. " +
                                "There might be an error later on, or the problem might fix itself.")
                        .masthead("Dragons Ahead!")
                        .showWarning();

        }

        dialogsFactory.showCreateSliceDialog(parentWindow, requestRspecSource);

        return null;
    }

    private static boolean hasGtsResources(RequestRspecSource requestRspecSource) {
        FXModelRspec modelRspec = requestRspecSource.getModelRspec(ModelRspecType.FX);

        return modelRspec != null && !modelRspec.getGeantTestbedTypes().isEmpty();

    }

    private static GeantTestbedType findInvalidGtsResource(RequestRspecSource requestRspecSource) {
        FXModelRspec modelRspec = requestRspecSource.getModelRspec(ModelRspecType.FX);
        if(modelRspec == null)
            return null;

        return modelRspec.getGeantTestbedTypes().stream()
                .filter(gtt -> gtt.getDsl() == null || gtt.getDsl().isEmpty())
                .findFirst().orElse(null);
    }
}
