/*******************************************************************************
 * Copyright (c) 2016, 2018 Red Hat Inc. and others.
 * 
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Red Hat - Initial Contribution
 *******************************************************************************/
package org.eclipse.linuxtools.internal.docker.ui;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.linuxtools.internal.docker.core.ContainerFileProxy;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.FileSystemElement;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.model.WorkbenchViewerComparator;
import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;

/**
 * A standard directory selection dialog which solicits a choice of directory
 * from the user. The <code>getResult</code> method returns the selected
 * directory in a list.
 * <p>
 * This class may be instantiated; it is not intended to be subclassed.
 * </p>
 * <p>
 * Example:
 * 
 * <pre>
 * 		ProgressMonitorDialog pd = new ProgressMonitorDialog(
 *				Activator.getActiveWorkbenchShell());
 *		ContainerFileSystemProvider provider = new ContainerFileSystemProvider(
 *				connection, container.id());
 *		PopulateContainerFilesOperation sfo = new PopulateContainerFilesOperation(
 *				new ContainerFileProxy("", "", true), //$NON-NLS-1$ //$NON-NLS-2$
 *				null, provider);
 *		try {
 *			pd.run(true, true, sfo); m
 *		} catch (InvocationTargetException | InterruptedException e) {
 *			e.printStackTrace();
 *		}
 *		ContainerDirectorySelectionDialog d = new ContainerDirectorySelectionDialog(
 *				Activator.getActiveWorkbenchShell(), sfo.getResult(), provider,
 *				null);
 *		if (d.open() == IStatus.OK) {
 *			return d.getResult();
 *		}
 * </pre>
 * </p>
 * 
 * @noextend This class is not intended to be subclassed by clients.
 */
public class ContainerDirectorySelectionDialog extends SelectionDialog {
    // the root file representative to populate the viewer with
    private FileSystemElement root;

	private IImportStructureProvider structureProvider;
	// static final String FILE_SELECTION_DIALOG =
	// "org.eclipse.ui.ide.file_selection_dialog_context"; //$NON-NLS-1$

    // the visual selection widget group
	ContainerTreeGroup selectionGroup;

    // expand all items in the tree view on dialog open
    private boolean expandAllOnOpen = false;

    // sizing constants
    private static final int SIZING_SELECTION_WIDGET_WIDTH = 500;

    private static final int SIZING_SELECTION_WIDGET_HEIGHT = 250;

	static final String SELECT_ALL_TITLE = "SelectionDialog_selectLabel"; //$NON-NLS-1$
	static final String DESELECT_ALL_TITLE = "SelectionDialog_deselectLabel"; //$NON-NLS-1$

    /**
     * Creates a file selection dialog rooted at the given file system element.
     *
     * @param parentShell the parent shell
     * @param fileSystemElement the root element to populate this dialog with
     * @param message the message to be displayed at the top of this dialog, or
     *    <code>null</code> to display a default message
     */
    public ContainerDirectorySelectionDialog(Shell parentShell,
			FileSystemElement fileSystemElement,
			IImportStructureProvider structureProvider, String message) {
        super(parentShell);
		setTitle(Messages.getString("DirectorySelectionDialog_title")); //$NON-NLS-1$
        root = fileSystemElement;
		this.structureProvider = structureProvider;
        if (message != null) {
			setMessage(message);
		} else {
			setMessage(Messages.getString("DirectorySelectionDialog_message")); //$NON-NLS-1$
		}
    }

    @Override
	protected void configureShell(Shell shell) {
        super.configureShell(shell);
		// TODO: replace with correct help context
		// PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
		// FILE_SELECTION_DIALOG);
    }

    @Override
	public void create() {
        super.create();
        initializeDialog();
    }

    @Override
	protected Control createDialogArea(Composite parent) {
        // page group
        Composite composite = (Composite) super.createDialogArea(parent);

        createMessageArea(composite);

        // Create a fake parent of the root to be the dialog input element.
        // Use an empty label so that display of the element's full name
        // doesn't include a confusing label
        FileSystemElement input = new FileSystemElement("", null, true);//$NON-NLS-1$
        input.addChild(root);
        root.setParent(input);

		selectionGroup = new ContainerTreeGroup(composite, input,
				getFolderProvider(), getDynamicFolderProvider(),
				new WorkbenchLabelProvider(),
				SWT.NONE,
                SIZING_SELECTION_WIDGET_WIDTH, // since this page has no other significantly-sized
                SIZING_SELECTION_WIDGET_HEIGHT); // widgets we need to hardcode the combined widget's
        // size, otherwise it will open too small

		ISelectionChangedListener listener = event -> getOkButton()
				.setEnabled(event.getSelection() != null
						&& !event.getSelection().isEmpty());

        WorkbenchViewerComparator comparator = new WorkbenchViewerComparator();
        selectionGroup.setTreeComparator(comparator);
		selectionGroup.addSelectionChangedListener(listener);
        return composite;
    }

    /**
     * Returns whether the tree view of the file system element
     * will be fully expanded when the dialog is opened.
     *
     * @return true to expand all on dialog open, false otherwise.
     */
    public boolean getExpandAllOnOpen() {
        return expandAllOnOpen;
    }

    /**
     * Returns a content provider for <code>FileSystemElement</code>s that returns
     * only folders as children.
     */
    private ITreeContentProvider getFolderProvider() {
        return new WorkbenchContentProvider() {
            @Override
			public Object[] getChildren(Object o) {
				if (o instanceof FileSystemElement) {
					return ((FileSystemElement) o).getFolders().getChildren(o);
                }

                return new Object[0];
			}
        };
    }

    /**
	 * Returns a content provider for <code>FileSystemElement</code>s that
	 * returns only folders as children.
	 */
	private ITreeContentProvider getDynamicFolderProvider() {
		return new WorkbenchContentProvider() {
			@Override
			public Object[] getChildren(Object o) {
				if (o instanceof MinimizedFileSystemElement) {
					return ((MinimizedFileSystemElement) o)
							.getFolders(structureProvider)
							.getChildren(o);
				} else if (o instanceof FileSystemElement) {
					return ((FileSystemElement) o).getFolders().getChildren(o);
				}

				return new Object[0];
			}
		};
	}

	/**
	 * Initializes this dialog's controls.
	 */
    private void initializeDialog() {
        // initialize page
        if (getInitialElementSelections().isEmpty()) {
			getOkButton().setEnabled(false);
		}
        selectionGroup.aboutToOpen();
    }

    /**
     * The <code>FileSelectionDialog</code> implementation of this
     * <code>Dialog</code> method builds a list of the selected files for later
     * retrieval by the client and closes this dialog.
     */
	@SuppressWarnings({})
	@Override
	protected void okPressed() {
		Object result = selectionGroup.getCurrentSelection();
		if (result != null) {
			MinimizedFileSystemElement selected = (MinimizedFileSystemElement) result;
			List<ContainerFileProxy> list = new ArrayList<>();
			list.add((ContainerFileProxy) selected.getFileSystemObject());
			setResult(list);
		}
        super.okPressed();
    }

    /**
     * Set whether the tree view of the file system element
     * will be fully expanded when the dialog is opened.
     *
     * @param expandAll true to expand all on dialog open, false otherwise.
     */
    public void setExpandAllOnOpen(boolean expandAll) {
        expandAllOnOpen = expandAll;
    }
}
