/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.internal.wizards.datatransfer;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.PlatformUI;

/**
 *	Page 1 of the base resource export-to-archive Wizard.
 *
 *	@since 3.1
 */
public class WizardArchiveFileResourceExportPage1 extends
		WizardFileSystemResourceExportPage1 {

	// widgets
	protected Button compressContentsCheckbox;

	private Button zipFormatButton;
	private Button targzFormatButton;

	// dialog store id constants
	private static final String STORE_DESTINATION_NAMES_ID = "WizardZipFileResourceExportPage1.STORE_DESTINATION_NAMES_ID"; //$NON-NLS-1$

	private static final String STORE_CREATE_STRUCTURE_ID = "WizardZipFileResourceExportPage1.STORE_CREATE_STRUCTURE_ID"; //$NON-NLS-1$

	private static final String STORE_COMPRESS_CONTENTS_ID = "WizardZipFileResourceExportPage1.STORE_COMPRESS_CONTENTS_ID"; //$NON-NLS-1$

	/**
	 *	Create an instance of this class.
	 *
	 *	@param name java.lang.String
	 */
	protected WizardArchiveFileResourceExportPage1(String name,
			IStructuredSelection selection) {
		super(name, selection);
	}

	/**
	 * Create an instance of this class
	 * @param selection the selection
	 */
	public WizardArchiveFileResourceExportPage1(IStructuredSelection selection) {
		this("zipFileExportPage1", selection); //$NON-NLS-1$
		setTitle(DataTransferMessages.ArchiveExport_exportTitle);
		setDescription(DataTransferMessages.ArchiveExport_description);
	}

	@Override
	public void createControl(Composite parent) {
		super.createControl(parent);
		PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(),
				IDataTransferHelpContextIds.ZIP_FILE_EXPORT_WIZARD_PAGE);
	}

	/**
	 *	Create the export options specification widgets.
	 *
	 */
	@Override
	protected void createOptionsGroupButtons(Group optionsGroup) {
		Font font = optionsGroup.getFont();
		optionsGroup.setLayout(new GridLayout(2, true));

		Composite left = new Composite(optionsGroup, SWT.NONE);
		left.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false));
		left.setLayout(new GridLayout(1, true));

		createFileFormatOptions(left, font);

		// compress... checkbox
		compressContentsCheckbox = new Button(left, SWT.CHECK
				| SWT.LEFT);
		compressContentsCheckbox.setText(DataTransferMessages.ZipExport_compressContents);
		compressContentsCheckbox.setFont(font);

		createResolveLinkedResources(left, font);

		Composite right = new Composite(optionsGroup, SWT.NONE);
		right.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false));
		right.setLayout(new GridLayout(1, true));

		createDirectoryStructureOptions(right, font);

		// initial setup
		createDirectoryStructureButton.setSelection(true);
		createSelectionOnlyButton.setSelection(false);
		compressContentsCheckbox.setSelection(true);
	}

	/**
	 * Create the buttons for the group that determine if the entire or
	 * selected directory structure should be created.
	 * @param optionsGroup
	 * @param font
	 */
	protected void createFileFormatOptions(Composite optionsGroup, Font font) {
		// create directory structure radios
		zipFormatButton = new Button(optionsGroup, SWT.RADIO | SWT.LEFT);
		zipFormatButton.setText(DataTransferMessages.ArchiveExport_saveInZipFormat);
		zipFormatButton.setSelection(true);
		zipFormatButton.setFont(font);

		// create directory structure radios
		targzFormatButton = new Button(optionsGroup, SWT.RADIO | SWT.LEFT);
		targzFormatButton.setText(DataTransferMessages.ArchiveExport_saveInTarFormat);
		targzFormatButton.setSelection(false);
		targzFormatButton.setFont(font);
	}

	/**
	 * Returns a boolean indicating whether the directory portion of the
	 * passed pathname is valid and available for use.
	 */
	protected boolean ensureTargetDirectoryIsValid(String fullPathname) {
		int separatorIndex = fullPathname.lastIndexOf(File.separator);

		if (separatorIndex == -1) {
			return true;
		}

		return ensureTargetIsValid(new File(fullPathname.substring(0,
				separatorIndex)));
	}

	/**
	 * Returns a boolean indicating whether the passed File handle is
	 * is valid and available for use.
	 */
	protected boolean ensureTargetFileIsValid(File targetFile) {
		if (targetFile.exists() && targetFile.isDirectory()) {
			displayErrorDialog(DataTransferMessages.ZipExport_mustBeFile);
			giveFocusToDestination();
			return false;
		}

		if (targetFile.exists()) {
			if (targetFile.canWrite()) {
				if (!queryYesNoQuestion(DataTransferMessages.ZipExport_alreadyExists)) {
					return false;
				}
			} else {
				displayErrorDialog(DataTransferMessages.ZipExport_alreadyExistsError);
				giveFocusToDestination();
				return false;
			}
		}

		return true;
	}

	/**
	 * Ensures that the target output file and its containing directory are
	 * both valid and able to be used.  Answer a boolean indicating validity.
	 */
	protected boolean ensureTargetIsValid() {
		String targetPath = getDestinationValue();

		if (!ensureTargetDirectoryIsValid(targetPath)) {
			return false;
		}

		if (!ensureTargetFileIsValid(new File(targetPath))) {
			return false;
		}

		return true;
	}

	/**
	 *  Export the passed resource and recursively export all of its child resources
	 *  (iff it's a container).  Answer a boolean indicating success.
	 */
	protected boolean executeExportOperation(ArchiveFileExportOperation op) {
		op.setCreateLeadupStructure(createDirectoryStructureButton
				.getSelection());
		op.setUseCompression(compressContentsCheckbox.getSelection());
		op.setIncludeLinkedResources(resolveLinkedResourcesCheckbox.getSelection());
		op.setUseTarFormat(targzFormatButton.getSelection());

		try {
			getContainer().run(true, true, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			displayErrorDialog(e.getTargetException());
			return false;
		}

		IStatus status = op.getStatus();
		if (!status.isOK()) {
			ErrorDialog.openError(getContainer().getShell(),
					DataTransferMessages.DataTransfer_exportProblems,
					null, // no special message
					status);
			return false;
		}

		return true;
	}

	/**
	 * The Finish button was pressed.  Try to do the required work now and answer
	 * a boolean indicating success.  If false is returned then the wizard will
	 * not close.
	 * @return boolean
	 */
	@Override
	public boolean finish() {
		List resourcesToExport = getWhiteCheckedResources();

		if (!ensureTargetIsValid()) {
			return false;
		}

		//Save dirty editors if possible but do not stop if not all are saved
		saveDirtyEditors();
		// about to invoke the operation so save our state
		saveWidgetValues();

		return executeExportOperation(new ArchiveFileExportOperation(null,
				resourcesToExport, getDestinationValue()));
	}

	/**
	 *	Answer the string to display in the receiver as the destination type
	 */
	@Override
	protected String getDestinationLabel() {
		return DataTransferMessages.ArchiveExport_destinationLabel;
	}

	/**
	 *	Answer the contents of self's destination specification widget.  If this
	 *	value does not have a suffix then add it first.
	 */
	@Override
	protected String getDestinationValue() {
		String idealSuffix = getOutputSuffix();
		String destinationText = super.getDestinationValue();

		// only append a suffix if the destination doesn't already have a . in
		// its last path segment.
		// Also prevent the user from selecting a directory.  Allowing this will
		// create a ".zip" file in the directory
		if (destinationText.length() != 0
				&& !destinationText.endsWith(File.separator)) {
			int dotIndex = destinationText.lastIndexOf('.');
			if (dotIndex != -1) {
				// the last path seperator index
				int pathSepIndex = destinationText.lastIndexOf(File.separator);
				if (pathSepIndex != -1 && dotIndex < pathSepIndex) {
					destinationText += idealSuffix;
				}
			} else {
				destinationText += idealSuffix;
			}
		}

		return destinationText;
	}

	/**
	 *	Answer the suffix that files exported from this wizard should have.
	 *	If this suffix is a file extension (which is typically the case)
	 *	then it must include the leading period character.
	 *
	 */
	protected String getOutputSuffix() {
		if(zipFormatButton.getSelection()) {
			return ".zip"; //$NON-NLS-1$
		} else if(compressContentsCheckbox.getSelection()) {
			return ".tar.gz"; //$NON-NLS-1$
		} else {
			return ".tar"; //$NON-NLS-1$
		}
	}

	/**
	 *	Open an appropriate destination browser so that the user can specify a source
	 *	to import from
	 */
	@Override
	protected void handleDestinationBrowseButtonPressed() {
		FileDialog dialog = new FileDialog(getContainer().getShell(), SWT.SAVE | SWT.SHEET);
		dialog.setFilterExtensions(new String[] { "*.zip;*.tar.gz;*.tar;*.tgz", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$
		dialog.setText(DataTransferMessages.ArchiveExport_selectDestinationTitle);
		String currentSourceString = getDestinationValue();
		int lastSeparatorIndex = currentSourceString
				.lastIndexOf(File.separator);
		if (lastSeparatorIndex != -1) {
			dialog.setFilterPath(currentSourceString.substring(0,
					lastSeparatorIndex));
		}
		String selectedFileName = dialog.open();

		if (selectedFileName != null) {
			setErrorMessage(null);
			setDestinationValue(selectedFileName);
		}
	}

	/**
	 *	Hook method for saving widget values for restoration by the next instance
	 *	of this class.
	 */
	@Override
	protected void internalSaveWidgetValues() {
		// update directory names history
		IDialogSettings settings = getDialogSettings();
		if (settings != null) {
			String[] directoryNames = settings
					.getArray(STORE_DESTINATION_NAMES_ID);
			if (directoryNames == null) {
				directoryNames = new String[0];
			}

			directoryNames = addToHistory(directoryNames, getDestinationValue());
			settings.put(STORE_DESTINATION_NAMES_ID, directoryNames);

			settings.put(STORE_CREATE_STRUCTURE_ID,
					createDirectoryStructureButton.getSelection());

			settings.put(STORE_COMPRESS_CONTENTS_ID, compressContentsCheckbox
					.getSelection());
		}
	}

	/**
	 *	Hook method for restoring widget values to the values that they held
	 *	last time this wizard was used to completion.
	 */
	@Override
	protected void restoreWidgetValues() {
		IDialogSettings settings = getDialogSettings();
		if (settings != null) {
			String[] directoryNames = settings
					.getArray(STORE_DESTINATION_NAMES_ID);
			if (directoryNames == null || directoryNames.length == 0) {
				return; // ie.- no settings stored
			}

			// destination
			setDestinationValue(directoryNames[0]);
			for (String directoryName : directoryNames) {
				addDestinationItem(directoryName);
			}

			boolean setStructure = settings
					.getBoolean(STORE_CREATE_STRUCTURE_ID);

			createDirectoryStructureButton.setSelection(setStructure);
			createSelectionOnlyButton.setSelection(!setStructure);

			compressContentsCheckbox.setSelection(settings
					.getBoolean(STORE_COMPRESS_CONTENTS_ID));
		}
	}

	@Override
	protected String destinationEmptyMessage() {
		return DataTransferMessages.ArchiveExport_destinationEmpty;
	}

	/**
	 *	Answer a boolean indicating whether the receivers destination specification
	 *	widgets currently all contain valid values.
	 */
	@Override
	protected boolean validateDestinationGroup() {
		String destinationValue = getDestinationValue();
		if (destinationValue.endsWith(".tar")) { //$NON-NLS-1$
			compressContentsCheckbox.setSelection(false);
			targzFormatButton.setSelection(true);
			zipFormatButton.setSelection(false);
		} else if (destinationValue.endsWith(".tar.gz") //$NON-NLS-1$
				|| destinationValue.endsWith(".tgz")) { //$NON-NLS-1$
			compressContentsCheckbox.setSelection(true);
			targzFormatButton.setSelection(true);
			zipFormatButton.setSelection(false);
		} else if (destinationValue.endsWith(".zip")) { //$NON-NLS-1$
			zipFormatButton.setSelection(true);
			targzFormatButton.setSelection(false);
		}

		return super.validateDestinationGroup();
	}
}
