/*******************************************************************************
 * Copyright (c) 2004, 2011 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.tests.dnd;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.internal.dnd.TestDropLocation;
import org.eclipse.ui.tests.TestPlugin;
import org.eclipse.ui.tests.autotests.AutoTestSuite;

/**
 * @since 3.0
 */
public class DragTestSuite extends AutoTestSuite {

    /**
     * Returns the suite. This is required to use the JUnit Launcher.
     */
    public static Test suite() {
        return new DragTestSuite();
    }

    /**
     * Whether the platform we're running on supports the detaching of views.
     * This is initialized in the following static block.
     *
     * @since 3.2
     */
	private static final boolean isDetachingSupported;

	static {
		Shell shell = new Shell();
		Composite c = new Composite(shell, SWT.NONE);
		isDetachingSupported  = c.isReparentable();
		shell.dispose();
	}

    public DragTestSuite() {
        super(Platform.find(TestPlugin.getDefault().getBundle(), new Path("data/dragtests.xml")));

        String resNav = IPageLayout.ID_RES_NAV;
        String probView = IPageLayout.ID_PROBLEM_VIEW;

        // Drag sources for views
        TestDragSource[] viewDragSources = new TestDragSource[] {
                new ViewDragSource(resNav, false),
                new ViewDragSource(resNav, true),
                new ViewDragSource(probView, false),
                new ViewDragSource(probView, true) };

        // Drag sources for editors
        TestDragSource[] editorDragSources = new TestDragSource[] {
                new EditorDragSource(0, false), new EditorDragSource(0, true),
                new EditorDragSource(2, false), new EditorDragSource(2, true) };

        // Drop targets that will only be tested for views

        // Drag sources for maximized views
        TestDragSource[] maximizedViewDragSources = new TestDragSource[] {
                new ViewDragSource(resNav, false, true),
                new ViewDragSource(resNav, true, true),
                new ViewDragSource(probView, false, true),
                new ViewDragSource(probView, true, true) };

        // Now generate all test cases
        for (TestDragSource source : maximizedViewDragSources) {
            addAllCombinations(source, getMaximizedViewDropTargets(source));
        }

        for (TestDragSource source : viewDragSources) {
            addAllCombinations(source, getViewDropTargets(source));
            addAllCombinations(source, getCommonDropTargets(source));

            // Test dragging onto a detached window
            addAllCombinationsDetached(source, getDetachedWindowDropTargets(source));
        }

        for (TestDragSource source : editorDragSources) {
            addAllCombinations(source, getEditorDropTargets(source));
            addAllCombinations(source, getCommonDropTargets(source));

            // Test dragging onto a detached window
            addAllCombinationsDetached(source, getDetachedWindowDropTargets(source));
        }
        addTest(new TestSuite(Bug87211Test.class));
    }

    /**
     * Returns drop targets that will only be tested for maximized views. (we only need to ensure
     * that the view will become un-maximized -- the regular view test cases will excercise
     * the remainder of the view dragging code). We need to drag each kind of maximized view
     * to something that couldn't be seen while the view is maximized -- like the editor area).
     *
     * @param dragSource
     * @return
     * @since 3.1
     */
    private TestDropLocation[] getMaximizedViewDropTargets(IWorkbenchWindowProvider originatingWindow) {
        return new TestDropLocation[] {
                new EditorAreaDropTarget(originatingWindow, SWT.RIGHT) };
    }

    private TestDropLocation[] getCommonDropTargets(IWorkbenchWindowProvider dragSource) {
        TestDropLocation[] targets = {
            // Test dragging to the edges of the workbench window
            new WindowDropTarget(dragSource, SWT.TOP),
            new WindowDropTarget(dragSource, SWT.BOTTOM),
            new WindowDropTarget(dragSource, SWT.LEFT),
            new WindowDropTarget(dragSource, SWT.RIGHT) };

		return targets;
    }

    /**
     * Return all drop targets that only apply to views, given the window being dragged from.
     *
     * @param provider
     * @return
     * @since 3.1
     */
    private TestDropLocation[] getViewDropTargets(IWorkbenchWindowProvider dragSource) {

        String resNav = IPageLayout.ID_RES_NAV;
        String probView = IPageLayout.ID_PROBLEM_VIEW;

        TestDropLocation[] targets = new TestDropLocation[] {
            // Editor area
            new EditorAreaDropTarget(dragSource, SWT.LEFT),
            new EditorAreaDropTarget(dragSource, SWT.RIGHT),
            new EditorAreaDropTarget(dragSource, SWT.TOP),
            new EditorAreaDropTarget(dragSource, SWT.BOTTOM),

            // Resource navigator (a view that isn't in a stack)
            new ViewDropTarget(dragSource, resNav, SWT.LEFT),
            new ViewDropTarget(dragSource, resNav, SWT.RIGHT),
            new ViewDropTarget(dragSource, resNav, SWT.BOTTOM),
            new ViewDropTarget(dragSource, resNav, SWT.CENTER),
            new ViewDropTarget(dragSource, resNav, SWT.TOP),

            // Problems view (a view that is in a stack)
            // Omit the top from this test, since the meaning of dropping on the top border of
            // a stack may change in the near future
            new ViewDropTarget(dragSource, probView, SWT.LEFT),
            new ViewDropTarget(dragSource, probView, SWT.RIGHT),
            new ViewDropTarget(dragSource, probView, SWT.BOTTOM),
            new ViewDropTarget(dragSource, probView, SWT.CENTER),
            new ViewDropTarget(dragSource, probView, SWT.TOP),

            // Fast view bar
            null, //new FastViewBarDropTarget(dragSource),

            // View tabs
            new ViewTabDropTarget(dragSource, resNav),
            new ViewTabDropTarget(dragSource, probView),
            new ViewTitleDropTarget(dragSource, probView),
            };

		return targets;
    }

    /**
     * Return all drop targets that apply to detached windows, given the window being dragged from.
     *
     * @param provider
     * @return
     * @since 3.1
     */
    private TestDropLocation[] getDetachedWindowDropTargets(IWorkbenchWindowProvider dragSource) {
        TestDropLocation[] targets = new TestDropLocation[] {
            // Editor area
            new ViewDropTarget(dragSource, DragDropPerspectiveFactory.dropViewId1, SWT.CENTER),
            new ViewDropTarget(dragSource, DragDropPerspectiveFactory.dropViewId3, SWT.CENTER),
            new ViewTabDropTarget(dragSource, DragDropPerspectiveFactory.dropViewId1),
            new DetachedDropTarget()
        };

		return targets;
    }

    private TestDropLocation[] getEditorDropTargets(IWorkbenchWindowProvider originatingWindow) {
        String resNav = IPageLayout.ID_RES_NAV;
        // Drop targets that will only be tested for editors
        return new TestDropLocation[] {
        // A view
                new ViewDropTarget(originatingWindow, resNav, SWT.CENTER),

                // A stand-alone editor
                new EditorDropTarget(originatingWindow, 2, SWT.LEFT),
                new EditorDropTarget(originatingWindow, 2, SWT.RIGHT),
                new EditorDropTarget(originatingWindow, 2, SWT.TOP),
                new EditorDropTarget(originatingWindow, 2, SWT.BOTTOM),
                new EditorDropTarget(originatingWindow, 2, SWT.CENTER),

                // Editors (a stack of editors)
                new EditorDropTarget(originatingWindow, 0, SWT.LEFT),
                new EditorDropTarget(originatingWindow, 0, SWT.RIGHT),
                new EditorDropTarget(originatingWindow, 0, SWT.BOTTOM),
                new EditorDropTarget(originatingWindow, 0, SWT.CENTER),
                new EditorTabDropTarget(originatingWindow, 0),
                new EditorTitleDropTarget(originatingWindow, 0),
                };
    }

    private void addAllCombinations(TestDragSource dragSource,
            TestDropLocation[] dropTargets) {

        for (TestDropLocation dropTarget : dropTargets) {
        	if (dropTarget == null) {
				continue;
			}

            DragTest newTest = new DragTest(dragSource, dropTarget, getLog());
            addTest(newTest);
        }
    }

    private void addAllCombinationsDetached(TestDragSource dragSource,
            TestDropLocation[] dropTargets) {

    	if (isDetachingSupported) {
	        for (TestDropLocation dropTarget : dropTargets) {
	            DragTest newTest = new DetachedWindowDragTest(dragSource, dropTarget, getLog());
	            addTest(newTest);
	        }
    	}
    }

}
