/*******************************************************************************
 * Copyright (c) 2000, 2017 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
 *     Mickael Istria (Red Hat Inc.) - [263316] Specialization for content-types
 *******************************************************************************/
package org.eclipse.ui.internal.dialogs;

import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.LayoutConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
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.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.osgi.framework.FrameworkUtil;

/**
 * This class is used to prompt the user for a file name &amp; extension.
 */
public class ContentTypeFilenameAssociationDialog extends TitleAreaDialog {

	private static final String DIALOG_SETTINGS_SECTION = "ContentTypeFilenameAssociationDialog"; //$NON-NLS-1$

	private String filename = ""; //$NON-NLS-1$

	private String initialValue;

	private Text filenameField;

	private Button okButton;

	private String title;

	private String helpContextId;

	private final String headerTitle;

	private final String message2;

	private final String label;

	/**
	 * Spec type according to the input text. Can be
	 * {@link IContentType#FILE_NAME_SPEC},
	 * {@link IContentType#FILE_EXTENSION_SPEC},
	 * {@link IContentType#FILE_PATTERN_SPEC}
	 */
	private int specType;

	/**
	 * Constructs a new file extension dialog.
	 *
	 * @param parentShell   the parent shell
	 * @param title         the dialog title
	 * @param helpContextId the help context for this dialog
	 * @param headerTitle   the dialog header
	 * @param message       the dialog message
	 * @param label         the label for the "file type" field
	 * @since 3.4
	 */
	public ContentTypeFilenameAssociationDialog(Shell parentShell, String title, String helpContextId,
			String headerTitle, String message, String label) {
		super(parentShell);
		this.title = title;
		this.helpContextId = helpContextId;
		this.headerTitle = headerTitle;
		message2 = message;
		this.label = label;

		setShellStyle(getShellStyle() | SWT.SHEET);
	}

	@Override
	protected void configureShell(Shell shell) {
		super.configureShell(shell);
		shell.setText(title);
		PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, helpContextId);
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		Composite parentComposite = (Composite) super.createDialogArea(parent);

		Composite contents = new Composite(parentComposite, SWT.NONE);
		contents.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		setTitle(headerTitle);
		setMessage(message2);

		new Label(contents, SWT.LEFT).setText(label);

		filenameField = new Text(contents, SWT.SINGLE | SWT.BORDER);
		if (initialValue != null) {
			filenameField.setText(initialValue);
		}
		filenameField.addModifyListener(event -> {
			if (event.widget == filenameField) {
				filename = filenameField.getText().trim();
				okButton.setEnabled(validateFileType());
			}
		});
		filenameField.setFocus();

		Dialog.applyDialogFont(parentComposite);

		Point defaultMargins = LayoutConstants.getMargins();
		GridLayoutFactory.fillDefaults().numColumns(2).margins(defaultMargins.x, defaultMargins.y)
				.generateLayout(contents);

		return contents;
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
		okButton.setEnabled(false);
		createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
	}

	/**
	 * Validate the user input for a file type
	 */
	private boolean validateFileType() {
		// We need kernel api to validate the extension or a filename

		// check for empty name and extension
		if (filename.isEmpty()) {
			setErrorMessage(null);
			return false;
		}

		// check for empty extension if there is no name
		int index = filename.lastIndexOf('.');
		if (index == filename.length() - 1) {
			if (index == 0 || (index == 1 && filename.charAt(0) == '*')) {
				setErrorMessage(WorkbenchMessages.FileExtension_extensionEmptyMessage);
				return false;
			}
		}

		// check for characters before *
		// or no other characters
		// or next chatacter not '.'
		// or another *
		index = filename.indexOf('*');
		if (index > -1) {
			if (filename.length() == 1) {
				setErrorMessage(WorkbenchMessages.FileExtension_extensionEmptyMessage);
				return false;
			}
		}

		if (hasWildcards(filename)) {
			this.specType = IContentType.FILE_PATTERN_SPEC; // start with most general, then refine
			int extPrefix = filename.indexOf("*."); //$NON-NLS-1$
			if (extPrefix == 0) {
				String ext = filename.substring(2);
				if (!hasWildcards(ext)) {
					this.specType = IContentType.FILE_EXTENSION_SPEC;
				}
			}
		} else {
			this.specType = IContentType.FILE_NAME_SPEC;
		}
		setErrorMessage(null);
		return true;
	}

	private static boolean hasWildcards(String s) {
		return s.contains("?") || s.contains("*"); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Sets the initial value that should be prepopulated in this dialog.
	 *
	 * @param initialValue the value to be displayed to the user
	 * @since 3.4
	 */
	public void setInitialValue(String initialValue) {
		this.initialValue = initialValue;
	}

	@Override
	protected IDialogSettings getDialogBoundsSettings() {
		IDialogSettings settings = PlatformUI
				.getDialogSettingsProvider(FrameworkUtil.getBundle(ContentTypeFilenameAssociationDialog.class))
				.getDialogSettings();
		IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
		if (section == null)
			section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
		return section;
	}

	@Override
	protected boolean isResizable() {
		return true;
	}

	/**
	 * @return the text for the spec. For the case of extensions, it's only the
	 *         extension (without <code>*.</code> prefix. In other cases, it's the
	 *         whole expression.
	 */
	public String getSpecText() {
		if (this.specType == IContentType.FILE_EXTENSION_SPEC) {
			return filename.substring(2);
		}
		return filename;
	}

	/**
	 * @return the spec type according to the input text. Can be
	 *         {@link IContentType#FILE_NAME_SPEC},
	 *         {@link IContentType#FILE_EXTENSION_SPEC},
	 *         {@link IContentType#FILE_PATTERN_SPEC}
	 */
	public int getSpecType() {
		return this.specType;
	}
}
