/*******************************************************************************
 * 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
 *******************************************************************************/
package org.eclipse.jdt.internal.ui.wizards.buildpaths;

import java.io.File;
import java.util.List;

import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.util.BidiUtils;

import org.eclipse.ui.PlatformUI;

import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.IUIConstants;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField;

public class VariableCreationDialog extends StatusDialog {

	private IDialogSettings fDialogSettings;

	private StringDialogField fNameField;
	private StatusInfo fNameStatus;

	private StringButtonDialogField fPathField;
	private StatusInfo fPathStatus;
	private SelectionButtonDialogField fDirButton;

	private CPVariableElement fElement;

	private List<CPVariableElement> fExistingNames;

	public VariableCreationDialog(Shell parent, CPVariableElement element, List<CPVariableElement> existingNames) {
		super(parent);
		if (element == null) {
			setTitle(NewWizardMessages.VariableCreationDialog_titlenew);
		} else {
			setTitle(NewWizardMessages.VariableCreationDialog_titleedit);
		}

		fDialogSettings= JavaPlugin.getDefault().getDialogSettings();

		fElement= element;

		fNameStatus= new StatusInfo();
		fPathStatus= new StatusInfo();

		NewVariableAdapter adapter= new NewVariableAdapter();
		fNameField= new StringDialogField();
		fNameField.setDialogFieldListener(adapter);
		fNameField.setLabelText(NewWizardMessages.VariableCreationDialog_name_label);

		fPathField= new StringButtonDialogField(adapter);
		fPathField.setDialogFieldListener(adapter);
		fPathField.setLabelText(NewWizardMessages.VariableCreationDialog_path_label);
		fPathField.setButtonLabel(NewWizardMessages.VariableCreationDialog_path_file_button);

		fDirButton= new SelectionButtonDialogField(SWT.PUSH);
		fDirButton.setDialogFieldListener(adapter);
		fDirButton.setLabelText(NewWizardMessages.VariableCreationDialog_path_dir_button);

		fExistingNames= existingNames;

		if (element != null) {
			fNameField.setText(element.getName());
			fPathField.setText(element.getPath().toString());
		} else {
			fNameField.setText(""); //$NON-NLS-1$
			fPathField.setText(""); //$NON-NLS-1$
		}
	}

	/*
	 * @see Windows#configureShell
	 */
	@Override
	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
		PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IJavaHelpContextIds.VARIABLE_CREATION_DIALOG);
	}


	public CPVariableElement getClasspathElement() {
		return new CPVariableElement(fNameField.getText(), new Path(fPathField.getText()));
	}

	/*
	 * @see Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	protected Control createDialogArea(Composite parent) {
		Composite composite= (Composite) super.createDialogArea(parent);

		Composite inner= new Composite(composite, SWT.NONE);
		inner.setFont(composite.getFont());

		GridLayout layout= new GridLayout();
		layout.marginWidth= 0;
		layout.marginHeight= 0;
		layout.numColumns= 4;
		inner.setLayout(layout);

		int fieldWidthHint= convertWidthInCharsToPixels(50);

		fNameField.doFillIntoGrid(inner, 2);
		LayoutUtil.setWidthHint(fNameField.getTextControl(null), fieldWidthHint);
		LayoutUtil.setHorizontalGrabbing(fNameField.getTextControl(null));

		DialogField.createEmptySpace(inner, 2);

		fPathField.doFillIntoGrid(inner, 3);
		LayoutUtil.setWidthHint(fPathField.getTextControl(null), fieldWidthHint);
		BidiUtils.applyBidiProcessing(fPathField.getTextControl(null), StructuredTextTypeHandlerFactory.FILE);

		fDirButton.doFillIntoGrid(inner, 1);

		DialogField focusField= (fElement == null) ? fNameField : fPathField;
		focusField.postSetFocusOnDialogField(parent.getDisplay());
		applyDialogFont(composite);
		return composite;
	}


	// -------- NewVariableAdapter --------

	private class NewVariableAdapter implements IDialogFieldListener, IStringButtonAdapter {

		// -------- IDialogFieldListener
		@Override
		public void dialogFieldChanged(DialogField field) {
			doFieldUpdated(field);
		}

		// -------- IStringButtonAdapter
		@Override
		public void changeControlPressed(DialogField field) {
			doChangeControlPressed(field);
		}
	}

	private void doChangeControlPressed(DialogField field) {
		if (field == fPathField) {
			IPath path= chooseExtJarFile();
			if (path != null) {
				fPathField.setText(path.toString());
			}
		}
	}

	private void doFieldUpdated(DialogField field) {
		if (field == fNameField) {
			fNameStatus= nameUpdated();
		} else if (field == fPathField) {
			fPathStatus= pathUpdated();
		} else if (field == fDirButton) {
			IPath path= chooseExtDirectory();
			if (path != null) {
				fPathField.setText(path.toString());
			}
		}
		updateStatus(StatusUtil.getMoreSevere(fPathStatus, fNameStatus));
	}

	private StatusInfo nameUpdated() {
		StatusInfo status= new StatusInfo();
		String name= fNameField.getText();
		if (name.length() == 0) {
			status.setError(NewWizardMessages.VariableCreationDialog_error_entername);
			return status;
		}
		if (name.trim().length() != name.length()) {
			status.setError(NewWizardMessages.VariableCreationDialog_error_whitespace);
		} else if (!Path.ROOT.isValidSegment(name)) {
			status.setError(NewWizardMessages.VariableCreationDialog_error_invalidname);
		} else if (nameConflict(name)) {
			status.setError(NewWizardMessages.VariableCreationDialog_error_nameexists);
		}
		return status;
	}

	private boolean nameConflict(String name) {
		if (fElement != null && fElement.getName().equals(name)) {
			return false;
		}
		for (CPVariableElement existingName : fExistingNames) {
			if (name.equals(existingName.getName())){
				return true;
			}
		}
		return false;
	}


	private StatusInfo pathUpdated() {
		StatusInfo status= new StatusInfo();

		String path= fPathField.getText();
		if (path.length() > 0) { // empty path is ok
			if (!Path.ROOT.isValidPath(path)) {
				status.setError(NewWizardMessages.VariableCreationDialog_error_invalidpath);
			} else if (!new File(path).exists()) {
				status.setWarning(NewWizardMessages.VariableCreationDialog_warning_pathnotexists);
			}
		}
		return status;
	}


	private String getInitPath() {
		String initPath= fPathField.getText();
		if (initPath.length() == 0) {
			initPath= fDialogSettings.get(IUIConstants.DIALOGSTORE_LASTEXTJAR);
			if (initPath == null) {
				initPath= ""; //$NON-NLS-1$
			}
		} else {
			IPath entryPath= new Path(initPath);
			if (ArchiveFileFilter.isArchivePath(entryPath, true)) {
				entryPath.removeLastSegments(1);
			}
			initPath= entryPath.toOSString();
		}
		return initPath;
	}


	/*
	 * Open a dialog to choose a jar from the file system
	 */
	private IPath chooseExtJarFile() {
		String initPath= getInitPath();

		FileDialog dialog= new FileDialog(getShell(), SWT.SHEET);
		dialog.setText(NewWizardMessages.VariableCreationDialog_extjardialog_text);
		dialog.setFilterExtensions(ArchiveFileFilter.ALL_ARCHIVES_FILTER_EXTENSIONS);
		dialog.setFilterPath(initPath);
		String res= dialog.open();
		if (res != null) {
			fDialogSettings.put(IUIConstants.DIALOGSTORE_LASTEXTJAR, dialog.getFilterPath());
			return Path.fromOSString(res).makeAbsolute();
		}
		return null;
	}

	private IPath chooseExtDirectory() {
		String initPath= getInitPath();

		DirectoryDialog dialog= new DirectoryDialog(getShell(), SWT.SHEET);
		dialog.setText(NewWizardMessages.VariableCreationDialog_extdirdialog_text);
		dialog.setMessage(NewWizardMessages.VariableCreationDialog_extdirdialog_message);
		dialog.setFilterPath(initPath);
		String res= dialog.open();
		if (res != null) {
			fDialogSettings.put(IUIConstants.DIALOGSTORE_LASTEXTJAR, dialog.getFilterPath());
			return Path.fromOSString(res);
		}
		return null;
	}



}
