package de.renew.draw.ui.api;

import de.renew.draw.storables.ontology.FigureFilter;
import de.renew.draw.ui.impl.services.CommandServiceImpl;
import de.renew.draw.ui.ontology.AbstractCommand;
import de.renew.draw.ui.ontology.Alignment;
import de.renew.draw.ui.ontology.Anchor;
import de.renew.draw.ui.ontology.SelectionMode;
import de.renew.draw.ui.ontology.SpreadMode;
import de.renew.plugin.IPlugin;


/**
 * Service class for creating Commands.
 *
 * @author Timo Heitmann
 */
public final class CommandApi {

    private static final CommandServiceImpl COMMAND_SERVICE;

    static {

        COMMAND_SERVICE = new CommandServiceImpl();

    }

    private CommandApi() {}

    /**
     * Constructs a command with the given name and given functionality.
     * @param name the name of the command.
     * @param runnable the function to run upon command execution.
     * @return the created command
     */
    public static AbstractCommand createCommand(String name, Runnable runnable) {

        return COMMAND_SERVICE.createCommand(name, runnable);

    }

    /**
     * Creates an <code>VersionInfoCommand</code> for the given plugin.
     * @param plugin the plugin instance whose version is of interest.
     * @return the created command
     */
    public static AbstractCommand createVersionInfoCommand(IPlugin plugin) {

        return COMMAND_SERVICE.createVersionInfoCommand(plugin);

    }

    /**
     * Creates an {@code GroupCommand} to group the selection into a GroupFigure.
     *
     * @param name the name of the GroupCommand
     * @return the created GroupCommand
     */
    public static AbstractCommand createGroupCommand(String name) {
        return COMMAND_SERVICE.createGroupCommand(name);
    }

    /**
     * Creates an {@code UnGroupCommand} to ungroup the selection.
     *
     * @param name the name of the UnGroupCommand
     * @return the created UnGroupCommand
     */
    public static AbstractCommand createUnGroupCommand(String name) {
        return COMMAND_SERVICE.createUngroupCommand(name);
    }

    /**
     * Constructs a SelectCommand command for certain figures,
     * which selects, adds to selection or removes from selection.
     *
     * @param name the name of the SelectCommand
     * @param figureClass the class of figures to be selected
     * @param mode the SelectionMode, which determines behavior of the command e.g. {remove from, add to} selection
     * @return the created SelectCommand
     */
    public static AbstractCommand createSelectCommand(
        String name, Class<?> figureClass, SelectionMode mode)
    {
        return COMMAND_SERVICE.createSelectCommand(name, figureClass, mode);
    }

    /**
     * Constructs a SelectCommand command for certain figures,
     * which selects, adds to selection or removes from selection.
     *
     * @param name the name of the SelectCommand
     * @param figureClass the class of figures to be selected
     * @param parentClass also check this class for the parent of the child figures to be selected.
     *                    If parentClass != null, figureClass has to be a subclass of ChildFigure
     *                    and parentClass should be a subclass of ParentFigure.
     * @param mode the SelectionMode, which determines behavior of the command e.g. {remove from, add to} selection
     * @return the created SelectCommand
     */
    public static AbstractCommand createSelectCommand(
        String name, Class<?> figureClass, Class<?> parentClass, SelectionMode mode)
    {
        return COMMAND_SERVICE.createSelectCommand(name, figureClass, parentClass, mode);
    }

    /**
     * Constructs a new SelectCommand, which selects figures matching the given filter.
     *
     * @param name the command name
     * @param filter the FigureFilter, which decides whether a figure will be selected
     * @param mode the SelectionMode, which determines behavior of the command e.g. {remove from, add to} selection
     * @return the created SelectCommand
     */
    public static AbstractCommand createSelectCommand(
        String name, FigureFilter filter, SelectionMode mode)
    {
        return COMMAND_SERVICE.createSelectCommand(name, filter, mode);
    }

    /**
     * Constructs an AlignCommand, which aligns a selection of figures relative to each other.
     *
     * @param name the command name
     * @param alignment the alignment operation (LEFTS, CENTERS, RIGHTS, etc.)
     * @return the created AlignCommand
     */
    public static AbstractCommand createAlignCommand(String name, Alignment alignment) {
        return COMMAND_SERVICE.createAlignCommand(name, alignment);
    }

    /**
     * Constructs an alignment command, which aligns a selection of figures relative to each other.
     *
     * @param name the command name
     * @param alignment the alignment operation (LEFTS, CENTERS, RIGHTS, etc.)
     * @param anchor the reference point to align the figures to (BIGGEST, FIRST, SELECTED, etc.)
     * @return the created AlignCommand
     */
    public static AbstractCommand createAlignCommand(
        String name, Alignment alignment, Anchor anchor)
    {
        return COMMAND_SERVICE.createAlignCommand(name, alignment, anchor);
    }

    /**
     * Creates an SpreadCommand, which spreads the selection of figures by making their relative distances equal.
     *
     * @param name the name of the command
     * @param mode the operation mode to equalize distance between e.g. LEFTS, TOPS, CENTERS
     * @return the created SpreadCommand
     */
    public static AbstractCommand createSpreadCommand(String name, SpreadMode mode) {
        return COMMAND_SERVICE.createSpreadCommand(name, mode);
    }

    /**
     * Creates an ChangeAttributeCommand to change a named figure attribute.
     *
     * @param commandName the name of the command
     * @param attributeName the name of the attribute to be changed
     * @param attributeValue the new attribute value
     * @return the created ChangeAttributeCommand
     */
    public static AbstractCommand createChangeAttributeCommand(
        String commandName, String attributeName, Object attributeValue)
    {
        return COMMAND_SERVICE
            .createChangeAttributeCommand(commandName, attributeName, attributeValue);
    }
}
