/*
 * @(#)SelectCommand.java 5.1
 *
 */

package CH.ifa.draw.figures;

import java.util.HashSet;
import java.util.Objects;
import java.util.Vector;

import CH.ifa.draw.DrawPlugin;
import CH.ifa.draw.framework.ChildFigure;
import de.renew.draw.storables.ontology.Drawing;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.storables.ontology.FigureEnumeration;
import de.renew.draw.storables.ontology.FigureFilter;
import de.renew.draw.ui.ontology.AbstractCommand;
import de.renew.draw.ui.ontology.DrawingEditor;
import de.renew.draw.ui.ontology.DrawingView;
import de.renew.draw.ui.ontology.SelectionMode;

/**
 * Command to select certain Figures of the current drawing.
 * {@link CH.ifa.draw.standard.SelectionTool}
 * @deprecated This class is only for internal usage and will later be made private.
 */
@Deprecated
public class SelectCommand extends AbstractCommand {

    /**
     * Value for the mode parameter of some constructors:
     * The select command behaves in its 'classical' way,
     * it clears any previous selection.
     * This mode is the default if constructors without
     * a mode parameter are used.
     **/
    public static final int SELECT = 0;

    /**
     * Value for the mode parameter of some constructors:
     * The select command adds the specified figures to
     * the selection.
     **/
    public static final int ADD = 1;

    /**
     * Value for the mode parameter of some constructors:
     * The select command removes the specified figures from
     * the selection.
     **/
    public static final int REMOVE = 2;

    /**
     * Value for the mode parameter of some constructors:
     * The select command restricts the selection to the specified figures.
     **/
    public static final int RESTRICT = 3;

    /**
     * Value for the mode parameter of some constructors:
     * The select command inverts the selection.
     **/
    public static final int INVERT = 4;

    /**
     * Drawing editor of the class that is not actively used
     */
    protected DrawingEditor _editor;

    /**
     * Determines which figures are used in the command executions
     */
    protected final FigureFilter _filter;

    /**
     * Sets a mode that determines the selection of figures
     */
    protected final int _selectMode;

    /**
     * Constructs a new SelectCommand that selects all figures of type {@link Figure}.
     *
     * @param name the command name
     * @deprecated This constructor is only for internal usage and will later be made private.
     */
    @Deprecated
    public SelectCommand(String name) {
        this(name, Figure.class, null, SELECT);
    }

    /**
     * Constructs a select command for certain figures.
     *
     * @param name the command name
     * @param figureClass the class of figures to be selected
     * @deprecated This constructor is only for internal usage and will later be made private.
     */
    @Deprecated
    public SelectCommand(String name, Class<?> figureClass) {
        this(name, figureClass, SELECT);
    }

    /**
     * Constructs a select/add to selection/remove from selection
     * command for certain figures.
     *
     * @param name the command name
     * @param figureClass the class of figures to be selected
     * @param selectMode one of the constants SELECT, ADD, REMOVE
     * or RESTRICT defined in this class
     * @deprecated This constructor is only for internal usage. Please use
     *             {@link de.renew.draw.ui.api.CommandApi#createSelectCommand(String, Class, SelectionMode)} instead.
     */
    @Deprecated
    public SelectCommand(String name, Class<?> figureClass, int selectMode) {
        this(name, figureClass, null, selectMode);
    }

    /**
     * Constructs a select command for certain figures.
     *
     * @param name the command name
     * @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.
     * @deprecated This constructor is only for internal usage and will later be made private.
     */
    @Deprecated
    public SelectCommand(String name, final Class<?> figureClass, final Class<?> parentClass) {
        this(name, figureClass, parentClass, SELECT);
    }

    /**
     * Constructs a select/add to selection/remove from selection
     * command for certain figures.
     *
     * @param name the command name
     * @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 selectMode one of the constants SELECT, ADD, REMOVE
     * or RESTRICT defined in this class
     * @deprecated This constructor is only for internal usage. Please use
     *             {@link de.renew.draw.ui.api.CommandApi#createSelectCommand(String, Class, Class, SelectionMode)} instead.
     */
    @Deprecated
    public SelectCommand(
        String name, final Class<?> figureClass, final Class<?> parentClass, int selectMode)
    {
        this(name, figure -> isValidFigure(figure, figureClass, parentClass), selectMode);
    }

    private static boolean isValidFigure(
        Figure figure, Class<?> figureClass, Class<?> parentClass)
    {

        return figureClass.isInstance(figure)
            && (parentClass == null || parentClass.isInstance(((ChildFigure) figure).parent()));

    }

    /**
     * Constructs a new SelectCommand that selects figures matching the given filter.
     *
     * @param name the command name
     * @param filter the filter object that decides whether a figure
     * will be selected
     * @deprecated This constructor is only for internal usage and will later be made private.
     */
    @Deprecated
    public SelectCommand(String name, FigureFilter filter) {
        this(name, filter, SELECT);
    }

    /**
     * Constructs a select/add to selection/remove from selection
     * command for certain figures.
     *
     * @param name the command name
     * @param filter the filter object that decides whether a figure
     * will be selected
     * @param selectMode one of the constants SELECT, ADD, REMOVE
     * or RESTRICT defined in this class
     * @deprecated This constructor is only for internal usage. Please use
     *             {@link de.renew.draw.ui.api.CommandApi#createSelectCommand(String, FigureFilter, SelectionMode)} instead.
     */
    @Deprecated
    public SelectCommand(String name, FigureFilter filter, int selectMode) {
        super(name);
        // getEditor() = editor;
        _filter = filter;
        this._selectMode = selectMode;
    }

    @Override
    public void execute() {
        DrawingView view =
            Objects.requireNonNull(DrawPlugin.getCurrent()).getDrawingEditor().view();
        Drawing drawing = view.drawing();

        FigureEnumeration figEnumeration = drawing.figures();
        Vector<Figure> concerned = new Vector<>();

        FigureEnumeration selected = view.selectionElements();
        HashSet<Figure> selectedSet = new HashSet<>();
        while (selected.hasMoreElements()) {
            selectedSet.add(selected.nextFigure());
        }

        while (figEnumeration.hasMoreElements()) {
            Figure fig = figEnumeration.nextFigure();
            if (_selectMode != INVERT) {
                if (_filter.isAcceptedFigure(fig)) {
                    if (_selectMode != RESTRICT) {
                        concerned.addElement(fig);
                    }
                } else {
                    if (_selectMode == RESTRICT) {
                        concerned.addElement(fig);
                    }
                }
            } else {
                if (!(selectedSet.contains(fig))) {
                    concerned.addElement(fig);
                }
            }
        }

        switch (_selectMode) {
            case REMOVE:
            case RESTRICT:
                view.removeFromSelectionAll(concerned);
                break;
            case SELECT:
            case INVERT:
                view.clearSelection();
            default:
                view.addToSelectionAll(concerned);
        }

        view.checkDamage();
    }
}