/**
 * File:    CreationWizardTemplatePageHelper.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
 *******************************************************************************/

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

import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jwt.meta.model.core.Comment;
import org.eclipse.jwt.meta.model.core.CoreFactory;
import org.eclipse.jwt.meta.model.core.CorePackage;
import org.eclipse.jwt.meta.model.core.provider.CoreItemProviderAdapterFactory;
import org.eclipse.jwt.meta.model.data.DataFactory;
import org.eclipse.jwt.meta.model.data.DataType;
import org.eclipse.jwt.meta.model.processes.Activity;
import org.eclipse.jwt.meta.model.processes.ProcessesFactory;
import org.eclipse.jwt.meta.model.processes.ProcessesPackage;
import org.eclipse.jwt.meta.model.processes.provider.ProcessesItemProviderAdapterFactory;
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.wizards.creation.CreationWizard1;
import org.eclipse.jwt.we.misc.wizards.creation.CreationWizard2;
import org.eclipse.jwt.we.misc.wizards.template.TemplateFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;


/**
 * This is a helper class with static methods for {@link CreationWizardPageTemplate},
 * {@link CreationWizard1} and {@link CreationWizard2}.
 * 
 * @version $Id: CreationWizardTemplatePageHelper.java
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab, University
 *         of Augsburg, Germany, www.ds-lab.org
 */
public class WizardHelper
{

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


	/**
	 * Create a new GridData object with the given parameters.
	 * 
	 * @param verticalAlignment
	 *            The verticalAlignment
	 * @param horizontalAlignment
	 *            The horizontalAlignment
	 * @param grabExcessVerticalSpace
	 *            The grabExcessVerticalSpace
	 * @param grabExcessHorizontalSpace
	 *            The grabExcessHorizontalSpace
	 * @param verticalSpan
	 *            The verticalSpan
	 * @param horizontalSpan
	 *            The horizontalSpan
	 * 
	 * @return A new GridData object
	 */
	public static GridData createData(int verticalAlignment, int horizontalAlignment,
			boolean grabExcessVerticalSpace, boolean grabExcessHorizontalSpace,
			int verticalSpan, int horizontalSpan)
	{
		GridData data = new GridData();

		if (verticalAlignment != -1)
			data.verticalAlignment = verticalAlignment;
		if (horizontalAlignment != -1)
			data.horizontalAlignment = horizontalAlignment;
		if (horizontalSpan != -1)
			data.horizontalSpan = horizontalSpan;
		if (horizontalSpan != -1)
			data.verticalSpan = verticalSpan;

		data.grabExcessVerticalSpace = grabExcessVerticalSpace;
		data.grabExcessHorizontalSpace = grabExcessHorizontalSpace;

		return data;
	}


	/**
	 * Creates the template listbox and sets its properties.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return The template listbox
	 */
	public static List createListBox(Composite parent)
	{
		// the label for the template listbox
		Label listboxLabel = new Label(parent, SWT.RIGHT);
		listboxLabel.setText(PluginProperties.wizards_TemplateSelected_label);
		listboxLabel.setLayoutData(createData(GridData.FILL, GridData.FILL, false, true,
				-1, 10));
		listboxLabel.setAlignment(SWT.LEFT);

		// the listbox for the templates
		List listbox = new List(parent, SWT.SINGLE);
		listbox
				.setLayoutData(createData(GridData.FILL, GridData.FILL, true, true, -1,
						10));

		return listbox;
	}


	/**
	 * Creates the Add Button and sets its properties.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return The Add Button
	 */
	public static Button createAddButton(Composite parent)
	{
		Button addButton = new Button(parent, SWT.PUSH);

		addButton.setText(PluginProperties.wizards_Add_label);
		addButton.setEnabled(false);
		addButton.setLayoutData(createData(-1, -1, false, false, -1, 1));

		return addButton;
	}


	/**
	 * Creates the Remove Button and sets its properties.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return The Remove Button
	 */
	public static Button createRemoveButton(Composite parent)
	{
		Button removeButton = new Button(parent, SWT.PUSH);

		removeButton.setText(PluginProperties.wizards_Remove_label);
		removeButton.setEnabled(false);
		removeButton.setLayoutData(createData(-1, -1, false, false, -1, 1));

		return removeButton;
	}


	/**
	 * Creates the Remove All Button and sets its properties.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return The Remove All Button
	 */
	public static Button createRemoveAllButton(Composite parent)
	{
		Button removeallButton = new Button(parent, SWT.PUSH);

		removeallButton.setText(PluginProperties.wizards_RemoveAll_label);
		removeallButton.setEnabled(false);
		removeallButton.setLayoutData(createData(-1, -1, false, false, -1, 8));

		return removeallButton;
	}


	/**
	 * Creates the template label and the template textfield and sets their properties.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return template textfield
	 */
	public static Text createTemplateField(Composite parent)
	{
		// the label for the template
		Label templateLabel = new Label(parent, SWT.RIGHT);

		templateLabel.setText("Template:"); //$NON-NLS-1$
		templateLabel.setLayoutData(createData(-1, -1, false, false, -1, -1));

		// the templatetextfield
		Text templateField = new Text(parent, SWT.BORDER);
		templateField.setLayoutData(createData(-1, GridData.FILL, false, true, -1, 8));

		return templateField;
	}


	/**
	 * Creates the Browse Button and sets its properties.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return The Browse Button
	 */
	public static Button createBrowseButton(Composite parent)
	{
		Button browseButton = new Button(parent, SWT.PUSH);

		browseButton.setText(PluginProperties.wizards_Browse_label);
		browseButton.setLayoutData(createData(-1, -1, false, false, -1, -1));

		return browseButton;
	}


	/**
	 * Creates the tree which displays the packages and the label.
	 * 
	 * @param parent
	 *            The composite parent
	 * 
	 * @return The package tree
	 */
	public static Tree createPackageTree(Composite parent)
	{
		Label packageLabel = new Label(parent, SWT.RIGHT);
		packageLabel.setText(PluginProperties.wizards_TemplateContents_label);
		packageLabel.setLayoutData(WizardHelper.createData(GridData.FILL, GridData.FILL,
				false, true, -1, 10));
		packageLabel.setAlignment(SWT.LEFT);

		Tree packageTree = new Tree(parent, SWT.SINGLE);
		packageTree.setLayoutData(WizardHelper.createData(GridData.FILL, GridData.FILL,
				true, true, 25, 10));

		return packageTree;
	}


	/**
	 * Creates a TreeViewer and sets its providers. (May create a new AdapterFactory if
	 * none was supplied)
	 * 
	 * @param adapterfactory
	 *            The adapterfactory
	 * @param packageTree
	 *            The packageTree
	 * 
	 * @return The TreeViewer
	 */
	public static TreeViewer createPackageViewer(AdapterFactory adapterfactory,
			Tree packageTree)
	{
		TreeViewer packageViewer = new TreeViewer(packageTree);

		// unfortunately, the "official" adapterfactory may not exist at this point
		if (adapterfactory == null)
		{
			ComposedAdapterFactory caf = new ComposedAdapterFactory();
			caf.addAdapterFactory(new CoreItemProviderAdapterFactory());
			caf.addAdapterFactory(new ProcessesItemProviderAdapterFactory());
			caf.addAdapterFactory(new ResourceItemProviderAdapterFactory());
			packageViewer.setContentProvider(new AdapterFactoryContentProvider(caf));
			packageViewer.setLabelProvider(new AdapterFactoryLabelProvider(caf));
		}
		else
		{
			packageViewer.setContentProvider(new AdapterFactoryContentProvider(
					adapterfactory));
			packageViewer
					.setLabelProvider(new AdapterFactoryLabelProvider(adapterfactory));
		}

		packageViewer.addFilter(new TemplateFilter());

		return packageViewer;
	}


	/**
	 * Adds a file to the listbox and selects it. If it already exists, the existing
	 * element is selected.
	 * 
	 * @param fileName
	 *            The filename
	 * @param list
	 *            The ListBox
	 */
	public static void addListBox(Text templatefield, List list)
	{
		// the index of the new item
		int index = -1;

		// complete the file name
		String templateName = URI.createFileURI(templatefield.getText()).toFileString();

		if (!templateName.endsWith(WEEditor.getTemplateExtension()))
		{
			templateName += "." + WEEditor.getTemplateExtension(); //$NON-NLS-1$
		}

		// check if item already exists
		for (int i = 0; i < list.getItems().length; i++)
		{
			if (templateName.equals(list.getItems()[i].toString()))
			{
				index = i;
			}
		}

		// if item is new -> append to list
		if (index == -1)
		{
			list.add(templateName);
			index = list.getItems().length - 1;
		}

		// select the element and delete field
		list.select(index);
		list.notifyListeners(SWT.Selection, null);
		templatefield.setText(""); //$NON-NLS-1$
	}


	/**
	 * Removes a file from the listbox and sets the focus on a neighbour element.
	 * 
	 * @param list
	 *            The ListBox
	 */
	public static void removeListBoxItem(List list)
	{
		// the index of the selected item
		int index = list.getSelectionIndex();

		if (index != -1)
		{
			// remove the selected item
			list.remove(index);

			// select the previous item
			if (index - 1 != -1)
			{
				list.select(index - 1);
			}
			// or the first item
			else if (list.getItems().length > 0)
			{
				list.select(0);
			}
		}
		list.notifyListeners(SWT.Selection, null);
	}


	/**
	 * Removes all files from the listbox
	 * 
	 * @param list
	 *            The ListBox
	 */
	public static void removeAllListBoxItems(org.eclipse.swt.widgets.List list)
	{
		// clear list
		list.removeAll();
		list.notifyListeners(SWT.Selection, null);
	}


	/**
	 * Clears the displayed model
	 * 
	 * @param packageViewer
	 *            The packageViewer
	 * @param resourceSet
	 *            The resourceSet
	 * 
	 * @return The name of the loaded model file
	 */
	protected static void clearModelView(TreeViewer packageViewer, ResourceSet resourceSet)
	{
		resourceSet = null;
		packageViewer.setInput(null);
	}


	/**
	 * Displays the model which is selected in the listbox in the TreeViewer or replaces
	 * the model filename with an error message if an Exception occurs. If no element is
	 * selected, the display is erased.
	 * 
	 * @param listbox
	 *            The listbox
	 * @param packageViewer
	 *            The packageViewer
	 * @param resourceSet
	 *            The resourceSet
	 * @param loadedModedFile
	 *            The loadedModedFile
	 * @param modelError
	 *            The modelError
	 * 
	 * @return The name of the loaded model file
	 */
	@SuppressWarnings("unchecked")
	public static String showModelInBox(List listbox, TreeViewer packageViewer,
			ResourceSet resourceSet, String loadedModedFile, String modelError)
	{
		// The filename of the selected model (or error message)
		String modelFile = ""; //$NON-NLS-1$

		if (listbox.getSelectionIndex() != -1)
		{
			modelFile = listbox.getItem(listbox.getSelectionIndex());
		}

		// if nothing is selected or error message was selected -> clear view
		if ((listbox.getSelectionIndex() == -1) || (modelError.equals(modelFile)))
		{
			clearModelView(packageViewer, resourceSet);
			return ""; //$NON-NLS-1$
		}

		// if the selected model is already loaded -> return
		if (modelFile.equals(loadedModedFile))
		{
			return loadedModedFile;
		}
		loadedModedFile = modelFile;

		// the file URI
		URI fileUri = URI.createFileURI(modelFile);

		// create a resource set
		resourceSet = null;
		resourceSet = new ResourceSetImpl();

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

		// display model or error message
		try
		{
			XMIResource resource = (XMIResource) resourceSet.getResource(fileUri, true);

			for (Object resourceC : resource.getContents())
			{
				if (resourceC instanceof org.eclipse.jwt.meta.model.core.Package)
				{
					packageViewer.setInput(resourceC);
					break;
				}
			}
			packageViewer.expandToLevel(2);
		}
		catch (Exception e)
		{
			logger.warning("Error loading file `" + modelFile + "'.", e); //$NON-NLS-1$ //$NON-NLS-2$
			listbox.setItem(listbox.getSelectionIndex(), modelError);
			clearModelView(packageViewer, resourceSet);
			return ""; //$NON-NLS-1$
		}
		return loadedModedFile;
	}


	/**
	 * Creates the resources from the selected templates.
	 * 
	 * @param packageName
	 *            The package name
	 * @param activityName
	 *            The activity name
	 * @param templates
	 *            The list of templates
	 * 
	 * @return The template root package
	 */
	public static EObject createResources(String packageName, String activityName,
			String authorName, String versionName, boolean standardPackages,
			ArrayList templates)
	{
		// we need a root package...
		org.eclipse.jwt.meta.model.core.Model rootPackage = CoreFactory.eINSTANCE
				.createModel();
		rootPackage.setName(packageName);
		rootPackage.setAuthor(authorName);
		rootPackage.setVersion(versionName);
		rootPackage.setFileversion(GeneralHelper.getWEVersion());

		if (standardPackages)
		{
			// ...and a application package...
			org.eclipse.jwt.meta.model.core.Package applicationPackage = CoreFactory.eINSTANCE
					.createPackage();
			applicationPackage
					.setName(PluginProperties.wizards_ModelWizardApplicationPackage_std);
			rootPackage.getSubpackages().add(applicationPackage);
			if (!PluginProperties.wizards_ModelWizardApplicationComment_std.equals("")) //$NON-NLS-1$
			{
				Comment applicationComment = CoreFactory.eINSTANCE.createComment();
				applicationComment
						.setText(PluginProperties.wizards_ModelWizardApplicationComment_std);
				applicationPackage.getOwnedComment().add(applicationComment);
			}

			// ...and a role package...
			org.eclipse.jwt.meta.model.core.Package rolePackage = CoreFactory.eINSTANCE
					.createPackage();
			rolePackage.setName(PluginProperties.wizards_ModelWizardRolePackage_std);
			rootPackage.getSubpackages().add(rolePackage);
			if (!PluginProperties.wizards_ModelWizardRoleComment_std.equals("")) //$NON-NLS-1$
			{
				Comment roleComment = CoreFactory.eINSTANCE.createComment();
				roleComment.setText(PluginProperties.wizards_ModelWizardRoleComment_std);
				rolePackage.getOwnedComment().add(roleComment);
			}

			// ...and a data package...
			org.eclipse.jwt.meta.model.core.Package dataPackage = CoreFactory.eINSTANCE
					.createPackage();
			dataPackage.setName(PluginProperties.wizards_ModelWizardDataPackage_std);
			rootPackage.getSubpackages().add(dataPackage);
			if (!PluginProperties.wizards_ModelWizardDataComment_std.equals("")) //$NON-NLS-1$
			{
				Comment dataComment = CoreFactory.eINSTANCE.createComment();
				dataComment.setText(PluginProperties.wizards_ModelWizardDataComment_std);
				dataPackage.getOwnedComment().add(dataComment);
			}

			// ...and a datatypes package...
			org.eclipse.jwt.meta.model.core.Package datatypesPackage = CoreFactory.eINSTANCE
					.createPackage();
			datatypesPackage
					.setName(PluginProperties.wizards_ModelWizardDatatypesPackage_std);
			rootPackage.getSubpackages().add(datatypesPackage);
			datatypesPackage.setSuperpackage(dataPackage);

			DataFactory factory = DataFactory.eINSTANCE;
			DataType url = factory.createDataType();
			url.setName(PluginProperties.Datatypes_URL);
			url.setPackage(datatypesPackage);
			DataType dioParameter = factory.createDataType();
			dioParameter.setName(PluginProperties.Datatypes_dioParameter);
			dioParameter.setPackage(datatypesPackage);
			DataType qualifier = factory.createDataType();
			qualifier.setName(PluginProperties.Datatypes_qualifier);
			qualifier.setPackage(datatypesPackage);
			DataType searchquery = factory.createDataType();
			searchquery.setName(PluginProperties.Datatypes_searchquery);
			searchquery.setPackage(datatypesPackage);
			DataType filename = factory.createDataType();
			filename.setName(PluginProperties.Datatypes_filename);
			filename.setPackage(datatypesPackage);

			if (!PluginProperties.wizards_ModelWizardDatatypesComment_std.equals("")) //$NON-NLS-1$
			{
				Comment datatypesComment = CoreFactory.eINSTANCE.createComment();
				datatypesComment
						.setText(PluginProperties.wizards_ModelWizardDatatypesComment_std);
				datatypesPackage.getOwnedComment().add(datatypesComment);
			}
		}

		// ...and an activity
		Activity rootActivity = ProcessesFactory.eINSTANCE.createActivity();
		rootPackage.getElements().add(rootActivity);
		rootActivity.setName(activityName);

		if (!PluginProperties.wizards_ModelWizardActivityComment_std.equals("")) //$NON-NLS-1$
		{
			Comment activityComment = CoreFactory.eINSTANCE.createComment();
			activityComment
					.setText(PluginProperties.wizards_ModelWizardActivityComment_std);
			rootActivity.getOwnedComment().add(activityComment);
		}

		// import templates
		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
				{
					if (resourceSet.getResource(fileUri, true).getContents().get(0) instanceof org.eclipse.jwt.meta.model.core.Package)
					{
						org.eclipse.jwt.meta.model.core.Package importpackage = (org.eclipse.jwt.meta.model.core.Package) resourceSet
								.getResource(fileUri, true).getContents().get(0);

						(new ImportTemplateCommand(rootPackage, null, importpackage, null))
								.execute();
					}
				}
				catch (Exception e)
				{
					logger.warning("Error importing file `" + fileUri.toFileString() //$NON-NLS-1$
							+ "'.", e); //$NON-NLS-1$
				}
			}
		}

		return rootPackage;
	}


	/**
	 * Make dialog bigger and center.
	 */
	public static void resizeDialog(Shell shell)
	{
		int workbenchWidth = Plugin.getDefault().getWorkbench()
				.getActiveWorkbenchWindow().getShell().getBounds().width;
		int workbenchHeight = Plugin.getDefault().getWorkbench()
				.getActiveWorkbenchWindow().getShell().getBounds().height;
		int workbenchX = Plugin.getDefault().getWorkbench().getActiveWorkbenchWindow()
				.getShell().getBounds().x;
		int workbenchY = Plugin.getDefault().getWorkbench().getActiveWorkbenchWindow()
				.getShell().getBounds().y;
		int newDialogHeight = Math.max(shell.getSize().y, 600);
		int newDialogWidth = Math.max(shell.getSize().x, 520);
		int newDialogX = ((workbenchWidth / 2) + workbenchX) - (newDialogWidth / 2);
		int newDialogY = ((workbenchHeight / 2) + workbenchY) - (newDialogHeight / 2);

		shell.setBounds(newDialogX, newDialogY, newDialogWidth, newDialogHeight);
	}

}