package be.iminds.ilabt.jfed.experimenter_gui.ui.ribbon;

import be.iminds.ilabt.jfed.util.ExecuteOnNotNull;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * User: twalcari
 * Date: 11/6/13
 * Time: 9:41 AM
 */
public class RibbonBar extends TabPane {
    private static final Logger LOG = LoggerFactory.getLogger(RibbonBar.class);

    public static final String STYLESHEET_URL = "ribbon.css";
    private static final String RIBBON_STYLE = "ribbon-tabpane";

    public RibbonBar() {
        super();
        getStylesheets().add(getClass().getResource(STYLESHEET_URL).toExternalForm());
        getStyleClass().add(RIBBON_STYLE);

        //register accelerators for all visisble tabs on the scene
        new ExecuteOnNotNull<Scene>(sceneProperty()) {
            @Override
            public void run() {
                for (Tab tab : getTabs()) {
                    assert (tab instanceof RibbonTab);
                    registerAcceleratorsOfRibbonTab((RibbonTab) tab, false);
                }

                getTabs().addListener((ListChangeListener<Tab>) change -> {
                    while (change.next()) {
                        if (change.wasAdded()) {
                            for (Tab tab : change.getAddedSubList()) {
                                assert (tab instanceof RibbonTab);
                                registerAcceleratorsOfRibbonTab((RibbonTab) tab, false);
                            }
                        }
                        if (change.wasRemoved()) {
                            for (Tab tab : change.getRemoved()) {
                                assert (tab instanceof RibbonTab);
                                unregisterAcceleratorsOfRibbonTab((RibbonTab) tab, false);
                            }
                        }
                    }
                });

                assert (getSelectionModel().getSelectedItem() instanceof RibbonTab);
                registerAcceleratorsOfRibbonTab(((RibbonTab) getSelectionModel().getSelectedItem()), true);

                getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
                    if (oldValue != null) {
                        assert (oldValue instanceof RibbonTab);
                        unregisterAcceleratorsOfRibbonTab(((RibbonTab) oldValue), true);
                    }

                    if (newValue != null) {
                        assert (newValue instanceof RibbonTab);
                        registerAcceleratorsOfRibbonTab(((RibbonTab) newValue), true);
                    }
                });

            }
        };
    }

    private void registerAcceleratorsOfRibbonTab(RibbonTab ribbonTab, boolean onlyWhenVisible) {
        for (Node node : ribbonTab.getGroups()) {
            assert (node instanceof RibbonComponentGroup);
            RibbonComponentGroup ribbonComponentGroup = (RibbonComponentGroup) node;

            ribbonComponentGroup.getButtonChildren().stream()
                    .filter(buttonNode -> buttonNode instanceof RibbonButton)
                    .map(buttonNode -> (RibbonButton) buttonNode)
                    .filter(rb -> rb.getAccelerator() != null)
                    .filter(rb -> rb.getAcceleratorOnlyWhenVisible() == onlyWhenVisible)
                    .forEach(rb -> {
                        if (getScene().getAccelerators().containsKey(rb.getAccelerator()))
                            LOG.warn("Accelerator {} is already defined in scene!", rb.getAccelerator());
                        getScene().getAccelerators().put(rb.getAccelerator(), rb);

                    });
        }
    }


    private void unregisterAcceleratorsOfRibbonTab(RibbonTab ribbonTab, boolean onlyWhenVisible) {
        for (Node node : ribbonTab.getGroups()) {
            assert (node instanceof RibbonComponentGroup);
            RibbonComponentGroup ribbonComponentGroup = (RibbonComponentGroup) node;

            ribbonComponentGroup.getButtonChildren().stream()
                    .filter(buttonNode -> buttonNode instanceof RibbonButton)
                    .map(buttonNode -> (RibbonButton) buttonNode)
                    .filter(rb -> rb.getAccelerator() != null)
                    .filter(rb -> rb.getAcceleratorOnlyWhenVisible() == onlyWhenVisible)
                    .forEach(rb -> {
                        assert (getScene().getAccelerators().get(rb.getAccelerator()) == rb);
                        getScene().getAccelerators().remove(rb.getAccelerator());
                    });
        }
    }


}
