/*******************************************************************************
 * Copyright (c) 2009, 2018 Ericsson and others.
 *
 * All rights reserved. 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:
 *   Francois Chouinard - Initial API and implementation
 *   Francois Chouinard - Got rid of dependency on internal platform class
 *   Francois Chouinard - Complete re-design
 *   Anna Dushistova(Montavista) - [383047] NPE while importing a CFT trace
 *   Matthew Khouzam - Moved out some common functions
 *   Patrick Tasse - Add sorting of file system elements
 *   Bernd Hufmann - Re-design of trace selection and trace validation
 *   Marc-Andre Laperle - Preserve folder structure on import
 *   Marc-Andre Laperle - Extract archives during import
 *   Marc-Andre Laperle - Add support for Gzip (non-Tar)
 *******************************************************************************/

package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.tracecompass.internal.tmf.ui.Activator;
import org.eclipse.tracecompass.internal.tmf.ui.project.operations.NewExperimentOperation;
import org.eclipse.tracecompass.internal.tmf.ui.project.operations.SelectTracesOperation;
import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
import org.eclipse.tracecompass.tmf.core.TmfProjectNature;
import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat;
import org.eclipse.tracecompass.tmf.core.util.Pair;
import org.eclipse.tracecompass.tmf.ui.dialog.DirectoryDialogFactory;
import org.eclipse.tracecompass.tmf.ui.dialog.TmfFileDialogFactory;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry;
import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
import org.eclipse.ui.dialogs.FileSystemElement;
import org.eclipse.ui.dialogs.WizardResourceImportPage;
import org.eclipse.ui.ide.dialogs.IElementFilter;
import org.eclipse.ui.ide.dialogs.ResourceTreeAndListGroup;
import org.eclipse.ui.internal.ide.DialogUtil;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.model.WorkbenchViewerComparator;

/**
 * A variant of the standard resource import wizard for importing traces to
 * given tracing project. If no project or tracing project was selected the
 * wizard imports it to the default tracing project which is created if
 * necessary.
 *
 * In our case traces could be files or a directory structure. This wizard
 * supports both cases. It imports traces for a selected trace type or, if no
 * trace type is selected, it tries to detect the trace type automatically.
 * However, the automatic detection is a best-effort and cannot guarantee that
 * the detection is successful. The reason for this is that there might be
 * multiple trace types that can be assigned to a single trace.
 *
 *
 * @author Francois Chouinard
 */
@SuppressWarnings("restriction")
public class ImportTraceWizardPage extends WizardResourceImportPage {

    // ------------------------------------------------------------------------
    // Constants
    // ------------------------------------------------------------------------
    private static final String IMPORT_WIZARD_PAGE_NAME = "ImportTraceWizardPage"; //$NON-NLS-1$
    private static final String IMPORT_WIZARD_ROOT_DIRECTORY_ID = ".import_root_directory_id"; //$NON-NLS-1$ ;
    private static final String IMPORT_WIZARD_ARCHIVE_FILE_NAME_ID = ".import_archive_file_name_id"; //$NON-NLS-1$
    private static final String IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID = ".import_unrecognized_traces_id"; //$NON-NLS-1$
    private static final String IMPORT_WIZARD_PRESERVE_FOLDERS_ID = ".import_preserve_folders_id"; //$NON-NLS-1$
    private static final String IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID = ".import_from_directory"; //$NON-NLS-1$
    private static final String IMPORT_WIZARD_CREATE_EXPERIMENT_ID = ".create_experiment"; //$NON-NLS-1$

    // constant from WizardArchiveFileResourceImportPage1
    private static final String[] FILE_IMPORT_MASK = { "*.jar;*.zip;*.tar;*.tar.gz;*.tgz;*.gz", "*.*" }; //$NON-NLS-1$ //$NON-NLS-2$

    /**
     * A special trace type value to communicate that automatic trace type
     * detection will occur instead of setting a specific trace type when
     * importing the traces.
     */
    public static final String TRACE_TYPE_AUTO_DETECT = Messages.ImportTraceWizard_AutoDetection;

    /**
     * Threshold size in byte of an archive to decide if we extract the archive in a
     * folder instead of a temporary folder to avoid copying large archive.
     */
    private static final long ARCHIVE_SIZE_THRESHOLD = 400000000;

    /**
     * Preserve the folder structure of the import traces.
     */
    public static final int OPTION_PRESERVE_FOLDER_STRUCTURE = 1 << 1;
    /**
     * Create links to the trace files instead of copies.
     */
    public static final int OPTION_CREATE_LINKS_IN_WORKSPACE = 1 << 2;
    /**
     * Import files that were not recognized as the selected trace type.
     */
    public static final int OPTION_IMPORT_UNRECOGNIZED_TRACES = 1 << 3;
    /**
     * Overwrite existing resources without prompting.
     */
    public static final int OPTION_OVERWRITE_EXISTING_RESOURCES = 1 << 4;
    /**
     * Create an experiment with imported traces.
     */
    public static final int OPTION_CREATE_EXPERIMENT = 1 << 5;
    /**
     * Skip archive detection and extraction.
     */
    public static final int OPTION_SKIP_ARCHIVE_EXTRACTION = 1 << 6;
    /**
     * Filter by time range
     */
    public static final int OPTION_FILTER_TIMERANGE = 1 << 7;
    /**
     * Keep the extracted archive file to import using links.
     */
    public static final int OPTION_KEEP_EXTRACTED_ARCHIVE = 1 << 8;
    /**
     * Rename all traces with conflicting names. This flag is ignored, when
     * {@link ImportTraceWizardPage#OPTION_OVERWRITE_EXISTING_RESOURCES} is set.
     */
    public static final int OPTION_RENAME_ALL = 1 << 9;

    // ------------------------------------------------------------------------
    // Attributes
    // ------------------------------------------------------------------------

    // Target Trace folder element
    private TmfTraceFolder fTraceFolderElement;
    // The workspace experiment folder
    private TmfExperimentFolder fExperimentFolderElement;
    private  String fPreviousSource;
    // Combo box containing trace types
    private Combo fTraceTypes;
    // Button to ignore unrecognized traces or not
    private Button fImportUnrecognizedButton;
    // Button to overwrite existing resources or not
    private Button fOverwriteExistingResourcesCheckbox;
    // Button to link or copy traces to workspace
    private Button fCreateLinksInWorkspaceButton;
    // Button to preserve folder structure
    private Button fPreserveFolderStructureButton;
    // Button to create an experiment
    private Button fCreateExperimentCheckbox;
    // Text box for experiment name
    private Text fExperimentNameText;
    private boolean entryChanged = false;
    // The import from directory radio button
    private Button fImportFromDirectoryRadio;
    // The import from archive radio button
    private Button fImportFromArchiveRadio;
    // Flag to remember the "create links" checkbox when it gets disabled by
    // the import from archive radio button
    private Boolean fPreviousCreateLinksValue = true;
    // Button to enable time range filtering
    private Button fTimeRangeCheckbox;
    private Text fStartTimeRangeText;
    private Text fEndTimeRangeText;
    // Time range timestamps
    private ITmfTimestamp fStartTimestamp;
    private ITmfTimestamp fEndTimestamp;

    /** The archive name field */
    protected Combo fArchiveNameField;
    /** The archive browse button. */
    protected Button fArchiveBrowseButton;
    /** The directory name field */
    protected Combo directoryNameField;
    /** The directory browse button. */
    protected Button directoryBrowseButton;

    private ResourceTreeAndListGroup fSelectionGroup;

    // Keep trace of the selection root so that we can dispose its related
    // resources
    private TraceFileSystemElement fSelectionGroupRoot;

    private static final TmfTimestampFormat TIMESTAMP_FORMAT = new TmfTimestampFormat("yyyy-MM-dd HH:mm:ss.SSS SSS SSS"); //$NON-NLS-1$

    // ------------------------------------------------------------------------
    // Constructors
    // ------------------------------------------------------------------------

    /**
     * Constructor. Creates the trace wizard page.
     *
     * @param name
     *            The name of the page.
     * @param selection
     *            The current selection
     */
    protected ImportTraceWizardPage(String name, IStructuredSelection selection) {
        super(name, selection);
        setTitle(Messages.ImportTraceWizard_FileSystemTitle);
        setDescription(Messages.ImportTraceWizard_ImportTrace);

        // Locate the target trace folder
        IFolder traceFolder = null;
        Object element = selection.getFirstElement();

        if (element instanceof TmfTraceFolder) {
            fTraceFolderElement = (TmfTraceFolder) element;
            traceFolder = fTraceFolderElement.getResource();
        } else if (element instanceof IProject) {
            IProject project = (IProject) element;
            try {
                if (project.hasNature(TmfProjectNature.ID)) {
                    TmfProjectRegistry.addTracingNature(project, new NullProgressMonitor());
                    TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true);
                    fTraceFolderElement = projectElement.getTracesFolder();
                    if (fTraceFolderElement != null) {
                        traceFolder = fTraceFolderElement.getResource();
                    }
                }
            } catch (CoreException e) {
            }
        }

        // If no tracing project was selected or trace folder doesn't exist use
        // default tracing project
        if (traceFolder == null) {
            IProject project = TmfProjectRegistry.createProject(
                    TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME, null, new NullProgressMonitor());
            TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true);
            fTraceFolderElement = projectElement.getTracesFolder();
            traceFolder = fTraceFolderElement.getResource();
        }

        // Set the target trace folder
        if (traceFolder != null) {
            String path = traceFolder.getFullPath().toString();
            setContainerFieldValue(path);
        }

        TmfProjectElement project = fTraceFolderElement.getProject();
        fExperimentFolderElement = project.getExperimentsFolder();
    }

    /**
     * Constructor
     *
     * @param selection
     *            The current selection
     */
    public ImportTraceWizardPage(IStructuredSelection selection) {
        this(IMPORT_WIZARD_PAGE_NAME, selection);
    }

    /**
     * Create the import source selection widget. (Copied from
     * WizardResourceImportPage but instead always uses the internal
     * ResourceTreeAndListGroup to keep compatibility with Kepler)
     */
    @Override
    protected void createFileSelectionGroup(Composite parent) {

        // Just create with a dummy root.
        fSelectionGroup = new ResourceTreeAndListGroup(parent,
                new FileSystemElement("Dummy", null, true), //$NON-NLS-1$
                getFolderProvider(), new WorkbenchLabelProvider(),
                getFileProvider(), new WorkbenchLabelProvider(), SWT.NONE,
                DialogUtil.inRegularFontMode(parent));

        ICheckStateListener listener = event -> updateWidgetEnablements();

        WorkbenchViewerComparator comparator = new WorkbenchViewerComparator();
        fSelectionGroup.setTreeComparator(comparator);
        fSelectionGroup.setListComparator(comparator);
        fSelectionGroup.addCheckStateListener(listener);

    }

    // ------------------------------------------------------------------------
    // WizardResourceImportPage
    // ------------------------------------------------------------------------

    @Override
    protected void createSourceGroup(Composite parent) {
        createSourceSelectionGroup(parent);
        createFileSelectionGroup(parent);
        createTraceTypeGroup(parent);
        validateSourceGroup();
    }

    @Override
    protected void createDestinationGroup(Composite parent) {
        Composite containerComposite = new Composite(parent, SWT.NONE);
        containerComposite.setLayout(new GridLayout(2, false));
        containerComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));

        Label destinationLabel = new Label(containerComposite, SWT.NONE);
        destinationLabel.setText(IDEWorkbenchMessages.WizardImportPage_folder);

        Text containerText = new Text(containerComposite, SWT.SINGLE);
        containerText.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
        containerText.setEnabled(false);

        // Initialize the field with the container path
        containerText.setText(getContainerFullPath().toString());
    }

    @Override
    protected ITreeContentProvider getFileProvider() {
        return new WorkbenchContentProvider() {
            @Override
            public Object[] getChildren(Object object) {
                if (object instanceof TraceFileSystemElement) {
                    TraceFileSystemElement element = (TraceFileSystemElement) object;
                    return element.getFiles().getChildren(element);
                }
                return new Object[0];
            }
        };
    }

    @Override
    protected ITreeContentProvider getFolderProvider() {
        return new WorkbenchContentProvider() {
            @Override
            public Object[] getChildren(Object o) {
                if (o instanceof TraceFileSystemElement) {
                    TraceFileSystemElement element = (TraceFileSystemElement) o;
                    return element.getFolders().getChildren();
                }
                return new Object[0];
            }

            @Override
            public boolean hasChildren(Object o) {
                if (o instanceof TraceFileSystemElement) {
                    TraceFileSystemElement element = (TraceFileSystemElement) o;
                    if (element.isPopulated()) {
                        return getChildren(element).length > 0;
                    }
                    // If we have not populated then wait until asked
                    return true;
                }
                return false;
            }
        };
    }

    // ------------------------------------------------------------------------
    // Directory Selection Group (forked WizardFileSystemResourceImportPage1)
    // ------------------------------------------------------------------------

    /**
     * creates the source selection group.
     *
     * @param parent
     *            the parent composite
     */
    protected void createSourceSelectionGroup(Composite parent) {

        Composite sourceGroup = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 3;
        layout.makeColumnsEqualWidth = false;
        layout.marginWidth = 0;
        sourceGroup.setLayout(layout);
        sourceGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        // import from directory radio button
        fImportFromDirectoryRadio = new Button(sourceGroup, SWT.RADIO);
        fImportFromDirectoryRadio.setText(Messages.ImportTraceWizard_DirectoryLocation);

        // import location entry combo
        directoryNameField = createPathSelectionCombo(sourceGroup);
        createDirectoryBrowseButton(sourceGroup);

        // import from archive radio button
        fImportFromArchiveRadio = new Button(sourceGroup, SWT.RADIO);
        fImportFromArchiveRadio.setText(Messages.ImportTraceWizard_ArchiveLocation);

        // import location entry combo
        fArchiveNameField = createPathSelectionCombo(sourceGroup);
        createArchiveBrowseButton(sourceGroup);

        fImportFromDirectoryRadio.setSelection(true);
        fArchiveNameField.setEnabled(false);
        fArchiveBrowseButton.setEnabled(false);

        fImportFromDirectoryRadio.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                directoryRadioSelected();
            }
        });

        fImportFromArchiveRadio.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                archiveRadioSelected();
            }
        });
    }

    /**
     * Select or deselect all files in the file selection group
     *
     * @param checked
     *            whether or not the files should be checked
     */
    protected void setFileSelectionGroupChecked(boolean checked) {
        if (fSelectionGroup != null) {
            fSelectionGroup.setAllSelections(checked);
        }
    }

    /**
     * Create a combo that will be used to select a path to specify the source
     * of the import. The parent is assumed to have a GridLayout.
     *
     * @param parent
     *            the parent composite
     * @return the created path selection combo
     */
    protected Combo createPathSelectionCombo(Composite parent) {
        Combo pathSelectionCombo = new Combo(parent, SWT.BORDER);

        GridData layoutData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
        layoutData.widthHint = new PixelConverter(pathSelectionCombo).convertWidthInCharsToPixels(25);
        pathSelectionCombo.setLayoutData(layoutData);

        TraverseListener traverseListener = e -> {
            if (e.detail == SWT.TRAVERSE_RETURN) {
                e.doit = false;
                entryChanged = false;
                updateFromSourceField();
            }
        };

        FocusAdapter focusAdapter = new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                // Clear the flag to prevent constant update
                if (entryChanged) {
                    entryChanged = false;
                    updateFromSourceField();
                }
            }
        };

        SelectionAdapter selectionAdapter = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                entryChanged = false;
                updateFromSourceField();
            }
        };

        ModifyListener modifyListner = e -> entryChanged = true;

        pathSelectionCombo.addModifyListener(modifyListner);
        pathSelectionCombo.addTraverseListener(traverseListener);
        pathSelectionCombo.addFocusListener(focusAdapter);
        pathSelectionCombo.addSelectionListener(selectionAdapter);

        return pathSelectionCombo;
    }

    /**
     * Create the directory browse button.
     *
     * @param parent
     *            the parent composite
     */
    protected void createDirectoryBrowseButton(Composite parent) {
        directoryBrowseButton = createPathSelectionBrowseButton(parent);
        directoryBrowseButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleSourceDirectoryBrowseButtonPressed();
            }
        });
    }

    /**
     * Create the archive browse button.
     *
     * @param parent
     *            the parent composite
     */
    protected void createArchiveBrowseButton(Composite parent) {
        fArchiveBrowseButton = createPathSelectionBrowseButton(parent);
        fArchiveBrowseButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                handleArchiveBrowseButtonPressed(FILE_IMPORT_MASK);
            }
        });
    }

    /**
     * Create a browse button that will be used to browse for a path to specify
     * the source of the import. The parent is assumed to have a GridLayout.
     *
     * @param parent
     *            the parent composite
     * @return the created path selection combo
     */
    protected Button createPathSelectionBrowseButton(Composite parent) {
        Button pathSelectionBrowseButton = new Button(parent, SWT.PUSH);
        pathSelectionBrowseButton.setText(Messages.ImportTraceWizard_BrowseButton);
        setButtonLayoutData(pathSelectionBrowseButton);

        return pathSelectionBrowseButton;
    }

    private void archiveRadioSelected() {
        if (!isImportFromDirectory()) {
            directoryNameField.setEnabled(false);
            directoryBrowseButton.setEnabled(false);
            fArchiveNameField.setEnabled(true);
            fArchiveBrowseButton.setEnabled(true);
            updateFromSourceField();
            fArchiveNameField.setFocus();
            if (fCreateLinksInWorkspaceButton != null) {
                fPreviousCreateLinksValue = fCreateLinksInWorkspaceButton.getSelection();
                fCreateLinksInWorkspaceButton.setSelection(false);
                fCreateLinksInWorkspaceButton.setEnabled(false);
            }
        }
    }

    private void directoryRadioSelected() {
        if (isImportFromDirectory()) {
            directoryNameField.setEnabled(true);
            directoryBrowseButton.setEnabled(true);
            fArchiveNameField.setEnabled(false);
            fArchiveBrowseButton.setEnabled(false);
            updateFromSourceField();
            directoryNameField.setFocus();
            if (fCreateLinksInWorkspaceButton != null) {
                fCreateLinksInWorkspaceButton.setSelection(fPreviousCreateLinksValue);
                fCreateLinksInWorkspaceButton.setEnabled(true);
            }
        }
    }

    // ------------------------------------------------------------------------
    // Browse for the source directory
    // ------------------------------------------------------------------------

    /**
     * Handle the button pressed event
     */
    protected void handleSourceDirectoryBrowseButtonPressed() {
        String currentSource = directoryNameField.getText();
        DirectoryDialog dialog = DirectoryDialogFactory.create(directoryNameField.getShell(), SWT.SAVE | SWT.SHEET);
        dialog.setText(Messages.ImportTraceWizard_SelectTraceDirectoryTitle);
        dialog.setMessage(Messages.ImportTraceWizard_SelectTraceDirectoryMessage);
        dialog.setFilterPath(getSourceDirectoryName(currentSource));

        String selectedDirectory = dialog.open();
        if (selectedDirectory != null) {
            // Just quit if the directory is not valid
            if ((getSourceDirectory(selectedDirectory) == null) || selectedDirectory.equals(currentSource)) {
                return;
            }
            // If it is valid then proceed to populate
            setErrorMessage(null);
            setSourcePath(selectedDirectory);
        }
    }

    /**
     * Handle the button pressed event
     *
     * @param extensions
     *            file extensions used to filter files shown to the user
     */
    protected void handleArchiveBrowseButtonPressed(String[] extensions) {
        FileDialog dialog = TmfFileDialogFactory.create(fArchiveNameField.getShell(), SWT.SHEET);
        dialog.setFilterExtensions(extensions);
        dialog.setText(Messages.ImportTraceWizard_SelectTraceArchiveTitle);
        String fileName = fArchiveNameField.getText().trim();
        if (!fileName.isEmpty()) {
            File path = new File(fileName).getParentFile();
            if (path != null && path.exists()) {
                dialog.setFilterPath(path.toString());
            }
        }

        String selectedArchive = dialog.open();
        if (selectedArchive != null) {
            setErrorMessage(null);
            setSourcePath(selectedArchive);
            updateWidgetEnablements();
        }
    }

    private File getSourceDirectory() {
        if (directoryNameField == null) {
            return null;
        }
        return getSourceDirectory(directoryNameField.getText());
    }

    private File getSourceArchiveFile() {
        if (fArchiveNameField == null) {
            return null;
        }

        return getSourceArchiveFile(fArchiveNameField.getText());
    }

    private String getSourceContainerPath() {
        if (isImportFromDirectory()) {
            File sourceDirectory = getSourceDirectory();
            if (sourceDirectory != null) {
                return sourceDirectory.getAbsolutePath();
            }
        }
        File sourceArchiveFile = getSourceArchiveFile();
        if (sourceArchiveFile != null) {
            return sourceArchiveFile.getParent();
        }
        return null;
    }

    private static File getSourceDirectory(String path) {
        File sourceDirectory = new File(getSourceDirectoryName(path));
        if (!sourceDirectory.exists() || !sourceDirectory.isDirectory()) {
            return null;
        }

        return sourceDirectory;
    }

    private static File getSourceArchiveFile(String path) {
        File sourceArchiveFile = new File(path);
        if (!sourceArchiveFile.exists() || sourceArchiveFile.isDirectory()) {
            return null;
        }

        return sourceArchiveFile;
    }

    private static String getSourceDirectoryName(String sourceName) {
        IPath result = new Path(sourceName.trim());
        if (result.getDevice() != null && result.segmentCount() == 0) {
            result = result.addTrailingSeparator();
        } else {
            result = result.removeTrailingSeparator();
        }
        return result.toOSString();
    }

    private void updateFromSourceField() {
        setSourcePath(getSourceField().getText());
        updateWidgetEnablements();
    }

    private Combo getSourceField() {
        if (directoryNameField == null) {
            return fArchiveNameField;
        }

        return directoryNameField.isEnabled() ? directoryNameField : fArchiveNameField;
    }

    /**
     * Set the source path that was selected by the user by various input
     * methods (Browse button, typing, etc).
     *
     * Clients can also call this to set the path programmatically (hard-coded
     * initial path) and this can also be overridden to be notified when the
     * source path changes.
     *
     * @param path
     *            the source path
     */
    protected void setSourcePath(String path) {
        Combo sourceField = getSourceField();
        if (sourceField == null) {
            return;
        }

        if (path.length() > 0) {
            String[] currentItems = sourceField.getItems();
            int selectionIndex = -1;
            for (int i = 0; i < currentItems.length; i++) {
                if (currentItems[i].equals(path)) {
                    selectionIndex = i;
                }
            }
            if (selectionIndex < 0) {
                int oldLength = currentItems.length;
                String[] newItems = new String[oldLength + 1];
                System.arraycopy(currentItems, 0, newItems, 0, oldLength);
                newItems[oldLength] = path;
                sourceField.setItems(newItems);
                selectionIndex = oldLength;
            }
            sourceField.select(selectionIndex);
        }
        resetSelection();
    }

    // ------------------------------------------------------------------------
    // File Selection Group (forked WizardFileSystemResourceImportPage1)
    // ------------------------------------------------------------------------
    private void resetSelection() {

        if (fSelectionGroupRoot != null) {
            disposeSelectionGroupRoot();
        }
        fSelectionGroupRoot = getFileSystemTree();
        fSelectionGroup.setRoot(fSelectionGroupRoot);

        if (fCreateExperimentCheckbox != null) {
            File file = getSourceFile();
            if (file != null) {
                String previousName = fExperimentNameText.getText().trim();
                if (((fPreviousSource != null) && (previousName.equals(fPreviousSource))) || previousName.isEmpty()) {
                    fExperimentNameText.setText(file.getName());
                }
                fPreviousSource = file.getName();
            }
        }
    }

    private void disposeSelectionGroupRoot() {
        if (fSelectionGroupRoot != null && fSelectionGroupRoot.getProvider() != null) {
            FileSystemObjectImportStructureProvider provider = fSelectionGroupRoot.getProvider();
            provider.dispose();
            fSelectionGroupRoot = null;
        }
    }

    private TraceFileSystemElement getFileSystemTree() {
        Pair<IFileSystemObject, FileSystemObjectImportStructureProvider> rootObjectAndProvider = ArchiveUtil.getRootObjectAndProvider(getSourceFile(), getContainer().getShell());
        if (rootObjectAndProvider == null) {
            return null;
        }
        return selectFiles(rootObjectAndProvider.getFirst(), rootObjectAndProvider.getSecond());
    }

    private TraceFileSystemElement selectFiles(final IFileSystemObject rootFileSystemObject,
            final FileSystemObjectImportStructureProvider structureProvider) {
        final TraceFileSystemElement[] results = new TraceFileSystemElement[1];
        BusyIndicator.showWhile(getShell().getDisplay(), () -> results[0] = TraceFileSystemElement.createRootTraceFileElement(rootFileSystemObject, structureProvider));
        return results[0];
    }

    // ------------------------------------------------------------------------
    // Trace Type Group
    // ------------------------------------------------------------------------
    private final void createTraceTypeGroup(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 3;
        layout.makeColumnsEqualWidth = false;
        composite.setLayout(layout);
        composite.setFont(parent.getFont());
        GridData buttonData = new GridData(SWT.FILL, SWT.FILL, true, false);
        composite.setLayoutData(buttonData);

        // Trace type label ("Trace Type:")
        Label typeLabel = new Label(composite, SWT.NONE);
        typeLabel.setText(Messages.ImportTraceWizard_TraceType);
        typeLabel.setFont(parent.getFont());

        // Trace type combo
        fTraceTypes = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1);
        fTraceTypes.setLayoutData(data);
        fTraceTypes.setFont(parent.getFont());

        String[] availableTraceTypes = TmfTraceType.getAvailableTraceTypes();
        String[] traceTypeList = new String[availableTraceTypes.length + 1];
        traceTypeList[0] = TRACE_TYPE_AUTO_DETECT;
        System.arraycopy(availableTraceTypes, 0, traceTypeList, 1, availableTraceTypes.length);
        fTraceTypes.setItems(traceTypeList);
        fTraceTypes.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateWidgetEnablements();
                boolean enabled = fTraceTypes.getText().equals(TRACE_TYPE_AUTO_DETECT);
                fImportUnrecognizedButton.setEnabled(enabled);
            }
        });
        fTraceTypes.select(0);

        // Unrecognized checkbox
        fImportUnrecognizedButton = new Button(composite, SWT.CHECK);
        // Do not import unrecognized traces by default
        fImportUnrecognizedButton.setSelection(false);
        fImportUnrecognizedButton.setText(Messages.ImportTraceWizard_ImportUnrecognized);
    }

    // ------------------------------------------------------------------------
    // Options
    // ------------------------------------------------------------------------

    @Override
    protected void createOptionsGroupButtons(Group optionsGroup) {

        // Overwrite checkbox
        fOverwriteExistingResourcesCheckbox = new Button(optionsGroup, SWT.CHECK);
        fOverwriteExistingResourcesCheckbox.setFont(optionsGroup.getFont());
        fOverwriteExistingResourcesCheckbox.setText(Messages.ImportTraceWizard_OverwriteExistingTrace);
        fOverwriteExistingResourcesCheckbox.setSelection(false);

        // Create links checkbox
        fCreateLinksInWorkspaceButton = new Button(optionsGroup, SWT.CHECK);
        fCreateLinksInWorkspaceButton.setFont(optionsGroup.getFont());
        fCreateLinksInWorkspaceButton.setText(Messages.ImportTraceWizard_CreateLinksInWorkspace);
        fCreateLinksInWorkspaceButton.setSelection(true);

        fCreateLinksInWorkspaceButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateWidgetEnablements();
            }
        });

        fPreserveFolderStructureButton = new Button(optionsGroup, SWT.CHECK);
        fPreserveFolderStructureButton.setFont(optionsGroup.getFont());
        fPreserveFolderStructureButton.setText(Messages.ImportTraceWizard_PreserveFolderStructure);
        fPreserveFolderStructureButton.setSelection(true);

        Composite comp = new Composite(optionsGroup, SWT.NONE);
        GridLayout layout = new GridLayout(2, false);
        layout.marginLeft = 0;
        layout.marginRight = 0;
        layout.marginBottom = 0;
        layout.marginTop = 0;
        layout.marginWidth = 0;
        comp.setLayout(layout);
        GridData data = new GridData(GridData.FILL, GridData.CENTER, true, false);
        comp.setLayoutData(data);

        fCreateExperimentCheckbox = new Button(comp, SWT.CHECK);
        fCreateExperimentCheckbox.setFont(comp.getFont());
        fCreateExperimentCheckbox.setText(Messages.ImportTraceWizard_CreateExperiment);
        fCreateExperimentCheckbox.setSelection(false);
        data = new GridData(GridData.BEGINNING, GridData.CENTER, false, false);
        fCreateExperimentCheckbox.setLayoutData(data);

        fExperimentNameText = new Text(comp, SWT.BORDER);
        data = new GridData(GridData.FILL, GridData.CENTER, true, false);
        fExperimentNameText.setLayoutData(data);

        fExperimentNameText.addModifyListener(e -> updateWidgetEnablements());

        fCreateExperimentCheckbox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                fExperimentNameText.setEnabled(fCreateExperimentCheckbox.getSelection());
                updateWidgetEnablements();
            }
        });

        fTimeRangeCheckbox = new Button(optionsGroup, SWT.CHECK);
        fTimeRangeCheckbox.setText(Messages.ImportTraceWizard_TimeRangeOptionButton + " (" + TIMESTAMP_FORMAT.toPattern() + ")"); //$NON-NLS-1$//$NON-NLS-2$

        Composite timeRangeComposite = new Composite(optionsGroup, SWT.NONE);
        GridLayoutFactory.fillDefaults().numColumns(2).applyTo(timeRangeComposite);
        GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(timeRangeComposite);

        Label startTimestampLabel = new Label(timeRangeComposite, SWT.NONE);
        startTimestampLabel.setText(Messages.ImportTraceWizard_StartTime);
        startTimestampLabel.setEnabled(false);
        fStartTimeRangeText = new Text(timeRangeComposite, SWT.SINGLE);
        fStartTimeRangeText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        fStartTimeRangeText.setEnabled(false);

        Label endTimestampLabel = new Label(timeRangeComposite, SWT.NONE);
        endTimestampLabel.setText(Messages.ImportTraceWizard_EndTime);
        endTimestampLabel.setEnabled(false);
        fEndTimeRangeText = new Text(timeRangeComposite, SWT.SINGLE);
        fEndTimeRangeText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        fEndTimeRangeText.setEnabled(false);

        ((GridData) timeRangeComposite.getLayoutData()).exclude = true;

        ModifyListener timeRangeModifyListener = e -> updateWidgetEnablements();

        fStartTimeRangeText.addModifyListener(timeRangeModifyListener);
        fEndTimeRangeText.addModifyListener(timeRangeModifyListener);

        fTimeRangeCheckbox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean isTimeFilteringChecked = fTimeRangeCheckbox.getSelection();
                ((GridData) timeRangeComposite.getLayoutData()).exclude = !isTimeFilteringChecked;
                fStartTimeRangeText.setEnabled(isTimeFilteringChecked);
                fEndTimeRangeText.setEnabled(isTimeFilteringChecked);
                startTimestampLabel.setEnabled(isTimeFilteringChecked);
                endTimestampLabel.setEnabled(isTimeFilteringChecked);
                optionsGroup.getParent().layout(true);
                timeRangeComposite.layout(true);
                updateWidgetEnablements();
            }
        });

        updateWidgetEnablements();
    }

    // ------------------------------------------------------------------------
    // Determine if the finish button can be enabled
    // ------------------------------------------------------------------------
    @Override
    public boolean validateSourceGroup() {

        File source = getSourceFile();
        if (source == null) {
            setMessage(Messages.ImportTraceWizard_SelectTraceSourceEmpty);
            setErrorMessage(null);
            return false;
        }

        if (sourceConflictsWithDestination(new Path(source.getPath()))) {
            setMessage(null);
            setErrorMessage(getSourceConflictMessage());
            return false;
        }

        if (!isImportFromDirectory() && !ArchiveUtil.ensureTarSourceIsValid(source.getAbsolutePath()) && !ArchiveUtil.ensureZipSourceIsValid(source.getAbsolutePath())
                && !ArchiveUtil.ensureGzipSourceIsValid(source.getAbsolutePath())) {
            setMessage(null);
            setErrorMessage(Messages.ImportTraceWizard_BadArchiveFormat);
            return false;
        }

        if (fSelectionGroup.getCheckedElementCount() == 0) {
            setMessage(null);
            setErrorMessage(Messages.ImportTraceWizard_SelectTraceNoneSelected);
            return false;
        }

        IContainer container = getSpecifiedContainer();
        if (container != null && container.isVirtual()) {
            if (Platform.getPreferencesService().getBoolean(Activator.PLUGIN_ID, ResourcesPlugin.PREF_DISABLE_LINKING, false, null)) {
                setMessage(null);
                setErrorMessage(Messages.ImportTraceWizard_CannotImportFilesUnderAVirtualFolder);
                return false;
            }
            if (fCreateLinksInWorkspaceButton == null || !fCreateLinksInWorkspaceButton.getSelection()) {
                setMessage(null);
                setErrorMessage(Messages.ImportTraceWizard_HaveToCreateLinksUnderAVirtualFolder);
                return false;
            }
        }
        setErrorMessage(null);
        return true;
    }

    @Override
    protected boolean validateOptionsGroup() {
        if (fCreateExperimentCheckbox != null && fCreateExperimentCheckbox.getSelection()) {
            String name = fExperimentNameText.getText().trim();
            // verify if experiment name is empty
            if (name.isEmpty()) {
                setMessage(null);
                setErrorMessage(Messages.ImportTraceWizard_ErrorEmptyExperimentName);
                return false;
            }
            // verify that name is a valid resource name
            IWorkspace workspace = ResourcesPlugin.getWorkspace();
            if ((workspace != null) && (!workspace.validateName(name, IResource.FILE).isOK())) {
                setMessage(null);
                setErrorMessage(NLS.bind(Messages.ImportTraceWizard_ErrorExperimentNameInvalid, name));
                return false;
            }
            // verify if experiment already exists
            if (fExperimentFolderElement != null) {
                TmfExperimentElement element = fExperimentFolderElement.getExperiment(name);
                if (element != null) {
                    setMessage(null);
                    setErrorMessage(NLS.bind(Messages.ImportTraceWizard_ErrorExperimentAlreadyExists, name));
                    return false;
                }
                IFolder expResource = fExperimentFolderElement.getResource();
                IResource res = expResource.findMember(name);
                if (res != null) {
                    setMessage(null);
                    setErrorMessage(NLS.bind(Messages.ImportTraceWizard_ErrorResourceAlreadyExists, name));
                    return false;
                }
            }
        }

        if (fTimeRangeCheckbox != null && fTimeRangeCheckbox.getSelection() && !validateTimeRange()) {
            fStartTimestamp = null;
            fEndTimestamp = null;
            setMessage(null);
            setErrorMessage(Messages.ImportTraceWizard_TimeRangeErrorMessage);
            return false;
        }
        setErrorMessage(null);
        return true;
    }

    private boolean validateTimeRange() {
        boolean isEmpty = fStartTimeRangeText.getText().isEmpty() || fEndTimeRangeText.getText().isEmpty();
        return !isEmpty && parseTimeRange() && fStartTimestamp.compareTo(fEndTimestamp) < 0;
    }

    private boolean parseTimeRange() {
        try {
            TIMESTAMP_FORMAT.setTimeZone(TmfTimestampFormat.getDefaulTimeFormat().getTimeZone());
            long startTimeValue = TIMESTAMP_FORMAT.parseValue(fStartTimeRangeText.getText());
            long endTimeValue = TIMESTAMP_FORMAT.parseValue(fEndTimeRangeText.getText());
            // Swap timestamps if start is after end
            if(startTimeValue < endTimeValue) {
                fStartTimestamp = TmfTimestamp.fromNanos(startTimeValue);
                fEndTimestamp = TmfTimestamp.fromNanos(endTimeValue);
            } else {
                fStartTimestamp = TmfTimestamp.fromNanos(endTimeValue);
                fEndTimestamp = TmfTimestamp.fromNanos(startTimeValue);
            }
            return true;
        } catch (ParseException e) {
            return false;
        }
    }

    private File getSourceFile() {
        return isImportFromDirectory() ? getSourceDirectory() : getSourceArchiveFile();
    }

    private boolean isImportFromDirectory() {
        return fImportFromDirectoryRadio != null && fImportFromDirectoryRadio.getSelection();
    }

    @Override
    protected void restoreWidgetValues() {
        super.restoreWidgetValues();

        IDialogSettings settings = getDialogSettings();
        boolean value;
        if (fImportUnrecognizedButton != null) {
            if (settings.get(getPageStoreKey(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID)) == null) {
                value = false;
            } else {
                value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID));
            }
            fImportUnrecognizedButton.setSelection(value);
        }

        if (fPreserveFolderStructureButton != null) {
            if (settings.get(getPageStoreKey(IMPORT_WIZARD_PRESERVE_FOLDERS_ID)) == null) {
                value = true;
            } else {
                value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_PRESERVE_FOLDERS_ID));
            }
            fPreserveFolderStructureButton.setSelection(value);
        }

        if (fCreateExperimentCheckbox != null) {
            if (settings.get(getPageStoreKey(IMPORT_WIZARD_CREATE_EXPERIMENT_ID)) == null) {
                value = false;
            } else {
                value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_CREATE_EXPERIMENT_ID));
            }
            fCreateExperimentCheckbox.setSelection(value);
            fExperimentNameText.setEnabled(fCreateExperimentCheckbox.getSelection());
        }

        if (settings.get(getPageStoreKey(IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID)) == null) {
            value = true;
        } else {
            value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID));
        }

        if (directoryNameField != null) {
            restoreComboValues(directoryNameField, settings, getPageStoreKey(IMPORT_WIZARD_ROOT_DIRECTORY_ID));
        }
        if (fArchiveNameField != null) {
            restoreComboValues(fArchiveNameField, settings, getPageStoreKey(IMPORT_WIZARD_ARCHIVE_FILE_NAME_ID));
        }

        if (fImportFromDirectoryRadio != null) {
            fImportFromDirectoryRadio.setSelection(value);
            if (value) {
                directoryRadioSelected();
            }
        }
        if (fImportFromArchiveRadio != null) {
            fImportFromArchiveRadio.setSelection(!value);
            if (!value) {
                archiveRadioSelected();
            }
        }
    }

    @Override
    protected void saveWidgetValues() {
        // Persist dialog settings
        IDialogSettings settings = getDialogSettings();
        if (fImportUnrecognizedButton != null) {
            settings.put(getPageStoreKey(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID), fImportUnrecognizedButton.getSelection());
        }
        if (fPreserveFolderStructureButton != null) {
            settings.put(getPageStoreKey(IMPORT_WIZARD_PRESERVE_FOLDERS_ID), fPreserveFolderStructureButton.getSelection());
        }

        if (fCreateExperimentCheckbox != null) {
            settings.put(getPageStoreKey(IMPORT_WIZARD_CREATE_EXPERIMENT_ID), fCreateExperimentCheckbox.getSelection());
        }

        settings.put(getPageStoreKey(IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID), isImportFromDirectory());

        if (directoryNameField != null) {
            saveComboValues(directoryNameField, settings, getPageStoreKey(IMPORT_WIZARD_ROOT_DIRECTORY_ID));
        }
        if (fArchiveNameField != null) {
            saveComboValues(fArchiveNameField, settings, getPageStoreKey(IMPORT_WIZARD_ARCHIVE_FILE_NAME_ID));
        }
    }

    private String getPageStoreKey(String key) {
        return getName() + key;
    }

    private static void restoreComboValues(Combo combo, IDialogSettings settings, String key) {
        String[] directoryNames = settings.getArray(key);
        if ((directoryNames != null) && (directoryNames.length != 0)) {
            for (int i = 0; i < directoryNames.length; i++) {
                combo.add(directoryNames[i]);
            }
        }
    }

    private void saveComboValues(Combo combo, IDialogSettings settings, String key) {
        // update names history
        String[] directoryNames = settings.getArray(key);
        if (directoryNames == null) {
            directoryNames = new String[0];
        }

        String items[] = combo.getItems();
        for (int i = 0; i < items.length; i++) {
            directoryNames = addToHistory(directoryNames, items[i]);
        }
        settings.put(key, directoryNames);
    }

    // ------------------------------------------------------------------------
    // Import the trace(s)
    // ------------------------------------------------------------------------

    /**
     * Finish the import.
     *
     * @return <code>true</code> if successful else <code>false</code>
     */
    public boolean finish() {
        String traceTypeLabel = getImportTraceTypeId();
        final String traceId = !TRACE_TYPE_AUTO_DETECT.equals(traceTypeLabel) ? TmfTraceType.getTraceTypeId(traceTypeLabel) : null;

        // Save dialog settings
        saveWidgetValues();

        final IPath baseSourceContainerPath = new Path(getSourceContainerPath());
        final boolean importFromArchive = getSourceArchiveFile() != null;
        final boolean keepArchive;
        final int importOptionFlags = getImportOptionFlags();
        final IPath destinationContainerPath = getContainerFullPath();

        // Get the archive name in case we decide to keep the archive later
        final String archiveName;
        File sourceArchiveFile = getSourceArchiveFile();
        if (importFromArchive && sourceArchiveFile != null) {
            archiveName = sourceArchiveFile.getName();
            long archiveSize = ArchiveUtil.getArchiveSize(sourceArchiveFile.getAbsolutePath());
            keepArchive = (archiveSize != -1 && archiveSize >= ARCHIVE_SIZE_THRESHOLD) ? true : false;
        } else {
            archiveName = null;
            keepArchive = false;
        }

        final IStatus[] operationStatus = new IStatus[1];
        operationStatus[0] = Status.OK_STATUS;
        final List<IResource> traceResources = new ArrayList<>();
        try {
            getContainer().run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {

                    final List<TraceFileSystemElement> selectedFileSystemElements = new LinkedList<>();
                    IElementFilter passThroughFilter = new IElementFilter() {

                        @Override
                        public void filterElements(Collection elements, IProgressMonitor m) {
                            selectedFileSystemElements.addAll(elements);
                        }

                        @Override
                        public void filterElements(Object[] elements, IProgressMonitor m) {
                            for (int i = 0; i < elements.length; i++) {
                                selectedFileSystemElements.add((TraceFileSystemElement) elements[i]);
                            }
                        }
                    };

                    // List fileSystemElements will be filled using the
                    // passThroughFilter
                    SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
                    fSelectionGroup.getAllCheckedListItems(passThroughFilter, subMonitor);

                    final TraceValidateAndImportOperation operation = new TraceValidateAndImportOperation(getContainer().getShell(), selectedFileSystemElements, traceId, baseSourceContainerPath, destinationContainerPath, importFromArchive,
                            importOptionFlags, fTraceFolderElement, fStartTimestamp, fEndTimestamp, archiveName, keepArchive);
                    operation.run(monitor);
                    monitor.done();
                    operationStatus[0] = operation.getStatus();
                    traceResources.addAll(operation.getImportedResources());
                }
            });

            // Only create experiment when option is selected and
            // if there has been at least one trace imported
            if (((importOptionFlags & OPTION_CREATE_EXPERIMENT) != 0) && (!traceResources.isEmpty())) {
                final IFolder[] experimentFolders = new IFolder[1];
                final TmfExperimentFolder root = fExperimentFolderElement;
                final String experimentName = fExperimentNameText.getText().trim();
                // just safety guards
                if ((root == null) || (experimentName.isEmpty())) {
                    return true;
                }
                if ((operationStatus[0] != null) && (operationStatus[0].isOK())) {
                    getContainer().run(true, true, new IRunnableWithProgress() {
                        @Override
                        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                            operationStatus[0] = null;
                            final NewExperimentOperation operation = new NewExperimentOperation(root, experimentName);
                            operation.run(monitor);
                            monitor.done();
                            operationStatus[0] = operation.getStatus();
                            experimentFolders[0] = operation.getExperimentFolder();
                        }
                    });

                    final IFolder expFolder = experimentFolders[0];
                    final TmfTraceFolder parentTraceFolder = fTraceFolderElement;
                    // just safety guards
                    if ((expFolder == null) || (parentTraceFolder == null)) {
                        return true;
                    }
                    if ((operationStatus[0] != null) && (operationStatus[0].isOK())) {
                        getContainer().run(true, true, new IRunnableWithProgress() {
                            @Override
                            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                                operationStatus[0] = null;
                                final SelectTracesOperation operation = new SelectTracesOperation(root, expFolder, parentTraceFolder, traceResources);
                                operation.run(monitor);
                                monitor.done();
                                operationStatus[0] = operation.getStatus();
                            }
                        });
                    }
                }
            }
        } catch (InvocationTargetException e) {
            operationStatus[0] = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ImportTraceWizard_ImportProblem, e.getTargetException());
        } catch (InterruptedException e) {
            operationStatus[0] = Status.CANCEL_STATUS;
            Thread.currentThread().interrupt();
        }
        if (!operationStatus[0].isOK()) {
            if (operationStatus[0].getSeverity() == IStatus.CANCEL) {
                setMessage(Messages.ImportTraceWizard_ImportOperationCancelled);
                setErrorMessage(null);
            } else {
                Throwable exception = operationStatus[0].getException();
                if (exception != null) {
                    Activator.getDefault().logError(exception.getMessage(), exception);
                    displayErrorDialog(operationStatus[0].getMessage() + ": " + exception); //$NON-NLS-1$
                }
                setMessage(null);
                setErrorMessage(Messages.ImportTraceWizard_ImportProblem);
            }
            return false;
        }
        setErrorMessage(null);
        return true;
    }

    /**
     * Get the trace type id to import as. This can also return
     * {@link #TRACE_TYPE_AUTO_DETECT} to communicate that automatic trace type
     * detection will occur instead of setting a specific trace type when
     * importing the traces.
     *
     * @return the trace type id or {@link #TRACE_TYPE_AUTO_DETECT}
     */
    protected String getImportTraceTypeId() {
        return fTraceTypes.getText();
    }

    /**
     * Get import options in the form of flags (bits).
     *
     * @return the import flags.
     * @see #OPTION_CREATE_LINKS_IN_WORKSPACE
     * @see #OPTION_IMPORT_UNRECOGNIZED_TRACES
     * @see #OPTION_OVERWRITE_EXISTING_RESOURCES
     * @see #OPTION_PRESERVE_FOLDER_STRUCTURE
     * @see #OPTION_CREATE_EXPERIMENT
     */
    protected int getImportOptionFlags() {
        int flags = 0;
        if (fCreateLinksInWorkspaceButton != null && fCreateLinksInWorkspaceButton.getSelection()) {
            flags |= OPTION_CREATE_LINKS_IN_WORKSPACE;
        }
        if (fImportUnrecognizedButton != null && fImportUnrecognizedButton.getSelection()) {
            flags |= OPTION_IMPORT_UNRECOGNIZED_TRACES;
        }
        if (fOverwriteExistingResourcesCheckbox != null && fOverwriteExistingResourcesCheckbox.getSelection()) {
            flags |= OPTION_OVERWRITE_EXISTING_RESOURCES;
        }
        if (fPreserveFolderStructureButton != null && fPreserveFolderStructureButton.getSelection()) {
            flags |= OPTION_PRESERVE_FOLDER_STRUCTURE;
        }
        if (fCreateExperimentCheckbox != null && fCreateExperimentCheckbox.getSelection()) {
            flags |= OPTION_CREATE_EXPERIMENT;
        }
        if (fTimeRangeCheckbox != null && fTimeRangeCheckbox.getSelection()) {
            flags |= OPTION_FILTER_TIMERANGE;
        }
        return flags;
    }

    @Override
    public void dispose() {
        super.dispose();
        disposeSelectionGroupRoot();
    }
}
