/**
 * File:    TemplateWizard.java
 * Created: 10.02.2007
 *
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * University of Augsburg, Germany <www.ds-lab.org>
 *
 * 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:
 *    Christian Saad, Programming distributed Systems Lab, University of Augsburg 
 *    	- initial API and implementation
 *    Marc Blachon, Bull SAS, Grenoble, France
 *      - getting ImageFactory from factory registry.
 *******************************************************************************/

package org.eclipse.jwt.we.misc.wizards.template;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jwt.meta.model.core.CorePackage;
import org.eclipse.jwt.meta.model.core.Model;
import org.eclipse.jwt.meta.model.processes.ProcessesPackage;
import org.eclipse.jwt.we.Plugin;
import org.eclipse.jwt.we.PluginProperties;
import org.eclipse.jwt.we.commands.template.ImportTemplateCommand;
import org.eclipse.jwt.we.editors.WEEditor;
import org.eclipse.jwt.we.misc.logging.Logger;
import org.eclipse.jwt.we.misc.util.GeneralHelper;
import org.eclipse.jwt.we.misc.views.Views;
import org.eclipse.jwt.we.misc.wizards.template.exp.ExportTemplateWizardPage;
import org.eclipse.jwt.we.misc.wizards.template.imp.ImportTemplateWizardPage;
import org.eclipse.jwt.we.misc.wizards.template.select.ModeTemplateWizardPage;
import org.eclipse.jwt.we.model.view.Diagram;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;


/**
 * This is a wizard for templates.
 * 
 * @version $Id: TemplateWizard.java,v 1.7 2009-11-26 12:41:50 chsaad Exp $
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab, University
 *         of Augsburg, Germany, www.ds-lab.org
 */
public class TemplateWizard
		extends Wizard
		implements INewWizard
{

	/**
	 * A Logger.
	 */
	static final Logger logger = Logger.getLogger(TemplateWizard.class);

	/**
	 * Select import/export mode.
	 */
	protected ModeTemplateWizardPage modePage;

	/**
	 * Export template page.
	 */
	protected ExportTemplateWizardPage exportPage;

	/**
	 * Import template page.
	 */
	protected ImportTemplateWizardPage importPage;

	/**
	 * Remember the workbench during initialization.
	 */
	protected IWorkbench workbench;


	/**
	 * This just records the information.
	 * 
	 * @param workbench
	 *            The current workbench.
	 * @param selection
	 *            The current object selection.
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection)
	{
		this.workbench = workbench;
		setWindowTitle(PluginProperties.wizards_TemplateWizard_title);
		// setDefaultPageImageDescriptor(ImageFactory.createImageDescriptor(PluginProperties.editor_Wizard_icon));
		setDefaultPageImageDescriptor(Plugin.getInstance().getFactoryRegistry()
				.getImageFactory(Views.getInstance().getSelectedView())
				.createImageDescriptor(PluginProperties.editor_Wizard_icon));
	}


	/**
	 * The framework calls this to create the contents of the wizard.
	 */
	@Override
	public void addPages()
	{
		// select mode
		modePage = new ModeTemplateWizardPage("mode", workbench); //$NON-NLS-1$
		modePage.setTitle(PluginProperties.wizards_ModeTemplateWizard_title);
		addPage(modePage);

		// import page
		importPage = new ImportTemplateWizardPage("import", workbench); //$NON-NLS-1$
		importPage.setTitle(PluginProperties.wizards_ImportTemplateWizard_title);
		importPage.setDescription(PluginProperties.wizards_ImportSelect_label);
		addPage(importPage);

		// export page
		exportPage = new ExportTemplateWizardPage("export", workbench); //$NON-NLS-1$
		exportPage.setTitle(PluginProperties.wizards_ExportTemplateWizard_title);
		exportPage.setDescription(PluginProperties.wizards_ExportSelect_label);
		addPage(exportPage);
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.wizard.Wizard#canFinish()
	 */
	@Override
	public boolean canFinish()
	{
		if (modePage.isImportMode())
		{
			return ((ImportTemplateWizardPage) getPage("import")).validatePage(); //$NON-NLS-1$
		}
		else
		{
			return ((ExportTemplateWizardPage) getPage("export")).validatePage(); //$NON-NLS-1$
		}
	}


	/**
	 * Do the work after everything is specified.
	 * 
	 * @return <code>true</code>, if the wizards completes sucessfully. <code>false</code>
	 *         if an error occured or the dialog was cancelled.
	 */
	@Override
	public boolean performFinish()
	{
		if (modePage.isImportMode())
		{
			return performFinishImport();
		}
		else
		{
			return performFinishExport();
		}
	}


	/**
	 * Do the work after everything is specified.
	 * 
	 * @return <code>true</code>, if the wizards completes sucessfully. <code>false</code>
	 *         if an error occured or the dialog was cancelled.
	 */
	public boolean performFinishImport()
	{
		boolean successful = true;

		ArrayList templates = ((ImportTemplateWizardPage) getPage("import")) //$NON-NLS-1$
				.getTemplates();

		try
		{
			if (templates.size() != 0)
			{
				for (Iterator i = templates.iterator(); i.hasNext();)
				{
					URI fileUri = URI.createFileURI((String) i.next());

					ResourceSet resourceSet = new ResourceSetImpl();

					resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
							.put(WEEditor.getTemplateExtension(),
									new XMIResourceFactoryImpl());

					resourceSet.getPackageRegistry().put(CorePackage.eNS_URI,
							CorePackage.eINSTANCE);
					resourceSet.getPackageRegistry().put(ProcessesPackage.eNS_URI,
							ProcessesPackage.eINSTANCE);

					try
					{
						Model importModel = null;
						Diagram importDiagram = null;

						for (Object object : resourceSet.getResource(fileUri, true)
								.getContents())
						{
							if (object instanceof Model)
							{
								importModel = (Model) object;
							}
							else if (object instanceof Diagram)
							{
								importDiagram = (Diagram) object;
							}
						}
						// import command
						Model rootPackage = ((Model) GeneralHelper.getActiveInstance()
								.getModel());

						Diagram rootDiagram = GeneralHelper.getActiveInstance()
								.getDiagramData();

						GeneralHelper.getActiveInstance().getEditDomain()
								.getCommandStack().execute(
										new ImportTemplateCommand(rootPackage,
												rootDiagram, importModel, importDiagram));
					}
					catch (Exception e)
					{
						logger.warning("Error importing file `" + fileUri.toFileString() //$NON-NLS-1$
								+ "'.", e); //$NON-NLS-1$
						successful = false;
					}
				}
			}
		}
		catch (Exception e)
		{
			successful = false;
		}

		finishMessageImport(successful);

		return successful;
	}


	/**
	 * Do the work after everything is specified.
	 * 
	 * @return <code>true</code>, if the wizards completes sucessfully. <code>false</code>
	 *         if an error occured or the dialog was cancelled.
	 */
	@SuppressWarnings("unchecked")
	public boolean performFinishExport()
	{
		String filename = ""; //$NON-NLS-1$

		try
		{
			// get the URI of the target model file.
			filename = exportPage.getFileURI().toFileString();
			if (!filename.endsWith(WEEditor.getTemplateExtension()))
			{
				filename += "." + WEEditor.getTemplateExtension(); //$NON-NLS-1$
			}
			final File newfile = new File(filename);
			final URI fileUri = URI.createFileURI(filename);
			// if file exists, ask if it should be overwritten
			if (newfile.exists())
			{
				if (!MessageDialog.openQuestion(getShell(),
						PluginProperties.editor_QuestionOverwriteFile_title,
						PluginProperties.editor_QuestionOverwriteFile_message(newfile
								.getAbsolutePath())))
				{
					exportPage.selectFileField();
					return false;
				}
			}

			// do the work within a workspace operation.
			IRunnableWithProgress operation = new IRunnableWithProgress()
			{

				public void run(IProgressMonitor progressMonitor)
				{
					try
					{
						// create a resource set and resource
						Resource resource = (new ResourceSetImpl())
								.createResource(fileUri);

						// the elements to be exported
						Collection modelElements = exportPage.getResources();

						if (modelElements == null)
						{
							// error: no elements to be exported
							finishMessageExport(fileUri.toFileString(), false);
							return;
						}

						// find root element and add it to the resource
						for (Object object : modelElements)
						{
							if (object instanceof Model || object instanceof Diagram)
							{
								resource.getContents().add((EObject) object);
							}
						}

						// save the contents of the resource to the file system.
						Map options = new HashMap();
						options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
						resource.save(options);

						// dispose
						modelElements.clear();

						// finished
						finishMessageExport(fileUri.toFileString(), true);
					}
					catch (Exception exception)
					{
						logger.warning(exception);
						finishMessageExport(fileUri.toFileString(), false);
					}
					finally
					{
						progressMonitor.done();
					}
				}
			};

			// run the workspace operation
			getContainer().run(false, false, operation);

			return true;
		}
		catch (Exception exception)
		{
			logger.warning(exception);
			finishMessageExport(filename, false);
			return false;
		}
	}


	/**
	 * Shows a successful/failed message.
	 * 
	 * @param filename
	 *            The Template filename
	 * @param successful
	 *            State of the export process
	 */
	public void finishMessageImport(boolean successful)
	{
		if (successful)
		{
			MessageDialog.openInformation(getShell(),
					PluginProperties.wizards_Import_title,
					PluginProperties.wizards_Import_ok);
		}
		else
		{
			MessageDialog.openError(getShell(), PluginProperties.wizards_Import_title,
					PluginProperties.wizards_Import_failed);
		}
	}


	/**
	 * Shows a successful/failed message.
	 * 
	 * @param filename
	 *            The Template filename
	 * @param successful
	 *            State of the export process
	 */
	public void finishMessageExport(String filename, boolean successful)
	{
		if (successful)
		{
			MessageDialog.openInformation(getShell(),
					PluginProperties.wizards_Export_title, PluginProperties.bind(
							PluginProperties.wizards_Export_ok, filename));
		}
		else
		{
			MessageDialog.openError(getShell(), PluginProperties.wizards_Export_title,
					PluginProperties.bind(PluginProperties.wizards_Export_failed,
							filename));
		}
	}

}
