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

import be.iminds.ilabt.jfed.experiment.*;
import be.iminds.ilabt.jfed.experimenter_gui.canvas.ExperimentCanvas;
import be.iminds.ilabt.jfed.experimenter_gui.canvas.rspec.*;
import be.iminds.ilabt.jfed.experimenter_gui.config.JFedGuiConfig;
import be.iminds.ilabt.jfed.experimenter_gui.slice.actions.ExperimentActionsFactory;
import be.iminds.ilabt.jfed.experimenter_gui.util.SSHTerminalUtil;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Server;
import be.iminds.ilabt.jfed.highlevel.model.Sliver;
import be.iminds.ilabt.jfed.highlevel.tasks.HighLevelTaskFactory;
import be.iminds.ilabt.jfed.highlevel.util.AggregateManagerWrapperFactory;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.lowlevel.TestbedInfoSource;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.AggregateManagerWrapper;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.StatusDetails;
import be.iminds.ilabt.jfed.lowlevel.authority.AuthorityFinder;
import be.iminds.ilabt.jfed.preferences.GuiPreferenceKey;
import be.iminds.ilabt.jfed.preferences.JFedGuiPreferences;
import be.iminds.ilabt.jfed.rspec.model.ModelRspecType;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.*;
import be.iminds.ilabt.jfed.ui.javafx.GlyphUtils;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Alert;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputDialog;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import org.controlsfx.glyphfont.FontAwesome;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;

/**
 * User: twalcari
 * Date: 11/18/13
 * Time: 5:49 PM
 */
public class SliceExperimentCanvas extends ExperimentCanvas implements ExperimentChangeListener {
    private static final Logger LOG = LoggerFactory.getLogger(SliceExperimentCanvas.class);

    private final ModelRspecToCanvasBinding binding;

    private final ContextMenu nodeContextMenu;
    private final ContextMenu linkContextMenu;
    private final ContextMenu addressPoolContextMenu;

    private final MenuItem shareLanItem;
    private final MenuItem diskImageMenuItem;
    private final MenuItem rebootMenuItem;
    private final MenuItem reloadMenuItem;
    private final MenuItem openConsoleMenuItem;
    private final MenuItem uploadMenuItem;

    private final ExperimentController experimentController;
    private final Experiment experiment;
    private final GeniUserProvider geniUserProvider;
    private final TestbedInfoSource testbedInfoSource;
    private final AuthorityFinder authorityFinder;
    private final HighLevelTaskFactory hltf;
    private final NodePropertiesDialogFactory nodePropertiesDialogFactory;
    private final SSHTerminalUtil sshTerminalUtil;
    private final AggregateManagerWrapperFactory aggregateManagerWrapperFactory;

    private final BooleanProperty isDemo =
            new SimpleBooleanProperty(new JFedGuiPreferences().getBoolean(GuiPreferenceKey.PREF_IS_DEMO, false));


    public SliceExperimentCanvas(ExperimentController experimentController, FXModelRspec model, JFedGuiConfig config,
                                 CanvasNodeFactory canvasNodeFactory, ExperimentActionsFactory experimentActionsFactory,
                                 GeniUserProvider geniUserProvider,
                                 TestbedInfoSource testbedInfoSource, AuthorityFinder authorityFinder, HighLevelTaskFactory hltf,
                                 NodePropertiesDialogFactory nodePropertiesDialogFactory, SSHTerminalUtil sshTerminalUtil,
                                 AggregateManagerWrapperFactory aggregateManagerWrapperFactory) {
        this.binding = new ModelRspecToCanvasBinding(model, this, config, canvasNodeFactory);

        this.experimentController = experimentController;
        this.aggregateManagerWrapperFactory = aggregateManagerWrapperFactory;
        this.experiment = experimentController.getExperiment();

        this.geniUserProvider = geniUserProvider;
        this.testbedInfoSource = testbedInfoSource;
        this.authorityFinder = authorityFinder;
        this.hltf = hltf;
        this.nodePropertiesDialogFactory = nodePropertiesDialogFactory;
        this.sshTerminalUtil = sshTerminalUtil;

        //change background-color of
        setCanvasStyle(CanvasStyle.FIXED);

        //initialize GUI

        /*
        Create node context menu
         */
        nodeContextMenu = new ContextMenu();
        {
            MenuItem sshMenuItem =
                    new MenuItem("Open SSH terminal", GlyphUtils.createGlyph(FontAwesome.Glyph.TERMINAL));
            sshMenuItem.setOnAction(actionEvent -> {
                assert (getSelectionProvider().getSelectedCanvasNode() instanceof RspecCanvasNode);
                RspecCanvasNode rspecCanvasNode = (RspecCanvasNode) getSelectionProvider().getSelectedCanvasNode();

                sshTerminalUtil.launchSSHTerminal(rspecCanvasNode.getRspecNode(), experimentController.getExperiment().getSlice());
            });
            nodeContextMenu.getItems().add(sshMenuItem);
        }

        String username = null;
        if (this.geniUserProvider != null &&
                this.geniUserProvider.getLoggedInGeniUser() != null &&
                this.geniUserProvider.getLoggedInGeniUser().getUserUrn() != null)
            username =
                    this.geniUserProvider.getLoggedInGeniUser().getUserUrn().getEncodedResourceName();
        if (username != null) {
            MenuItem sshMenuItemForced =
                    new MenuItem("Open SSH terminal with user \"" + username + "\"", GlyphUtils.createGlyph(FontAwesome.Glyph.TERMINAL));
            sshMenuItemForced.setOnAction(actionEvent -> {
                assert (getSelectionProvider().getSelectedCanvasNode() instanceof RspecCanvasNode);
                RspecCanvasNode rspecCanvasNode = (RspecCanvasNode) getSelectionProvider().getSelectedCanvasNode();

                sshTerminalUtil.launchSSHTerminalForcedLocalUser(rspecCanvasNode.getRspecNode(), experimentController.getExperiment().getSlice());
            });
            nodeContextMenu.getItems().add(sshMenuItemForced);
        }

        {
            MenuItem sshCustomUserMenuItem =
                    new MenuItem("Open SSH terminal with custom user", GlyphUtils.createGlyph(FontAwesome.Glyph.TERMINAL));
            sshCustomUserMenuItem.setOnAction(event -> {

                assert (getSelectionProvider().getSelectedCanvasNode() instanceof RspecCanvasNode);
                RspecCanvasNode rspecCanvasNode = (RspecCanvasNode) getSelectionProvider().getSelectedCanvasNode();

                String username1 =
                        geniUserProvider.getLoggedInGeniUser().getUserUrn().getEncodedResourceName();

                TextInputDialog dialog = new TextInputDialog(username1);
                dialog.setTitle("Open SSH terminal with custom user");
                dialog.setHeaderText("Open SSH terminal with custom user");
                dialog.setContentText("Please enter the custom username:");


                dialog.showAndWait()
                        .ifPresent(customUsername ->
                                sshTerminalUtil.launchSSHTerminal(rspecCanvasNode.getRspecNode(),
                                        experimentController.getExperiment().getSlice(),
                                        customUsername));


            });
            nodeContextMenu.getItems().add(sshCustomUserMenuItem);
        }

        {
            MenuItem infoMenuItem = new MenuItem("Show Node Info", GlyphUtils.createGlyph(FontAwesome.Glyph.INFO));
            infoMenuItem.setOnAction(actionEvent -> {
                assert (getSelectionProvider().getSelectedCanvasNode() instanceof RspecCanvasNode);
                RspecCanvasNode rspecCanvasNode = (RspecCanvasNode) getSelectionProvider().getSelectedCanvasNode();

                FXRspecNode rspecNode = tryGetManifestRspecNode(rspecCanvasNode);

                this.nodePropertiesDialogFactory.showSimplePropertiesDialog(experimentController.getExperiment().getSlice(),
                        rspecNode);
            });
            nodeContextMenu.getItems().add(infoMenuItem);
        }

        {
            diskImageMenuItem = new MenuItem("Create Image", GlyphUtils.createGlyph(FontAwesome.Glyph.UPLOAD));
            diskImageMenuItem.setOnAction(actionEvent -> {
                FXRspecNode selectedManifestNode = getSelectedManifestNode();

                if (selectedManifestNode != null) {
                    experimentActionsFactory.createCreateDiskImageAction(getScene().getWindow(), experimentController, selectedManifestNode).run();
                } else {
                    LOG.warn("Could not retrieve selected manifest node to create image");
                }
            });
            diskImageMenuItem.disableProperty().bind(isDemo);

            nodeContextMenu.getItems().add(diskImageMenuItem);
        }

        {
            rebootMenuItem = new MenuItem("Reboot", GlyphUtils.createGlyph(FontAwesome.Glyph.POWER_OFF));
            rebootMenuItem.setOnAction(actionEvent -> {
                Sliver selectedSliver = getSelectedSliver();
                if (selectedSliver != null) {
                    experimentActionsFactory.createRebootAction(getScene().getWindow(), experimentController, selectedSliver).run();
                } else {
                    LOG.error("Could not retrieve selected sliver sliver to reboot");
                }
            });
            rebootMenuItem.disableProperty().bind(isDemo);
            nodeContextMenu.getItems().add(rebootMenuItem);
        }

        {
            reloadMenuItem = new MenuItem("Reload OS", GlyphUtils.createGlyph(FontAwesome.Glyph.POWER_OFF));
            reloadMenuItem.setOnAction(actionEvent -> {
                Sliver selectedSliver = getSelectedSliver();
                if (selectedSliver != null) {
                    experimentActionsFactory.createReloadOSAction(getScene().getWindow(), experimentController, selectedSliver).run();
                } else {
                    LOG.error("Could not retrieve selected sliver sliver to reload os");
                }

            });
            reloadMenuItem.disableProperty().bind(isDemo);
            nodeContextMenu.getItems().add(reloadMenuItem);
        }

        {
            openConsoleMenuItem = new MenuItem("Open Boot Console", GlyphUtils.createGlyph(FontAwesome.Glyph.TERMINAL));
            openConsoleMenuItem.setOnAction(actionEvent -> {
                Sliver selectedSliver = getSelectedSliver();
                if (selectedSliver != null) {
                    experimentActionsFactory.createOpenConsoleAction(getScene().getWindow(), experimentController, selectedSliver).run();
                } else {
                    LOG.error("Could not retrieve selected sliver sliver to open boot console");
                }
            });
            nodeContextMenu.getItems().add(openConsoleMenuItem);
        }

        {
            uploadMenuItem = new MenuItem("Transfer files", GlyphUtils.createGlyph(FontAwesome.Glyph.UPLOAD));
            uploadMenuItem.setOnAction(actionEvent -> {
                final FXRspecNode selectedManifestNode = getSelectedManifestNode();
                if (selectedManifestNode != null) {
                    experimentActionsFactory.createSCPUploadAction(getScene().getWindow(), experimentController, selectedManifestNode).run();
                } else {
                    LOG.error("Could not retrieve selected node to transfer files to/from");
                }

            });
            nodeContextMenu.getItems().add(uploadMenuItem);
        }


        //contextMenu for links
        this.linkContextMenu = new ContextMenu();

        shareLanItem = new MenuItem("Share/Unshare Lan", GlyphUtils.createGlyph(FontAwesome.Glyph.SHARE_ALT));
        shareLanItem.setOnAction(actionEvent -> {
            RspecCanvasLink rspecCanvasLink = getSelectionProvider().getSelectedCanvasLink();

            experimentActionsFactory.createShareLanAction(this.getScene().getWindow(), experimentController,
                    rspecCanvasLink.getRspecLink()).run();
        });
        linkContextMenu.getItems().add(shareLanItem);


        MenuItem linkInfoMenuItem = new MenuItem("Show Link Info", GlyphUtils.createGlyph(FontAwesome.Glyph.INFO));
        linkInfoMenuItem.setOnAction(actionEvent -> new LinkPropertiesDialog(tryGetManifestRspecLink(getSelectionProvider().getSelectedCanvasLink())).showDialog());
        linkContextMenu.getItems().add(linkInfoMenuItem);


        experimentController.getExperiment().addExperimentChangeListener(this);
        updateCanvasStyle(experimentController.getExperiment().getExperimentState());

        //contextMenu for address pools
        this.addressPoolContextMenu = new ContextMenu();
        {
            MenuItem addressPoolInfoMenuItem =
                    new MenuItem("Show Address Pool Info", GlyphUtils.createGlyph(FontAwesome.Glyph.INFO));
            addressPoolInfoMenuItem.setOnAction(actionEvent -> {
                assert (getSelectionProvider().getSelectedAddressPool() != null);
                AddressPoolCanvasNode addressPoolCanvasNode = getSelectionProvider().getSelectedAddressPool();

                FXAddressPool manifestAddressPool = tryGetManifestAddressPool(addressPoolCanvasNode);
                if (manifestAddressPool != null)
                    new AddressPoolPropertiesDialog(manifestAddressPool).show();
                else
                    new Alert(Alert.AlertType.INFORMATION, "No information available").show();
            });
            addressPoolContextMenu.getItems().add(addressPoolInfoMenuItem);
        }
    }

    /**
     * Tries to get the corresponding RspecNode from the manifest. Otherwise returns the one from the request
     *
     * @param rspecCanvasNode -
     * @return -
     */
    @Nullable
    private FXRspecNode tryGetManifestRspecNode(RspecCanvasNode rspecCanvasNode) {
        FXRspecNode rspecNode = rspecCanvasNode.getRspecNode();

        //try to fetch node from manifest rspec
        if (experiment.getSlice().getManifestRspec() != null) {
            FXModelRspec manifestRspec =
                    experiment.getSlice().getManifestRspec().getModelRspec(ModelRspecType.FX);
            assert manifestRspec != null;
            FXRspecNode manifestRspecNode = manifestRspec.getNodeByUniqueId(rspecNode.getUniqueId());
            if (manifestRspecNode == null) {
                //fallback to client-id

                manifestRspecNode = manifestRspec.getNodeByClientId(rspecNode.getClientId());
            }

            if (manifestRspecNode != null) {
                rspecNode = manifestRspecNode;
            }
        }
        return rspecNode;
    }

    /**
     * Tries to get the corresponding RspecNode from the manifest. Otherwise returns the one from the request
     *
     * @param rspecCanvasLink -
     * @return -
     */
    @Nullable
    private FXRspecLink tryGetManifestRspecLink(RspecCanvasLink rspecCanvasLink) {
        FXRspecLink rspecLink = rspecCanvasLink.getRspecLink();

        //try to fetch node from manifest rspec
        if (experiment.getSlice().getManifestRspec() != null) {
            FXModelRspec manifestRspec =
                    experiment.getSlice().getManifestRspec().getModelRspec(ModelRspecType.FX);

            FXRspecLink manifestRspecLink = manifestRspec.getLinkByUniqueId(rspecLink.getUniqueId());
            if (manifestRspecLink == null) {
                //fallback to client-id
                manifestRspecLink = manifestRspec.getLinkByClientId(rspecLink.getClientId());
            }

            if (manifestRspecLink != null) {
                rspecLink = manifestRspecLink;
            }
        }
        return rspecLink;
    }

    @Nullable
    private FXAddressPool tryGetManifestAddressPool(AddressPoolCanvasNode addressPoolCanvasNode) {
        FXAddressPool canvasAddressPool = addressPoolCanvasNode.getAddressPool();

        if (experiment.getSlice().getManifestRspec() != null) {
            FXModelRspec manifestRspec =
                    experiment.getSlice().getManifestRspec().getModelRspec(ModelRspecType.FX);

            return manifestRspec.getAddressPoolByClientId(canvasAddressPool.getClientId());
        } else
            return null;
    }

    public static String statusToNodeStyleClass(NodeStatus status) {
        switch (status) {
            case READY_WITH_LOGINSERVICES:
                return "canvas-node-ready";
            case READY_WITHOUT_LOGINSERVICES:
                return "canvas-node-ready-nologin";
            case CHANGING:
                return "canvas-node-changing";
            case FAIL:
            case RESERVATION_FAIL:
                return "canvas-node-fail";
            case UNALLOCATED:
                return "canvas-node-unallocated";
            case UNINITIALISED:
                return "canvas-node-uninitialised";
            case UNKNOWN:
                return "canvas-node-unknown";
            default:
                throw new IllegalArgumentException();
        }
    }

    public static String statusToAddressPoolStyleClass(StatusDetails.SliverStatus status) {
        switch (status) {
            case READY:
                return "canvas-node-ready";
            case CHANGING:
                return "canvas-node-changing";
            case FAIL:
                return "canvas-node-fail";
            case UNALLOCATED:
                return "canvas-node-unallocated";
            case UNINITIALISED:
                return "canvas-node-uninitialised";
            case UNKNOWN:
                return "canvas-node-unknown";
            default:
                throw new IllegalArgumentException();
        }
    }


    public static String statusToInterfaceStyleClass(StatusDetails.SliverStatus status) {
        switch (status) {
            case READY:
                return "canvas-link-ready";
            case CHANGING:
                return "canvas-link-changing";
            case FAIL:
                return "canvas-link-fail";
            case UNALLOCATED:
                return "canvas-link-unallocated";
            case UNINITIALISED:
                return "canvas-link-uninitialised";
            case UNKNOWN:
                return "canvas-link-unknown";
            default:
                throw new IllegalArgumentException();
        }
    }

    public static String statusToLinkCenterStyleClass(StatusDetails.SliverStatus status) {
        if (status == null) {
            return "link-center-editable";
        }
        switch (status) {
            case READY:
                return "link-center-ready";
            case CHANGING:
                return "link-center-changing";
            case FAIL:
                return "link-center-fail";
            case UNALLOCATED:
                return "link-center-unallocated";
            case UNINITIALISED:
                return "link-center-uninitialised";
            case UNKNOWN:
                return "link-center-unknown";
            default:
                throw new IllegalArgumentException();
        }
    }


    @Override
    public void canvasItemOnMouseClicked(MouseEvent mouseEvent) {
        super.canvasItemOnMouseClicked(mouseEvent);

        if (mouseEvent.getSource() instanceof RspecCanvasNode) {
            RspecCanvasNode node = (RspecCanvasNode) mouseEvent.getSource();

            getSelectionProvider().setSelectedCanvasNode(node);
            if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 2) {
                sshTerminalUtil.launchSSHTerminal(node.getRspecNode(), experiment.getSlice());
            } else if (mouseEvent.getButton() != MouseButton.PRIMARY || mouseEvent.isControlDown()) {

                //show context menu
                nodeContextMenu.show(node, mouseEvent.getScreenX(), mouseEvent.getScreenY());

                boolean showCreateImage = false;
                boolean showReboot = false;
                boolean showReloadOs = false;
                boolean showOpenConsole = false;
                if (experiment.getSlice() != null && experiment.getSlice().getManifestRspec() != null) {

                    FXRspecNode selectedManifestNode = getSelectedManifestNode();
                    if (selectedManifestNode != null) {
                        //actually needed for GetVersion, but that is same case as CreateSliver
                        Server selectedAuthority =
                                authorityFinder.findByUrn(selectedManifestNode.getComponentManagerId(), AuthorityFinder.Purpose.CREATE_SLIVER);

                        if (selectedAuthority != null) {
                            AggregateManagerWrapper amWrapper =
                                    aggregateManagerWrapperFactory.getAggregateManagerWrapper(selectedAuthority);
                            showCreateImage =
                                    amWrapper.areUserDiskImageFunctionsSupported() && selectedManifestNode.getSliverId() != null;
                            showReboot = amWrapper.isRestartSupported() && selectedManifestNode.getSliverId() != null;
                            showReloadOs =
                                    amWrapper.isReloadOSSupported() && selectedManifestNode.getSliverId() != null;
                            showOpenConsole =
                                    amWrapper.isOpenConsoleSupported() && selectedManifestNode.getSliverId() != null;
                        }
                    }

                }
                diskImageMenuItem.setVisible(showCreateImage);
                rebootMenuItem.setVisible(showReboot);
                reloadMenuItem.setVisible(showReloadOs);
                openConsoleMenuItem.setVisible(showOpenConsole);
            }
        }

        if (mouseEvent.getSource() instanceof RspecCanvasLink.LinkCenter) {
            RspecCanvasLink link =
                    ((RspecCanvasLink.LinkCenter) mouseEvent.getSource()).getRspecCanvasLink();


            getSelectionProvider().setSelectedCanvasLink(link);
            assert (getSelectionProvider().getSelectedCanvasLink() != null);

            if (mouseEvent.getButton() != MouseButton.PRIMARY || mouseEvent.isControlDown()) {
                //check if shareLanItem should be available
                RspecCanvasLink rspecCanvasLink = getSelectionProvider().getSelectedCanvasLink();

                boolean isStiching = rspecCanvasLink.getRspecLink().isStitched(testbedInfoSource);
                boolean isEmulab = false;
                boolean supportsSharedLan = false;

                if (link.getRspecLink().getComponentManagerUrns().size() == 1) {
                    //actually needed for GetVersion, but that is same case as CreateSliver
                    Server nodeAuth =
                            authorityFinder.findByUrn(link.getRspecLink().getComponentManagerUrns().get(0), AuthorityFinder.Purpose.CREATE_SLIVER);
                    if (nodeAuth != null) {
                        AggregateManagerWrapper amWrapper =
                                aggregateManagerWrapperFactory.getAggregateManagerWrapper(nodeAuth);
                        supportsSharedLan = amWrapper.isShareLanSupported();
                        if (nodeAuth.getServerType() != null)
                            isEmulab =
                                    nodeAuth.getServerType().equalsIgnoreCase("emulab") || nodeAuth.getServerType().equalsIgnoreCase("protogeni") || nodeAuth.getServerType().equalsIgnoreCase("instageni");
                    }
                }

                if (isEmulab && supportsSharedLan && !isStiching && !isDemo.get())
                    shareLanItem.setDisable(false);
                else
                    shareLanItem.setDisable(true);

                //show context menu
                linkContextMenu.show(getSelectionProvider().getSelectedCanvasLink().getLinkCenter(),
                        mouseEvent.getScreenX(), mouseEvent.getScreenY());
            }
        }

        if (mouseEvent.getSource() instanceof AddressPoolCanvasNode) {
            getSelectionProvider().setSelectedAddressPool((AddressPoolCanvasNode) mouseEvent.getSource());

            if (mouseEvent.getButton() != MouseButton.PRIMARY || mouseEvent.isControlDown()) {
                addressPoolContextMenu.show(getSelectionProvider().getSelectedAddressPool(),
                        mouseEvent.getScreenX(), mouseEvent.getScreenY());
            } else if (mouseEvent.getClickCount() == 2) {
                AddressPoolCanvasNode addressPoolCanvasNode = (AddressPoolCanvasNode) mouseEvent.getSource();

                FXAddressPool manifestAddressPool = tryGetManifestAddressPool(addressPoolCanvasNode);
                if (manifestAddressPool != null)
                    new AddressPoolPropertiesDialog(manifestAddressPool).show();
                else
                    new Alert(Alert.AlertType.INFORMATION, "No information available").show();

            }

        }
    }


    @Override
    public void onExperimentStateChange(ExperimentState newExperimentState) {
        updateCanvasStyle(experiment.getExperimentState());

    }

    @Override
    public void onExperimentPartAdded(ExperimentPart experimentPart) {
       /* nothing to do */
    }

    private void updateCanvasStyle(ExperimentState newExperimentState) {
        CanvasStyle newStyle;

        switch (newExperimentState) {
            case EXPIRED:
            case EMPTY:
                newStyle = CanvasStyle.EXPIRED;
                break;
            case FUTURE_RESERVATION:
                newStyle = CanvasStyle.FUTURE_RESERVATION;
                break;
            case FAILING:
            case FAILED:
                newStyle = CanvasStyle.FAILED;
                break;
            default:
                newStyle = CanvasStyle.FIXED;
        }

        Platform.runLater(() -> setCanvasStyle(newStyle));


    }

    public RspecGTSNode getRspecGTSNode(FXGeantTestbedType gtt) {
        return binding.getRspecGTSNode(gtt);
    }

    public AddressPoolCanvasNode getAddressPoolCanvasNode(FXAddressPool addressPool) {
        return binding.getAddressPoolCanvasNode(addressPool);
    }

    public RspecCanvasNode getRspecCanvasNode(FXRspecNode node) {
        return binding.getRspecCanvasNode(node);
    }

    public RspecCanvasLink getRspecCanvasLink(FXRspecLink link) {
        return binding.getRspecCanvasLink(link);
    }


    public enum NodeStatus {
        UNINITIALISED, /* nothing known about status*/
        READY_WITH_LOGINSERVICES,
        READY_WITHOUT_LOGINSERVICES,
        UNALLOCATED,   /* known not to exist */
        UNKNOWN,       /* known to exist, but no status known. probably it is changing. */
        CHANGING,
        FAIL,
        RESERVATION_FAIL;


        public static NodeStatus fromSliverStatus(StatusDetails.SliverStatus sliverStatus, boolean loginServiceAvailable, boolean reservationFailed) {
            if (reservationFailed)
                return RESERVATION_FAIL;
            if (sliverStatus == StatusDetails.SliverStatus.READY) {
                if (loginServiceAvailable)
                    return READY_WITH_LOGINSERVICES;
                else
                    return READY_WITHOUT_LOGINSERVICES;
            } else {
                return NodeStatus.valueOf(sliverStatus.name());
            }
        }
    }


    private FXRspecNode getSelectedManifestNode() {
        assert (getSelectionProvider().getSelectedCanvasNode() instanceof RspecCanvasNode);
        RspecCanvasNode rspecCanvasNode = (RspecCanvasNode) getSelectionProvider().getSelectedCanvasNode();
        return
                ((FXModelRspec) experimentController.getExperiment().getSlice().getManifestRspec().getModelRspec(ModelRspecType.FX))
                        .getNodeByUniqueId(rspecCanvasNode.getRspecNode().getUniqueId());
    }

    private Sliver getSelectedSliver() {
        FXRspecNode selectedManifestNode = getSelectedManifestNode();

        if (selectedManifestNode != null) {
            if (selectedManifestNode.getSliverId() != null) {
                return experimentController.getExperiment().getSlice().findSliver(selectedManifestNode.getSliverId());
            } else {
                LOG.error("Manifest node {} does not have a sliver-Id!", selectedManifestNode.getUniqueId());
                return null;
            }
        } else {
            LOG.error("Could not retrieve the selected manifest node!");
            return null;
        }
    }

}
