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

import be.iminds.ilabt.jfed.experimenter_gui.config.JFedGuiConfig;
import be.iminds.ilabt.jfed.experimenter_gui.util.ui.FXUtils;
import be.iminds.ilabt.jfed.ui.javafx.util.StageUtils;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Resource;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.ResourceClass;
import be.iminds.ilabt.jfed.util.GeniUrn;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.Window;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.io.IOException;
import java.util.Collection;
import java.util.List;

/**
 * User: twalcari
 * Date: 1/8/2015
 * Time: 14:40
 */
@Singleton
public class MapDialogFactory {
    private static final Logger LOG = LoggerFactory.getLogger(MapDialogFactory.class);
    private static final String TESTBEDS_MAP_DIALOG_FXML = "TestbedsMapDialog.fxml";
    private static final String NODES_MAP_DIALOG_FXML = "NodesMapDialog.fxml";
    private static final String IMAGE_MAP_DIALOG_FXML = "ImageMapDialog.fxml";

    private final Provider<FXMLLoader> fxmlLoaderProvider;

    @Inject
    public MapDialogFactory(Provider<FXMLLoader> fxmlLoaderProvider) {
        this.fxmlLoaderProvider = fxmlLoaderProvider;
    }

    public Resource showTestbedMapDialog(Window parent, ResourceClass resourceClass) {
        try {
            FXMLLoader loader = fxmlLoaderProvider.get();
            loader.setLocation(getClass().getResource(TESTBEDS_MAP_DIALOG_FXML));

            Scene scene = new Scene(loader.load());

            TestbedsMapDialog controller = loader.getController();
            controller.setCmiManager(resourceClass);

            Stage dialogStage = new Stage();
            StageUtils.setJFedStageIcons(dialogStage);
            dialogStage.setScene(scene);

            dialogStage.setTitle("Map of available testbeds");
            dialogStage.setResizable(true);
            FXUtils.centerToOwner(parent, dialogStage);

            dialogStage.showAndWait();

            return controller.getResult();
        } catch (IOException e) {
            LOG.error("Error while creating testbeds map view", e);
            throw new RuntimeException(e);
        }
    }

    public JFedGuiConfig.ComponentInfo showNodeMapDialog(Window parent, List<JFedGuiConfig.ComponentInfo> nodes) {
        try {
            FXMLLoader loader = fxmlLoaderProvider.get();
            loader.setLocation(getClass().getResource(NODES_MAP_DIALOG_FXML));

            Scene scene = new Scene(loader.load());

            NodesMapDialog controller = loader.getController();
            controller.setNodes(nodes);

            Stage dialogStage = new Stage();
            StageUtils.setJFedStageIcons(dialogStage);
            dialogStage.setScene(scene);

            dialogStage.setTitle("Map of available nodes");
            dialogStage.setResizable(true);
            FXUtils.centerToOwner(parent, dialogStage);

            dialogStage.showAndWait();

            return controller.getResult();
        } catch (IOException e) {
            LOG.error("Error while creating testbeds map view", e);
            throw new RuntimeException(e);
        }
    }

    public JFedGuiConfig.ComponentInfo showNodeImageMapDialog(Window parent, ImageMap<GeniUrn> imageMap, Collection<JFedGuiConfig.ComponentInfo> availableNodes) {
        try {
            FXMLLoader loader = fxmlLoaderProvider.get();
            loader.setLocation(getClass().getResource(IMAGE_MAP_DIALOG_FXML));

            Scene scene = new Scene(loader.load());

            ImageMapDialog controller = loader.getController();
            controller.setNodesMap(imageMap, availableNodes);

            Stage dialogStage = new Stage();
            StageUtils.setJFedStageIcons(dialogStage);
            dialogStage.setScene(scene);
            dialogStage.setTitle("Image map of nodes");
            dialogStage.setResizable(true);

            dialogStage.sizeToScene();

            ObservableList<Screen> screens =
                    Screen.getScreensForRectangle(dialogStage.getX(), dialogStage.getY(), dialogStage.getWidth(), dialogStage.getHeight());

            double maxHeight =
                    screens.stream().mapToDouble(screen -> screen.getVisualBounds().getHeight()).min().orElse(dialogStage.getHeight());
            double maxWidth =
                    screens.stream().mapToDouble(screen -> screen.getVisualBounds().getWidth()).min().orElse(dialogStage.getWidth());

            dialogStage.setHeight(Double.min(dialogStage.getHeight(), maxHeight));
            dialogStage.setWidth(Double.min(dialogStage.getWidth(), maxWidth));

            // controller.setupStageSize(dialogStage);

            dialogStage.showAndWait();

            return controller.getResult();
        } catch (IOException e) {
            LOG.error("Error while creating testbeds map view", e);
            throw new RuntimeException(e);
        }
    }


}
