/*******************************************************************************
 * Copyright (c) 2000, 2015 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
 *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
 *       activated and used by other components.
 *     Markus Schorn <markus.schorn@windriver.com> - Fix for bug 136591 -
 *       [Dialogs] TypeFilteringDialog appends unnecessary comma
 *******************************************************************************/
package org.eclipse.ui.dialogs;

import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IFileEditorMapping;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.registry.EditorRegistry;

/**
 * The TypeFilteringDialog is a SelectionDialog that allows the user to select a
 * file editor.
 */
public class TypeFilteringDialog extends SelectionDialog {
    Button addTypesButton;

    Collection initialSelections;

    // the visual selection widget group
    CheckboxTableViewer listViewer;

    // sizing constants
    private static final int SIZING_SELECTION_WIDGET_HEIGHT = 250;

    private static final int SIZING_SELECTION_WIDGET_WIDTH = 300;

    private static final String TYPE_DELIMITER = WorkbenchMessages.TypesFiltering_typeDelimiter;

    //Define a title for the filter entry field.
    private String filterTitle = WorkbenchMessages.TypesFiltering_otherExtensions;

    Text userDefinedText;

    IFileEditorMapping[] currentInput;

    /**
     *  Creates a type filtering dialog using the supplied entries. Set the
     * initial selections to those whose extensions match the preselections.
     * @param parentShell The shell to parent the dialog from.
     * @param preselections
     *            of String - a Collection of String to define the preselected
     *            types
     */
    public TypeFilteringDialog(Shell parentShell, Collection preselections) {
        super(parentShell);
        setTitle(WorkbenchMessages.TypesFiltering_title);
        this.initialSelections = preselections;
        setMessage(WorkbenchMessages.TypesFiltering_message);
		setShellStyle(getShellStyle() | SWT.SHEET);
    }

    /**
     * Creates a type filtering dialog using the supplied entries. Set the
     * initial selections to those whose extensions match the preselections.
     *
     * @param parentShell The shell to parent the dialog from.
     * @param preselections
     *            of String - a Collection of String to define the preselected
     *            types
     * @param filterText -
     *            the title of the text entry field for other extensions.
     */
    public TypeFilteringDialog(Shell parentShell, Collection preselections,
            String filterText) {
        this(parentShell, preselections);
        this.filterTitle = filterText;
    }

    /**
     * Add the selection and deselection buttons to the dialog.
     *
     * @param composite
     *            org.eclipse.swt.widgets.Composite
     */
    private void addSelectionButtons(Composite composite) {
        Composite buttonComposite = new Composite(composite, SWT.RIGHT);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        buttonComposite.setLayout(layout);
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
                | GridData.GRAB_HORIZONTAL);
        data.grabExcessHorizontalSpace = true;
        composite.setData(data);
        Button selectButton = createButton(buttonComposite,
                IDialogConstants.SELECT_ALL_ID, WorkbenchMessages.WizardTransferPage_selectAll, false);
        SelectionListener listener = widgetSelectedAdapter(e -> listViewer.setAllChecked(true));
        selectButton.addSelectionListener(listener);
        Button deselectButton = createButton(buttonComposite,
                IDialogConstants.DESELECT_ALL_ID, WorkbenchMessages.WizardTransferPage_deselectAll, false);
        listener = widgetSelectedAdapter(e -> listViewer.setAllChecked(false));
        deselectButton.addSelectionListener(listener);
    }

    /**
     * Add the currently-specified extensions to result.
     * @param result
     */
    private void addUserDefinedEntries(List result) {
        StringTokenizer tokenizer = new StringTokenizer(userDefinedText
                .getText(), TYPE_DELIMITER);
        //Allow the *. and . prefix and strip out the extension
        while (tokenizer.hasMoreTokens()) {
            String currentExtension = tokenizer.nextToken().trim();
            if (!currentExtension.equals("")) { //$NON-NLS-1$
                if (currentExtension.startsWith("*.")) { //$NON-NLS-1$
					result.add(currentExtension.substring(2));
				} else {
                    if (currentExtension.startsWith(".")) { //$NON-NLS-1$
						result.add(currentExtension.substring(1));
					} else {
						result.add(currentExtension);
					}
                }
            }
        }
    }

    /**
     * Visually checks the previously-specified elements in this dialog's list
     * viewer.
     */
    private void checkInitialSelections() {
        IFileEditorMapping editorMappings[] = ((EditorRegistry) PlatformUI
				.getWorkbench().getEditorRegistry()).getUnifiedMappings();
        ArrayList selectedMappings = new ArrayList();
        for (IFileEditorMapping mapping : editorMappings) {
            //Check for both extension and label matches
            if (this.initialSelections.contains(mapping.getExtension())) {
                listViewer.setChecked(mapping, true);
                selectedMappings.add(mapping.getExtension());
            } else {
                if (this.initialSelections.contains(mapping.getLabel())) {
                    listViewer.setChecked(mapping, true);
                    selectedMappings.add(mapping.getLabel());
                }
            }
        }
        //Now add in the ones not selected to the user defined list
        Iterator initialIterator = this.initialSelections.iterator();
        StringBuilder entries = new StringBuilder();
        while (initialIterator.hasNext()) {
            String nextExtension = (String) initialIterator.next();
            if (!selectedMappings.contains(nextExtension)) {
            	if (entries.length() != 0) {
					entries.append(',');
            	}
                entries.append(nextExtension);
            }
        }
        this.userDefinedText.setText(entries.toString());
    }

    @Override
	protected void configureShell(Shell shell) {
        super.configureShell(shell);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
				IWorkbenchHelpContextIds.TYPE_FILTERING_DIALOG);
    }

    @Override
	protected Control createDialogArea(Composite parent) {
        // page group
        Composite composite = (Composite) super.createDialogArea(parent);
        createMessageArea(composite);
        listViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
        data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
        listViewer.getTable().setLayoutData(data);
        listViewer.getTable().setFont(parent.getFont());
        listViewer.setLabelProvider(FileEditorMappingLabelProvider.INSTANCE);
		listViewer.setContentProvider(ArrayContentProvider.getInstance());
        listViewer.setComparator(new ViewerComparator());
        addSelectionButtons(composite);
        createUserEntryGroup(composite);
        initializeViewer();
        // initialize page
        if (this.initialSelections != null && !this.initialSelections.isEmpty()) {
			checkInitialSelections();
		}
        return composite;
    }

    /**
     * Create the group that shows the user defined entries for the dialog.
     *
     * @param parent
     *            the parent this is being created in.
     */
    private void createUserEntryGroup(Composite parent) {
        Font font = parent.getFont();
        // destination specification group
        Composite userDefinedGroup = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        userDefinedGroup.setLayout(layout);
        userDefinedGroup.setLayoutData(new GridData(
                GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL));
        Label fTitle = new Label(userDefinedGroup, SWT.NONE);
        fTitle.setFont(font);
        fTitle.setText(filterTitle);
        // user defined entry field
        userDefinedText = new Text(userDefinedGroup, SWT.SINGLE | SWT.BORDER);
        userDefinedText.setFont(font);
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
                | GridData.GRAB_HORIZONTAL);
        userDefinedText.setLayoutData(data);
    }

    /**
     * Return the input to the dialog.
     * @return IFileEditorMapping[]
     */
    private IFileEditorMapping[] getInput() {
        //Filter the mappings to be just those with a wildcard extension
        if (currentInput == null) {
            List wildcardEditors = new ArrayList();
            IFileEditorMapping[] allMappings = ((EditorRegistry)PlatformUI.getWorkbench()
                    .getEditorRegistry()).getUnifiedMappings();
            for (IFileEditorMapping allMapping : allMappings) {
                if (allMapping.getName().equals("*")) { //$NON-NLS-1$
					wildcardEditors.add(allMapping);
				}
            }
            currentInput = new IFileEditorMapping[wildcardEditors.size()];
            wildcardEditors.toArray(currentInput);
        }
        return currentInput;
    }

    /**
     * Initializes this dialog's viewer after it has been laid out.
     */
    private void initializeViewer() {
        listViewer.setInput(getInput());
    }

    /**
     * The <code>TypeFilteringDialog</code> implementation of this
     * <code>Dialog</code> method builds a list of the selected elements for
     * later retrieval by the client and closes this dialog.
     */
    @Override
	protected void okPressed() {
        // Get the input children.
        IFileEditorMapping[] children = getInput();
        List list = new ArrayList();
        // Build a list of selected children.
        for (IFileEditorMapping element : children) {
            if (listViewer.getChecked(element)) {
				list.add(element.getExtension());
			}
        }
        addUserDefinedEntries(list);
        setResult(list);
        super.okPressed();
    }
}
