/*******************************************************************************
 * Copyright (c) 2009, 2021 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.pde.api.tools.ui.internal.use;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory;
import org.eclipse.jface.util.BidiUtils;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
import org.eclipse.pde.api.tools.ui.internal.ApiUIPlugin;
import org.eclipse.pde.api.tools.ui.internal.IApiToolsConstants;
import org.eclipse.pde.api.tools.ui.internal.IApiToolsHelpContextIds;
import org.eclipse.pde.api.tools.ui.internal.SWTFactory;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetHandle;
import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.TargetPlatformHelper;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
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.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;

/**
 * Tab for an API use scan
 *
 * @since 1.1
 */
public class ApiUseScanTab extends AbstractLaunchConfigurationTab {

	static final String[] EXTENSIONS = new String[] { "*.txt" }; //$NON-NLS-1$

	/**
	 * Default selection adapter for updating the launch dialog
	 */
	SelectionListener selectionadapter = SelectionListener.widgetSelectedAdapter(e -> updateDialog());

	/**
	 * Default modify adapter for updating the launch dialog
	 */
	ModifyListener modifyadapter = e -> updateDialog();

	boolean initializing = false;
	Combo baseline, targetCombo, reportTypeCombo;
	Button radioBaseline = null, radioTarget = null, radioInstall = null,
			radioReportOnly = null, baselinesButton = null,
			targetsButton = null, installButton = null, considerapi = null,
			considerinternal = null, consideruse = null, createhtml = null,
			openreport = null, cleanreportlocation = null,
			cleanhtmllocation = null;
	ITargetHandle[] targetHandles = new ITargetHandle[0];
	Text installLocation = null, searchScope = null, targetScope = null,
			reportlocation = null, description = null, filterRoot = null;
	Group searchForGroup = null, searchInGroup = null, filterGroup = null;

	@Override
	public void createControl(Composite parent) {
		Composite comp = SWTFactory.createComposite(parent, 2, 1, GridData.FILL_HORIZONTAL);
		GridLayout layout = (GridLayout) comp.getLayout();
		layout.makeColumnsEqualWidth = true;

		Group reportGroup = SWTFactory.createGroup(comp, Messages.ApiUseScanTab_analuze, 3, 3, GridData.FILL_HORIZONTAL);
		this.radioBaseline = SWTFactory.createRadioButton(reportGroup, Messages.ApiUseScanTab_api_baseline);
		this.radioBaseline.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> updateTarget()));
		this.baseline = SWTFactory.createCombo(reportGroup, SWT.BORDER | SWT.FLAT | SWT.READ_ONLY, 1, GridData.BEGINNING | GridData.FILL_HORIZONTAL, null);
		GridData gd = (GridData) this.baseline.getLayoutData();
		gd.grabExcessHorizontalSpace = true;
		this.baseline.addSelectionListener(selectionadapter);
		this.baselinesButton = SWTFactory.createPushButton(reportGroup, Messages.ApiUseScanTab_baselines, null);
		this.baselinesButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
			int bef = ApiUseScanTab.this.baseline.getSelectionIndex();
			String name = null;
			if (bef >= 0) {
				name = ApiUseScanTab.this.baseline.getItem(bef);
			}
			SWTFactory.showPreferencePage(getTabShell(), "org.eclipse.pde.api.tools.ui.apiprofiles.prefpage", null); //$NON-NLS-1$
			updateAvailableBaselines();
			if (ApiUseScanTab.this.baseline.getItemCount() == 1) {
				name = ApiUseScanTab.this.baseline.getItem(0);
			}
			if (name != null) {
				String[] items = ApiUseScanTab.this.baseline.getItems();
				for (int i = 0; i < items.length; i++) {
					if (name.equals(items[i])) {
						ApiUseScanTab.this.baseline.select(i);
						break;
					}
				}
			}
			updateDialog();
		}));

		this.radioTarget = SWTFactory.createRadioButton(reportGroup, Messages.ApiUseScanTab_target_definitions);
		this.radioTarget.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> updateTarget()));
		this.targetCombo = SWTFactory.createCombo(reportGroup, SWT.BORDER | SWT.FLAT | SWT.READ_ONLY, 1, GridData.BEGINNING | GridData.FILL_HORIZONTAL, null);
		gd = (GridData) this.targetCombo.getLayoutData();
		gd.grabExcessHorizontalSpace = true;
		this.targetCombo.addSelectionListener(selectionadapter);
		this.targetsButton = SWTFactory.createPushButton(reportGroup, Messages.ApiUseScanTab_targets, null);
		this.targetsButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
			int index = ApiUseScanTab.this.targetCombo.getSelectionIndex();
			ITargetHandle handle = null;
			if (index >= 0) {
				handle = ApiUseScanTab.this.targetHandles[index];
			}
			SWTFactory.showPreferencePage(getTabShell(), "org.eclipse.pde.ui.TargetPlatformPreferencePage", null); //$NON-NLS-1$
			updateAvailableTargets();
			if (handle != null) {
				for (int i = 0; i < targetHandles.length; i++) {
					if (handle.equals(targetHandles[i])) {
						targetCombo.select(i);
						break;
					}
				}
			}
			updateDialog();
		}));

		this.radioInstall = SWTFactory.createRadioButton(reportGroup, Messages.ApiUseScanTab_install_location);
		this.radioInstall.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> updateTarget()));
		this.installLocation = SWTFactory.createText(reportGroup, SWT.SINGLE | SWT.FLAT | SWT.BORDER, 1, GridData.FILL_HORIZONTAL);
		gd = (GridData) this.installLocation.getLayoutData();
		gd.grabExcessHorizontalSpace = true;
		this.installLocation.addModifyListener(e -> scheduleUpdate());

		this.installButton = SWTFactory.createPushButton(reportGroup, Messages.ApiUseScanTab_browse, null);
		this.installButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
			handleFolderBrowse(ApiUseScanTab.this.installLocation, Messages.ApiUseScanTab_select_install_location);
			updateDialog();
		}));
		this.radioReportOnly = SWTFactory.createRadioButton(reportGroup, Messages.ApiUseScanTab_generate_html_only);
		gd = (GridData) this.radioReportOnly.getLayoutData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalSpan = 2;
		this.radioReportOnly.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> updateTarget()));

		searchForGroup = SWTFactory.createGroup(comp, Messages.ApiUseScanTab_search_for, 2, 1, GridData.FILL_HORIZONTAL);
		SWTFactory.createLabel(searchForGroup, Messages.ApiUseScanTab_references_to, 1);
		this.targetScope = SWTFactory.createText(searchForGroup, SWT.SINGLE | SWT.FLAT | SWT.BORDER, 1, GridData.FILL_HORIZONTAL);
		this.targetScope.addModifyListener(modifyadapter);
		this.considerapi = SWTFactory.createCheckButton(searchForGroup, Messages.ApiUseScanTab_api_references, null, true, 2);
		this.considerapi.addSelectionListener(selectionadapter);
		this.considerinternal = SWTFactory.createCheckButton(searchForGroup, Messages.ApiUseScanTab_internal_references, null, true, 2);
		this.considerinternal.addSelectionListener(selectionadapter);
		this.consideruse = SWTFactory.createCheckButton(searchForGroup, Messages.ApiUseScanTab_illegal_api_use, null, true, 2);
		this.consideruse.addSelectionListener(selectionadapter);

		searchInGroup = SWTFactory.createGroup(comp, Messages.ApiUseScanTab_search_in, 2, 1, GridData.FILL_HORIZONTAL);
		gd = (GridData) searchInGroup.getLayoutData();
		gd.verticalAlignment = SWT.FILL;
		SWTFactory.createLabel(searchInGroup, Messages.ApiUseScanTab_bundles_matching, 1);
		this.searchScope = SWTFactory.createText(searchInGroup, SWT.SINGLE | SWT.FLAT | SWT.BORDER, 1, GridData.FILL_HORIZONTAL);
		this.searchScope.addModifyListener(modifyadapter);

		filterGroup = SWTFactory.createGroup(comp, Messages.ApiUseScanTab_filters, 3, 2, GridData.FILL_HORIZONTAL);
		SWTFactory.createLabel(filterGroup, Messages.ApiUseScanTab_additionalFilters, 1);
		this.filterRoot = SWTFactory.createText(filterGroup, SWT.SINGLE | SWT.FLAT | SWT.BORDER, 1, GridData.FILL_HORIZONTAL);
		BidiUtils.applyBidiProcessing(this.filterRoot, StructuredTextTypeHandlerFactory.FILE);
		this.filterRoot.addModifyListener(modifyadapter);
		Button filterBrowse = SWTFactory.createPushButton(filterGroup, Messages.ApiUseScanTab_Browse, null);
		filterBrowse.addSelectionListener(SelectionListener.widgetSelectedAdapter(
				e -> handleFolderBrowse(ApiUseScanTab.this.filterRoot, Messages.ApiUseScanTab_FilterBrowseTitle)));

		reportGroup = SWTFactory.createGroup(comp, Messages.ApiUseScanTab_reporting, 2, 2, GridData.FILL_HORIZONTAL);

		Composite reportTypeComp = SWTFactory.createComposite(reportGroup, 2, 2, GridData.BEGINNING, 0, 0);
		SWTFactory.createLabel(reportTypeComp, Messages.ApiUseScanTab_reportType, 1);
		reportTypeCombo = SWTFactory.createCombo(reportTypeComp, SWT.READ_ONLY, 1, GridData.FILL_BOTH, new String[] {
				Messages.ApiUseScanTab_referencedBundlesReport,
				Messages.ApiUseScanTab_referencingBundlesReport });
		reportTypeCombo.addSelectionListener(selectionadapter);

		SWTFactory.createLabel(reportGroup, Messages.ApiUseScanTab_report_location, 2);
		this.reportlocation = SWTFactory.createText(reportGroup, SWT.SINGLE | SWT.FLAT | SWT.BORDER, 1, GridData.FILL_HORIZONTAL);
		BidiUtils.applyBidiProcessing(this.reportlocation, StructuredTextTypeHandlerFactory.FILE);
		this.reportlocation.addModifyListener(modifyadapter);
		gd = (GridData) this.reportlocation.getLayoutData();
		gd.grabExcessHorizontalSpace = true;
		Button browse = SWTFactory.createPushButton(reportGroup, Messages.ApiUseScanTab_brows_e_, null);
		browse.addSelectionListener(SelectionListener.widgetSelectedAdapter(
				e -> handleFolderBrowse(ApiUseScanTab.this.reportlocation, Messages.ApiUseScanTab_SelectDirectory)));
		this.cleanreportlocation = SWTFactory.createCheckButton(reportGroup, Messages.ApiUseScanTab_clean_report_dir, null, false, 2);
		gd = (GridData) this.cleanreportlocation.getLayoutData();
		this.cleanreportlocation.addSelectionListener(selectionadapter);
		gd.horizontalIndent = 10;

		this.createhtml = SWTFactory.createCheckButton(reportGroup, Messages.ApiUseScanTab_create_html_report, null, false, 2);
		this.createhtml.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
			updateReportOptions();
			updateDialog();
		}));
		this.cleanhtmllocation = SWTFactory.createCheckButton(reportGroup, Messages.ApiUseScanTab_clean_html_report_dir, null, false, 2);
		gd = (GridData) this.cleanhtmllocation.getLayoutData();
		gd.horizontalIndent = 10;
		this.cleanhtmllocation.addSelectionListener(selectionadapter);
		this.openreport = SWTFactory.createCheckButton(reportGroup, Messages.ApiUseScanTab_open_report, null, false, 2);
		gd = (GridData) this.openreport.getLayoutData();
		gd.horizontalIndent = 10;
		this.openreport.setEnabled(false);
		this.openreport.addSelectionListener(selectionadapter);
		SWTFactory.createLabel(reportGroup, Messages.ApiUseScanTab_description, 1);
		this.description = SWTFactory.createText(reportGroup, SWT.BORDER | SWT.V_SCROLL | SWT.WRAP, 2, GridData.FILL_HORIZONTAL);
		gd = (GridData) this.description.getLayoutData();
		gd.heightHint = 40;
		this.description.addModifyListener(modifyadapter);
		PlatformUI.getWorkbench().getHelpSystem().setHelp(comp, IApiToolsHelpContextIds.API_USE_SCAN_TAB);
		setControl(comp);
	}

	/**
	 * Avoid synthetic accessor
	 */
	void updateDialog() {
		updateLaunchConfigurationDialog();
	}

	/**
	 * Avoid synthetic accessor
	 */
	void scheduleUpdate() {
		scheduleUpdateJob();
	}

	/**
	 * Avoid synthetic accessor
	 */
	Shell getTabShell() {
		return getShell();
	}

	/**
	 * The selected target has changed (radio selection). Update control enabled
	 * state and dialog.
	 */
	void updateTarget() {
		switch (getTargetKind()) {
			case ApiUseLaunchDelegate.KIND_API_BASELINE: {
				baseline.setEnabled(true);
				baselinesButton.setEnabled(true);
				targetCombo.setEnabled(false);
				targetsButton.setEnabled(false);
				installLocation.setEnabled(false);
				installButton.setEnabled(false);
				this.createhtml.setEnabled(true);
				this.cleanreportlocation.setEnabled(true);
				this.description.setEnabled(true);
				setGroupEnablement(this.searchForGroup, true);
				setGroupEnablement(this.searchInGroup, true);
				setGroupEnablement(this.filterGroup, true);
				break;
			}
			case ApiUseLaunchDelegate.KIND_TARGET_DEFINITION: {
				baseline.setEnabled(false);
				baselinesButton.setEnabled(false);
				targetCombo.setEnabled(true);
				targetsButton.setEnabled(true);
				installLocation.setEnabled(false);
				installButton.setEnabled(false);
				this.createhtml.setEnabled(true);
				this.cleanreportlocation.setEnabled(true);
				this.description.setEnabled(true);
				setGroupEnablement(this.searchForGroup, true);
				setGroupEnablement(this.searchInGroup, true);
				setGroupEnablement(this.filterGroup, true);
				break;
			}
			case ApiUseLaunchDelegate.KIND_INSTALL_PATH: {
				baseline.setEnabled(false);
				baselinesButton.setEnabled(false);
				targetCombo.setEnabled(false);
				targetsButton.setEnabled(false);
				installLocation.setEnabled(true);
				installButton.setEnabled(true);
				this.createhtml.setEnabled(true);
				this.cleanreportlocation.setEnabled(true);
				this.description.setEnabled(true);
				setGroupEnablement(this.searchForGroup, true);
				setGroupEnablement(this.searchInGroup, true);
				setGroupEnablement(this.filterGroup, true);
				break;
			}
			case ApiUseLaunchDelegate.KIND_HTML_ONLY: {
				baseline.setEnabled(false);
				baselinesButton.setEnabled(false);
				targetCombo.setEnabled(false);
				targetsButton.setEnabled(false);
				installLocation.setEnabled(false);
				installButton.setEnabled(false);
				this.createhtml.setSelection(true);
				this.createhtml.setEnabled(false);
				this.cleanreportlocation.setEnabled(false);
				this.description.setEnabled(false);
				setGroupEnablement(this.searchForGroup, false);
				setGroupEnablement(this.searchInGroup, false);
				setGroupEnablement(this.filterGroup, false);
				break;
			}
			default:
				break;
		}
		updateReportOptions();
		updateLaunchConfigurationDialog();
	}

	/**
	 * Updates the report options
	 */
	void updateReportOptions() {
		boolean enabled = this.createhtml.getSelection();
		this.openreport.setEnabled(enabled);
		this.cleanhtmllocation.setEnabled(enabled);
	}

	/**
	 * Sets the enabled state of all of the child of the given group
	 */
	void setGroupEnablement(Group group, boolean enabled) {
		Control[] children = group.getChildren();
		for (Control element : children) {
			element.setEnabled(enabled);
		}
	}

	/**
	 * @return the kind of target selected for the scan
	 */
	private int getTargetKind() {
		if (this.radioBaseline.getSelection()) {
			return ApiUseLaunchDelegate.KIND_API_BASELINE;
		} else if (this.radioTarget.getSelection()) {
			return ApiUseLaunchDelegate.KIND_TARGET_DEFINITION;
		} else if (this.radioInstall.getSelection()) {
			return ApiUseLaunchDelegate.KIND_INSTALL_PATH;
		} else if (this.radioReportOnly.getSelection()) {
			return ApiUseLaunchDelegate.KIND_HTML_ONLY;
		} else {
			return -1;
		}
	}

	@Override
	public String getName() {
		return Messages.ApiUseScanTab_api_use_report;
	}

	@Override
	public Image getImage() {
		return ApiUIPlugin.getSharedImage(IApiToolsConstants.IMG_ELCL_SETUP_APITOOLS);
	}

	/**
	 * Updates available target definitions.
	 */
	void updateAvailableTargets() {
		List<String> names = new ArrayList<>();
		ITargetPlatformService service = getTargetService();
		if (service != null) {
			ITargetHandle[] handles = service.getTargets(null);
			List<ITargetDefinition> defs = new ArrayList<>();
			for (ITargetHandle handle : handles) {
				try {
					defs.add(handle.getTargetDefinition());
				} catch (CoreException e) {
					// Suppress
				}
			}
			Collections.sort(defs, (o1, o2) -> {
				ITargetDefinition d1 = o1;
				ITargetDefinition d2 = o2;

				final String name1 = d1.getName();
				final String name2 = d2.getName();
				if (name1 == null) {
					if (name2 == null) {
						return d1.getHandle().toString().compareTo(d2.getHandle().toString());
					}
					return -1;
				} else if (name2 == null) {
					return 1;
				}
				return name1.compareTo(name2);
			});
			targetHandles = new ITargetHandle[defs.size()];
			for (int i = 0; i < defs.size(); i++) {
				ITargetDefinition def = defs.get(i);
				final ITargetHandle handle = def.getHandle();
				targetHandles[i] = handle;
				final String name = def.getName();
				names.add(name == null ? handle.toString() : name);
			}
		}
		this.targetCombo.setItems(names.toArray(new String[names.size()]));
	}

	/**
	 * Returns the target service or <code>null</code>
	 *
	 * @return service or <code>null</code>
	 */
	private ITargetPlatformService getTargetService() {
		return PDECore.getDefault().acquireService(ITargetPlatformService.class);
	}

	/**
	 * Updates available baselines.
	 */
	void updateAvailableBaselines() {
		HashSet<String> ids = new HashSet<>();
		IApiBaseline[] baselines = ApiPlugin.getDefault().getApiBaselineManager().getApiBaselines();
		for (IApiBaseline apiBaseline : baselines) {
			ids.add(apiBaseline.getName());
		}
		this.baseline.setItems(ids.toArray(new String[ids.size()]));
	}

	@Override
	public void initializeFrom(ILaunchConfiguration configuration) {
		this.initializing = true;
		try {
			updateAvailableBaselines();
			updateAvailableTargets();
			updateRadioButtons(configuration);
			restoreComboSelection(this.baseline, configuration.getAttribute(ApiUseLaunchDelegate.BASELINE_NAME, (String) null));
			String memento = configuration.getAttribute(ApiUseLaunchDelegate.TARGET_HANDLE, (String) null);
			if (memento != null) {
				ITargetPlatformService service = getTargetService();
				if (service != null) {
					ITargetHandle handle = service.getTarget(memento);
					for (int i = 0; i < this.targetHandles.length; i++) {
						if (handle.equals(this.targetHandles[i])) {
							this.targetCombo.select(i);
							break;
						}
					}
				}
			}
			if (this.targetCombo.getSelectionIndex() < 0) {
				this.targetCombo.select(0);
			}
			this.installLocation.setText(configuration.getAttribute(ApiUseLaunchDelegate.INSTALL_PATH, IApiToolsConstants.EMPTY_STRING));
			this.considerapi.setSelection(isSpecified(ApiUseLaunchDelegate.MOD_API_REFERENCES, configuration));
			this.considerinternal.setSelection(isSpecified(ApiUseLaunchDelegate.MOD_INTERNAL_REFERENCES, configuration));
			this.consideruse.setSelection(isSpecified(ApiUseLaunchDelegate.MOD_ILLEGAL_USE, configuration));
			this.filterRoot.setText(configuration.getAttribute(ApiUseLaunchDelegate.FILTER_ROOT, IApiToolsConstants.EMPTY_STRING));

			int reportType = configuration.getAttribute(ApiUseLaunchDelegate.REPORT_TYPE, ApiUseLaunchDelegate.REPORT_KIND_PRODUCER);
			if (reportType == ApiUseLaunchDelegate.REPORT_KIND_CONSUMER) {
				this.reportTypeCombo.select(1);
			} else {
				this.reportTypeCombo.select(0);
			}

			this.reportlocation.setText(configuration.getAttribute(ApiUseLaunchDelegate.REPORT_PATH, IApiToolsConstants.EMPTY_STRING));
			this.cleanreportlocation.setSelection(isSpecified(ApiUseLaunchDelegate.CLEAN_XML, configuration));
			boolean enabled = isSpecified(ApiUseLaunchDelegate.CREATE_HTML, configuration);
			this.createhtml.setSelection(enabled);
			this.openreport.setEnabled(enabled);
			this.cleanhtmllocation.setEnabled(enabled);
			this.openreport.setSelection(isSpecified(ApiUseLaunchDelegate.DISPLAY_REPORT, configuration));
			this.cleanhtmllocation.setSelection(isSpecified(ApiUseLaunchDelegate.CLEAN_HTML, configuration));
			this.searchScope.setText(configuration.getAttribute(ApiUseLaunchDelegate.SEARCH_SCOPE, IApiToolsConstants.EMPTY_STRING));
			this.targetScope.setText(configuration.getAttribute(ApiUseLaunchDelegate.TARGET_SCOPE, IApiToolsConstants.EMPTY_STRING));
			this.description.setText(configuration.getAttribute(ApiUseLaunchDelegate.DESCRIPTION, IApiToolsConstants.EMPTY_STRING));
			updateTarget();
		} catch (CoreException e) {
			setErrorMessage(e.getStatus().getMessage());
		} finally {
			this.initializing = false;
		}
	}

	/**
	 * Updates the radio button group in
	 * {@link #initializeFrom(ILaunchConfiguration)} to ensure the radio group
	 * stays up-to-date when a revert is performed
	 */
	void updateRadioButtons(ILaunchConfiguration configuration) throws CoreException {
		int kind = configuration.getAttribute(ApiUseLaunchDelegate.TARGET_KIND, 0);
		switch (kind) {
			case ApiUseLaunchDelegate.KIND_API_BASELINE: {
				radioBaseline.setSelection(true);
				radioTarget.setSelection(false);
				radioInstall.setSelection(false);
				radioReportOnly.setSelection(false);
				break;
			}
			case ApiUseLaunchDelegate.KIND_TARGET_DEFINITION: {
				radioBaseline.setSelection(false);
				radioTarget.setSelection(true);
				radioInstall.setSelection(false);
				radioReportOnly.setSelection(false);
				break;
			}
			case ApiUseLaunchDelegate.KIND_INSTALL_PATH: {
				radioBaseline.setSelection(false);
				radioTarget.setSelection(false);
				radioInstall.setSelection(true);
				radioReportOnly.setSelection(false);
				break;
			}
			case ApiUseLaunchDelegate.KIND_HTML_ONLY: {
				radioBaseline.setSelection(false);
				radioTarget.setSelection(false);
				radioInstall.setSelection(false);
				radioReportOnly.setSelection(true);
				break;
			}
			default: {
				int itemCount = ApiUseScanTab.this.baseline.getItemCount();
				if (itemCount > 0) {
					radioBaseline.setSelection(true);
					radioTarget.setSelection(false);
				} else {
					radioBaseline.setSelection(false);
					radioTarget.setSelection(true);
					TargetPlatformHelper.getWorkspaceTargetResolved(new NullProgressMonitor());
					updateAvailableTargets();
				}
				radioInstall.setSelection(false);
				radioReportOnly.setSelection(false);
			}
		}
	}

	/**
	 * Returns <code>true</code> if the given modifier is set in the
	 * configuration
	 */
	private boolean isSpecified(int modifier, ILaunchConfiguration configuration) throws CoreException {
		int modifiers = configuration.getAttribute(ApiUseLaunchDelegate.SEARCH_MODIFIERS, 0);
		return (modifiers & modifier) > 0;
	}

	/**
	 * Restores the selected item for the given combo based on the stored value
	 * from the configuration
	 */
	private void restoreComboSelection(Combo combo, String value) {
		int idx = -1;
		if (value != null) {
			idx = combo.indexOf(value);
			if (idx > -1) {
				combo.select(idx);
			} else {
				combo.select(0);
			}
		} else {
			combo.select(0);
		}
	}

	@Override
	public void performApply(ILaunchConfigurationWorkingCopy configuration) {
		configuration.setAttribute(ApiUseLaunchDelegate.TARGET_KIND, getTargetKind());
		configuration.setAttribute(ApiUseLaunchDelegate.BASELINE_NAME, this.baseline.getText().trim());
		configuration.setAttribute(ApiUseLaunchDelegate.INSTALL_PATH, this.installLocation.getText().trim());
		configuration.setAttribute(ApiUseLaunchDelegate.TARGET_HANDLE, getTargetMemento());
		int modifiers = 0;
		modifiers = consider(this.openreport, ApiUseLaunchDelegate.DISPLAY_REPORT, modifiers);
		modifiers = consider(this.cleanhtmllocation, ApiUseLaunchDelegate.CLEAN_HTML, modifiers);
		modifiers = consider(this.cleanreportlocation, ApiUseLaunchDelegate.CLEAN_XML, modifiers);
		modifiers = consider(this.considerapi, ApiUseLaunchDelegate.MOD_API_REFERENCES, modifiers);
		modifiers = consider(this.considerinternal, ApiUseLaunchDelegate.MOD_INTERNAL_REFERENCES, modifiers);
		modifiers = consider(this.consideruse, ApiUseLaunchDelegate.MOD_ILLEGAL_USE, modifiers);
		modifiers = consider(this.createhtml, ApiUseLaunchDelegate.CREATE_HTML, modifiers);
		configuration.setAttribute(ApiUseLaunchDelegate.SEARCH_MODIFIERS, modifiers);
		String filterRoot = this.filterRoot.getText().trim();
		if (filterRoot.length() > 0) {
			IPath path = IPath.fromOSString(filterRoot);
			configuration.setAttribute(ApiUseLaunchDelegate.FILTER_ROOT, path.toPortableString());
		} else {
			configuration.removeAttribute(ApiUseLaunchDelegate.FILTER_ROOT);
		}

		IPath path = IPath.fromOSString(this.reportlocation.getText().trim());
		configuration.setAttribute(ApiUseLaunchDelegate.REPORT_PATH, path.toPortableString());
		configuration.setAttribute(ApiUseLaunchDelegate.SEARCH_SCOPE, this.searchScope.getText().trim());
		configuration.setAttribute(ApiUseLaunchDelegate.TARGET_SCOPE, this.targetScope.getText().trim());
		configuration.setAttribute(ApiUseLaunchDelegate.DESCRIPTION, this.description.getText().trim());
		if (reportTypeCombo.getSelectionIndex() == 1) {
			configuration.setAttribute(ApiUseLaunchDelegate.REPORT_TYPE, ApiUseLaunchDelegate.REPORT_KIND_CONSUMER);
		} else {
			// TODO This will likely make the config dirty
			configuration.setAttribute(ApiUseLaunchDelegate.REPORT_TYPE, ApiUseLaunchDelegate.REPORT_KIND_PRODUCER);
		}
	}

	/**
	 * Returns the memento for the selected target definition or
	 * <code>null</code> if none.
	 *
	 * @return memento or <code>null</code>
	 */
	private String getTargetMemento() {
		ITargetHandle handle = getTargetHandle();
		if (handle == null) {
			return null;
		}
		try {
			return handle.getMemento();
		} catch (CoreException e) {
			setErrorMessage(e.getMessage());
			return null;
		}
	}

	/**
	 * Returns the handle of the selected target or <code>null</code> if none.
	 *
	 * @return target handle or <code>null</code>
	 */
	private ITargetHandle getTargetHandle() {
		int index = this.targetCombo.getSelectionIndex();
		if (index >= 0) {
			return this.targetHandles[index];
		}
		return null;
	}

	private int consider(Button button, int mask, int modifiers) {
		if (button.getSelection()) {
			return modifiers | mask;
		}
		return modifiers;
	}

	@Override
	public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
		int modifiers = ApiUseLaunchDelegate.MOD_INTERNAL_REFERENCES;
		configuration.setAttribute(ApiUseLaunchDelegate.SEARCH_MODIFIERS, modifiers);
		configuration.setAttribute(ApiUseLaunchDelegate.REPORT_TYPE, ApiUseLaunchDelegate.REPORT_KIND_PRODUCER);
	}

	@Override
	public boolean isValid(ILaunchConfiguration launchConfig) {
		if (this.initializing) {
			return true;
		}
		setErrorMessage(null);

		String text = this.reportlocation.getText().trim();
		if (IApiToolsConstants.EMPTY_STRING.equals(text)) {
			setErrorMessage(Messages.ApiUseScanTab_enter_report_location);
			return false;
		}
		if (!this.considerapi.getSelection() && !this.considerinternal.getSelection() && !this.consideruse.getSelection()) {
			setErrorMessage(Messages.ApiUseScanTab_must_search_something);
			return false;
		}
		text = this.searchScope.getText().trim();
		try {
			Pattern.compile(text);
		} catch (PatternSyntaxException pse) {
			setErrorMessage(NLS.bind(Messages.ApiUseScanTab_regex_problem, pse.getPattern()));
			return false;
		}
		text = this.targetScope.getText().trim();
		try {
			Pattern.compile(text);
		} catch (PatternSyntaxException pse) {
			setErrorMessage(NLS.bind(Messages.ApiUseScanTab_regex_problem, pse.getPattern()));
			return false;
		}
		return true;
	}

	/**
	 * Handles the Browse... button being selected
	 */
	void handleFolderBrowse(Text text, String message) {
		DirectoryDialog dialog = new DirectoryDialog(getShell());
		dialog.setMessage(message);
		String loctext = text.getText().trim();
		if (loctext.length() > 0) {
			dialog.setFilterPath(loctext);
		}
		String newpath = dialog.open();
		if (newpath != null) {
			text.setText(newpath);
		}
	}
}
