package de.renew.draw.ui.api.services;

import java.awt.Dialog;
import java.awt.Frame;
import java.awt.event.KeyEvent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;

import de.renew.draw.ui.api.MenuApi;
import de.renew.draw.ui.ontology.MenuSectionPosition;
import de.renew.draw.ui.ontology.MenuSeparatorFactory;

/**
 * Service class that provides methods for the {@link MenuApi} to call.
 *
 * @author Clara von Bargen
 */
public interface MenuService {

    /**
     * Registers a menu.
     * It uses the given parent menu if it exists otherwise it will create the given parent menu.
     * IMPORTANT: The registered menu must have the client property {@link MenuApi#ID_PROPERTY} set to a sensible ID (String).
     * (This is done via the {@link JMenuItem#putClientProperty(Object, Object)}  method of the menu item).
     * The Menu entry is added at the end of the last section of the menu.
     *
     * @param parentMenu the parent menu from the menu.
     * @param menuToRegister the menu that you want to register.
     */
    void registerMenu(String parentMenu, JMenuItem menuToRegister);

    /**
     * Registers the given menu item.
     * The given id is set as the client property {@link MenuApi#ID_PROPERTY} for the menu item.
     * The Menu entry is added at the end of the last section of the menu.
     *
     * @param parentMenu Name of the parent menu
     * @param menuToRegister the menu item to add.
     * @param id Client id of the menu item to register
     */
    void registerMenu(String parentMenu, JMenuItem menuToRegister, String id);

    /**
     * Registers the given menu item and add it to the given parentMenu.
     * IMPORTANT: The registered menu must have the client property {@link MenuApi#ID_PROPERTY} set to a sensible ID (String).
     * (This is done via the {@link JMenuItem#putClientProperty(Object, Object)} method of the menu item).
     * <p>
     * This method allows to specify the position of the menu item in its parent menu:
     * The parameter <code>requestedSection</code> specifies in which section of the parent menu (split with separators) the menu item is to be added,
     * starting with 1 for the first section.
     * If <code>requestedSection</code> is larger than the number of sections in <code>parentMenu</code> the item is added as last item.
     * The parameter <code>position</code> specifies at which position the item should be added.
     *
     * @param parentMenu the top level menu to which to add the menu item.
     * @param menuToRegister the menu item to add.
     * @param requestedSection the section to which the item should be added (starting at 1)
     * @param itemPosition determines where in the section item appears
     */
    void registerMenu(
        String parentMenu, JMenuItem menuToRegister, int requestedSection,
        MenuSectionPosition itemPosition);

    /**
     * Unregisters the given menu.
     *
     * @param menuToUnregister the menu to be unregistered
     */
    void unregisterMenu(JMenuItem menuToUnregister);

    /**
     * Unregisters the given menu using its identifier.
     *
     * @param id the identifier of the menu to be unregistered
     */
    void unregisterMenu(String id);

    /**
     * Creates a new top level menu out of a parent menu if non is already existing.
     *
     * @param parentMenu the parent menu
     * @param section the index of the section in which the menu is to be added (starting at 1)
     * @return the created top level menu
     */
    JMenu createTopLevelMenu(String parentMenu, int section);

    /**
     * Creates a menu item with the given name, shortcut and action.
     *
     * @param name     the name of the menu item
     * @param shortcut the shortcut for the menu item as the keycode representing the key (e.g. {@link KeyEvent#VK_R})
     * @param action the action to be performed when the menu item is clicked
     * @return the created menu item
     */
    JMenuItem createMenuItem(String name, int shortcut, Runnable action);

    /**
     * Creates a menu item with the given name and action.
     *
     * @param name   the name of the menu item.
     * @param action the action to be performed when the menu item is clicked
     * @return the created menu item
     */
    JMenuItem createMenuItem(String name, Runnable action);

    /**
     * Creates a {@link MenuSeparatorFactory} with the given ID. The id of any menu separator
     * created from the factory will start with this id.
     *
     * @param id the id of the separator factory
     * @return the created separator factory
     */
    MenuSeparatorFactory createMenuSeparatorFactory(String id);

    /**
     * Convenience method to be able to create a separator JMenuItem on the fly.
     * This method does NOT assure that the id is unique so the client has to assure it.
     * If you want the framework to handle unique ids, use a SeparatorFactory object instead.
     *
     * @param id the id for referencing that is set as the separator's label.
     * @return a new separator menu item with the given <code>id</code>.
     */
    JMenuItem createMenuSeparator(String id);


    /**
     * Returns the name of the plugins menu.
     *
     * @return name of the plugins menu
     */
    String getMenuNamePluginsMenu();

    /**
     * Returns the name of the platforms menu.
     *
     * @return name of the platforms menu
     */
    String getMenuNamePlatformsMenu();

    /**
     * Returns the name of the file menu.
     *
     * @return name of the file menu
     */
    String getMenuNameFileMenu();

    /**
     * Returns the name of the edit menu.
     *
     * @return name of the edit menu
     */
    String getMenuNameEditMenu();

    /**
     * Returns the name of the attribute menu.
     *
     * @return name of the attribute menu
     */
    String getMenuNameAttributesMenu();

    /**
     * Returns the name of the layout menu.
     *
     * @return name of the layout menu
     */
    String getMenuNameLayoutMenu();

    /**
     * Returns the name of the tools menu.
     *
     * @return name of the tools menu
     */
    String getMenuNameToolsMenu();

    /**
     * Returns the name of the Paose menu.
     *
     * @return name of the Paose menu
     */
    String getMenuNamePaoseMenu();

    /**
     * Returns the name of the windows menu in the menu bar.
     *
     * @return name of the windows menu
     */
    String getMenuNameHelpMenu();

    /**
     * Returns the category to use in the windows menu for tools and dialogs.
     *
     * @return category to use in the windows menu
     */
    String getWindowsCategoryNameTools();


    /**
     * Adds a (hopefully non-modal) dialog to the WindowsMenu under the
     * given category.
     *
     * @param category  the windows category to add the dialog to.
     *                  Make it a plural, if possible. May be <code>null</code>.
     * @param dialog    the dialog to bring to front when the menu entry is activated.
     **/
    void registerWindowsMenuDialog(String category, Dialog dialog);

    /**
     * Removes the given dialog from the WindowsMenu.
     * @param dialog Dialog that should be removed
     */
    void unregisterWindowsMenuDialog(Dialog dialog);

    /**
     * Adds a frame to the WindowsMenu under the given category.
     *
     * @param category  the windows category to add the frame to.
     *                  Make it a plural, if possible. May be {@code null}.
     * @param frame    the frame to bring to front when the menu entry is activated.
     **/
    void registerWindowsMenuFrame(String category, Frame frame);

    /**
     * Removes the given frame.
     * @param frame frame that should be removed
     */
    void unregisterWindowsMenuFrame(Frame frame);

    /**
     * Appends a menu item to the end of this menu.
     *
     * @param menuItem the {@link javax.swing.JMenuItem} to be added
     */
    void registerWindowsMenuItem(JMenuItem menuItem);

    /**
     * Removes the specified menu item from this menu.
     * If there is no popup menu, this method will have no effect.
     *
     * @param menuItem the {@link javax.swing.JMenuItem} to be removed from the menu
     */
    void unregisterWindowsMenuItem(JMenuItem menuItem);
}
