/*
 * Copyright (c) 2006-2008 Maskat Project.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Maskat Project - initial API and implementation
 */
package org.maskat.ui.wizards.nature;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.actions.CopyFilesAndFoldersOperation;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.ContainerGenerator;
import org.eclipse.ui.internal.wizards.newresource.ResourceMessages;
import org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard;

import org.maskat.runtime.MaskatRuntimePlugin;
import org.maskat.ui.ISharedImages;
import org.maskat.ui.MaskatNature;
import org.maskat.ui.MaskatUIPlugin;
import org.maskat.ui.Messages;

public class AddMaskatNatureWizard extends Wizard implements INewWizard,
		IExecutableExtension {

	/** The wizard ID */
	public static final String WIZARD_ID = MaskatUIPlugin.PLUGIN_ID
			+ ".addMaskatNatureWizard"; //$NON-NLS-1$

	private AddMaskatNatureCreationPage mainPage;

	/** cache of newly-created project */
	private IProject project;

	/** The config element which declares this wizard. */
	private IConfigurationElement configElement;
	
	/**
	 * Creates a wizard for creating a new project resource in the workspace.
	 */
	public AddMaskatNatureWizard(ISelection selection) {
		IDialogSettings workbenchSettings = MaskatUIPlugin.getDefault()
				.getDialogSettings();
		IDialogSettings section = workbenchSettings.getSection("AddMaskatNatureWizard"); //$NON-NLS-1$
		if (section == null) {
			section = workbenchSettings.addNewSection("AddMaskatNatureWizard"); //$NON-NLS-1$
		}
		setDialogSettings(section);

		setNeedsProgressMonitor(true);
		setWindowTitle(Messages.getString("wizard.nature.windowTitle")); //$NON-NLS-1$
		setDefaultPageImageDescriptor(MaskatUIPlugin
				.getImageDescriptor(ISharedImages.IMG_WIZBAN_NEWPROJECT));
		
		this.project = (IProject)((StructuredSelection) selection).getFirstElement();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IWorkbenchWizard#init(org.ec lipse.ui.IWorkbench,
	 *      org.eclipse.jface.viewers.IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
	 *      java.lang.String, java.lang.Object)
	 */
	public void setInitializationData(IConfigurationElement config, String propertyName,
			Object data) {
		configElement = config;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.wizard.Wizard#addPages()
	 */
	public void addPages() {
		super.addPages();

		mainPage = new AddMaskatNatureCreationPage(
				this.project, new Path("/maskatFW"), true);
		
		addPage(mainPage);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.wizard.Wizard#performFinish()
	 */
	public boolean performFinish() {
		if (createNewNature() == null) {
			return false;
		}
		BasicNewProjectResourceWizard.updatePerspective(configElement);
		return true;
	}

	/**
	 * Creates a new project resource with the selected name.
	 * <p>
	 * In normal usage, this method is invoked after the user has pressed Finish
	 * on the wizard; the enablement of the Finish button implies that all
	 * controls on the pages currently contain valid values.
	 * </p>
	 * <p>
	 * Note that this wizard caches the new project once it has been
	 * successfully created; subsequent invocations of this method will answer
	 * the same project resource without attempting to create it again.
	 * </p>
	 * 
	 * @return the created project resource, or <code>null</code> if the
	 *         project was not created
	 */
	private IProjectNature createNewNature() {
		final IProject projectHandle = project;
		final IPath fwPath = mainPage.getMaskatFrameworkPath();
		final boolean copy = mainPage.shouldCopyMaskatFramework();
		
		// create the new project operation
		WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
			protected void execute(IProgressMonitor monitor) throws CoreException {
				createProject(projectHandle, monitor, fwPath, copy);
			}
		};

		// run the new project creation operation
		try {
			getContainer().run(true, true, op);
		} catch (InterruptedException e) {
			return null;
		} catch (InvocationTargetException e) {
			// ie.- one of the steps resulted in a core exception
			Throwable t = e.getTargetException();
			if (t instanceof CoreException) {
				if (((CoreException) t).getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
					MessageDialog.openError(getShell(),
							ResourceMessages.NewProject_errorMessage, NLS.bind(
									ResourceMessages.NewProject_caseVariantExistsError,
									projectHandle.getName()));
				} else {
					ErrorDialog.openError(getShell(),
							ResourceMessages.NewProject_errorMessage, null, // no
							// special
							// message
							((CoreException) t).getStatus());
				}
			} else {
				// CoreExceptions are handled above, but unexpected runtime
				// exceptions and errors may still occur.
				MaskatUIPlugin.log(new Status(IStatus.ERROR, MaskatUIPlugin.PLUGIN_ID, 0,
						t.toString(), t));
				MessageDialog.openError(getShell(),
						ResourceMessages.NewProject_errorMessage, NLS
								.bind(ResourceMessages.NewProject_internalError, t
										.getMessage()));
			}
			return null;
		}
		return MaskatNature.getNature(project);
	}

	/**
	 * Creates a project resource given the project handle and description.
	 * 
	 * @param description
	 *            the project description to create a project resource for
	 * @param projectHandle
	 *            the project handle to create a project resource for
	 * @param monitor
	 *            the progress monitor to show visual progress with
	 * 
	 * @exception CoreException
	 *                if the operation fails
	 * @exception OperationCanceledException
	 *                if the operation is canceled
	 */
	//private void createProject(IProjectDescription description, IProject projectHandle,
	private void createProject(IProject projectHandle,
			IProgressMonitor monitor, IPath frameWorkPath, boolean shouldCopy)
				throws CoreException, OperationCanceledException {
		try {
			monitor.beginTask("",3000);//$NON-NLS-1$
			/* Add Maskat nature to the created project */
			try {
				MaskatNature.addNature(projectHandle, new SubProgressMonitor(monitor, 1000));
				MaskatNature nature = MaskatNature.getNature(projectHandle);
				nature.setMaskatFrameworkPath(frameWorkPath);
				nature.getPreferenceStore().save();
			} catch (IOException e) {
				throw new CoreException(new Status(IStatus.ERROR,
						MaskatUIPlugin.PLUGIN_ID, 0, e.getMessage(), e)); 
			}
			if (monitor.isCanceled()) {
				throw new OperationCanceledException();
			}
			/* Create folder for Maskat framework resources */
			IPath destinationPath = projectHandle.getFullPath().append(frameWorkPath);
			ContainerGenerator generator = new ContainerGenerator(destinationPath);
			IContainer destination = generator.generateContainer(new SubProgressMonitor(
					monitor, 1000));
			if (monitor.isCanceled()) {
				throw new OperationCanceledException();
			}
			if (shouldCopy) {
				/* Copy Maskat framwork resources from runtime plug-in */
				File[] contents = new File(MaskatRuntimePlugin.getFrameworkBaseURL()
						.getFile()).listFiles();
				URI[] uris = new URI[contents.length];
				for (int i = 0; i < contents.length; i++) {
					uris[i] = contents[i].toURI();
				}
				CopyFilesAndFoldersOperation op = new CopyFilesAndFoldersOperation(
						getShell());
				op.copyFilesInCurrentThread(uris, destination, new SubProgressMonitor(
						monitor, 1000));
			}
		} finally {
			monitor.done();
		}
	}
}
