package de.renew.windowmanagement;

import java.awt.Component;
import java.util.Collection;
import java.util.HashSet;
import javax.swing.JMenu;
import javax.swing.JMenuBar;

import bibliothek.gui.dock.support.lookandfeel.ComponentCollector;
import bibliothek.gui.dock.support.lookandfeel.LookAndFeelList;


/**
 * A helper class that manages the menu entries of the application.
 */
public class RenewMenuBar extends JMenuBar {

    /**
     * Used for any kinds of I/O operations.
     */
    public static final int FILE_MENU_SECTION = 0;

    /**
     * Operations that are used to manipulate the graphical content of the drawings in some way.
     */
    public static final int DIAGRAM_MANIPULATION_SECTION = 1;

    /**
     * Operations that are concerned specifically with Petri nets (simulation, analysis, etc).
     */
    public static final int PETRI_NET_SECTION = 2;

    /**
     * Any additional tools.
     */
    public static final int ADDITIONAL_TOOLS_SECTION = 3;

    /**
     * For everything that doesn't seem to fit anywhere else.
     */
    public static final int MISC_SECTION = 4;

    /**
     * Options concerned with system operations (i.e. layout/look-and-feel)
     */
    public static final int SYSTEMS_SECTION = 5;

    /**
     * The help menu, usually the last section.
     */
    public static final int HELP_MENU_SECTION = 6;

    private static final int NUMBER_OF_SECTIONS = 7;

    /**
     * A Array of sectionHead where the different sections are stored in.
     */
    private int[] _sectionHeads = new int[NUMBER_OF_SECTIONS];

    /**
     * The constructor for the helper class that manages the menu entries of the application.
     */
    public RenewMenuBar() {
        super();

        // We want to adapt the menu entries when the l&f changes.
        final Collection<Component> thisInACollection = new HashSet<>();
        thisInACollection.add(this);
        LookAndFeelList.getDefaultList().addComponentCollector(new ComponentCollector() {
            @Override
            public Collection<Component> listComponents() {


                return thisInACollection;
            }
        });
    }

    /**
     * Register a {@link JMenu} in the specified section of the menu bar.
     * The menu will be added at the end of the section.
     * For the last section (usually reserved for the help menu) it will be added in front of the section head instead.
     * <p>
     * All currently available section ids are held as static fields, i.e. {@link #FILE_MENU_SECTION}.
     *
     * @param menu    the menu to be added.
     * @param section the section id.
     * @return the added menu which was made visible
     * @throws UnknownMenuSectionException when the section ID is out of bounds
     */
    public JMenu addMenu(JMenu menu, int section) throws UnknownMenuSectionException {

        if (section >= NUMBER_OF_SECTIONS) {
            throw new UnknownMenuSectionException(
                "Section id was out of bounds, please refer to the menu manager for available sections.");
        }


        if (section == (NUMBER_OF_SECTIONS - 1)) {
            // Add in front of last section
            super.add(menu, _sectionHeads[section]);
        } else {
            // Add at end of specified section
            super.add(menu, _sectionHeads[section + 1]);
        }

        // Update indices of all following section heads
        for (section++; section < NUMBER_OF_SECTIONS; section++) {
            _sectionHeads[section]++;
        }

        menu.setVisible(true);
        return menu;
    }

    @Override
    public Component add(Component c, int section) {

        // Do nothing, so we don't accidentally mess up the ordering.
        return c;
    }

    @Override
    public JMenu add(JMenu menu) {

        try {
            addMenu(menu, MISC_SECTION);
        } catch (UnknownMenuSectionException e) {
            // Unless someone deletes the MISC_SECTION entry in this very class,
            // this clause should be unreachable.
        }

        return menu;
    }

    @Override
    public void remove(Component menu) {
        int index = getComponentIndex(menu);
        super.remove(menu);

        for (int i = 0; i < NUMBER_OF_SECTIONS; i++) {
            if (_sectionHeads[i] > index) {
                _sectionHeads[i]--;
            }
        }
    }


    /**
     * returns the final field of the number of sections.
     *
     * @return the final field.
     */
    public static int getNumberOfSections() {
        return NUMBER_OF_SECTIONS;
    }
}
