/*******************************************************************************
 * Copyright (c) 2007, 2012 Symbian Software Limited 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:
 * Bala Torati (Symbian) - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.ui.templateengine;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.core.templateengine.TemplateCore;
import org.eclipse.cdt.core.templateengine.TemplateDescriptor;
import org.eclipse.cdt.core.templateengine.TemplateEngine;
import org.eclipse.cdt.core.templateengine.TemplateInfo;
import org.eclipse.cdt.core.templateengine.TemplateInitializationException;
import org.eclipse.cdt.core.templateengine.process.ProcessFailureException;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.templateengine.pages.UIPagesProvider;
import org.eclipse.cdt.ui.templateengine.pages.UIWizardPage;
import org.eclipse.cdt.ui.templateengine.uitree.UIElementTreeBuilderHelper;
import org.eclipse.cdt.ui.templateengine.uitree.UIElementTreeBuilderManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWizard;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.w3c.dom.Element;

/**
 * Template class is responsible for initiating GUI construction. Collecting data from GUI and
 * initiating process part of Template Engine. This is created per TemplateDescriptor basis.
 * Once The Template is created it creates a TemplateDescriptor for the XML file name given.
 *
 * @since 4.0
 */

public class Template extends TemplateCore {

	private TemplateDescriptor templateDescriptor;
	private UIElementTreeBuilderManager uiElementTreeBuilderManager;
	private UIPagesProvider uiPagesProvider;
	private Map<String, UIWizardPage> pageMap;

	public Template(TemplateInfo templateInfo) throws TemplateInitializationException {
		super(templateInfo);
		templateDescriptor = getTemplateDescriptor();
		uiElementTreeBuilderManager = new UIElementTreeBuilderManager(
				new UIElementTreeBuilderHelper(templateDescriptor, templateInfo));
		uiPagesProvider = new UIPagesProvider();
	}

	/**
	 * 1. get PropertyGroupList.
	 * 2. clear UIPage's display order Vector.
	 * 3. for each PropertyGroup create the UIElementTree.
	 * 4. Request the UIPagesProvider to generate UIPages for the Tree.
	 * 5. return the HashMap of UIPages.
	 */
	public Map<String, UIWizardPage> getUIPages() {
		if (pageMap == null) {
			pageMap = new HashMap<>();
			List<Element> rootPropertyGrouplist = templateDescriptor.getPropertyGroupList();

			uiPagesProvider.clearOrderVector();

			for (int i = 0; i < rootPropertyGrouplist.size(); i++) {
				// since the tree is constructed for a list of PropertyGroup's tree
				// root is set to null
				// before invoking createUIElementTree(...).
				uiElementTreeBuilderManager.setUIElementTreeRootNull();
				uiElementTreeBuilderManager.createUIElementTree(null, rootPropertyGrouplist.get(i));
				pageMap.putAll(uiPagesProvider.getWizardUIPages(uiElementTreeBuilderManager.getUIElementTreeRoot(),
						getValueStore()));
			}
		}

		return pageMap;
	}

	public IWizardPage[] getTemplateWizardPages(IWizardPage predatingPage, IWizardPage followingPage, IWizard wizard) {
		List<IWizardDataPage> pages = new ArrayList<>();
		//		if (predatingPage != null) {
		//			pages.add(predatingPage);
		//		}

		Map<String, UIWizardPage> templatePages = getUIPages();
		List<String> templatePagesOrderVector = getPagesOrderVector();
		if (templatePagesOrderVector.size() != 0) {
			IWizardPage prevPage = predatingPage;

			for (int i = 0; i < templatePagesOrderVector.size(); i++) {
				UIWizardPage page = templatePages.get(templatePagesOrderVector.get(i));
				pages.add(page);
				page.setPreviousPage(prevPage);
				if (i + 1 < templatePagesOrderVector.size()) {
					page.setNextPage(templatePages.get(templatePagesOrderVector.get(i + 1)));
				} else {
					page.setNextPage(followingPage);
				}
				page.setWizard(wizard);
				prevPage = page;
			}

			predatingPage = prevPage;
		}

		try {
			IWizardPage prevPage = predatingPage;
			IWizardDataPage[] extraPages = getExtraCreatedPages((IWorkbenchWizard) wizard, PlatformUI.getWorkbench(),
					null);
			for (IWizardDataPage page : extraPages) {
				pages.add(page);
				page.setPreviousPage(prevPage);

				if (prevPage instanceof IWizardDataPage) {
					((IWizardDataPage) prevPage).setNextPage(page);
				}

				page.setWizard(wizard);
				prevPage = page;
			}

			if (prevPage instanceof IWizardDataPage) {
				((IWizardDataPage) prevPage).setNextPage(followingPage);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (followingPage != null)
			followingPage.setPreviousPage(predatingPage);

		return pages.toArray(new IWizardPage[pages.size()]);
	}

	IWizardDataPage[] getExtraCreatedPages(IWorkbenchWizard wizard, IWorkbench workbench,
			IStructuredSelection selection) {
		TemplateInfo templateInfo = getTemplateInfo();
		IPagesAfterTemplateSelectionProvider extraPagesProvider = (IPagesAfterTemplateSelectionProvider) templateInfo
				.getExtraPagesProvider();
		if (extraPagesProvider != null) {
			return extraPagesProvider.createAdditionalPages(wizard, null, null);
		}
		return new IWizardDataPage[0];
	}

	/**
	 *
	 * @return List,which contains Page display order
	 */

	public List<String> getPagesOrderVector() {
		return uiPagesProvider.getOrderVector();
	}

	/**
	 * this method is for JUnit Test case excecution. return the
	 * UIElementTreeBuilderManager instance used by this Template.
	 *
	 * @return UIElementTreeBuilderManager
	 */
	public UIElementTreeBuilderManager getUIElementTreeBuilderManager() {
		return uiElementTreeBuilderManager;
	}

	/**
	 * initializeProcessBlockList() will create the ProcessBlockList,
	 * processPorcessBlockList() will invoke each process execution by assigning
	 * resources to each process (Ref. ProcessResourceManager).
	 * @param monitor
	 */
	@Override
	public IStatus[] executeTemplateProcesses(IProgressMonitor monitor, final boolean showError) {
		setDirty();
		TemplateEngine.getDefault().updateSharedDefaults(this);
		final IStatus[][] result = new IStatus[1][];
		WorkspaceModifyOperation wmo = new WorkspaceModifyOperation() {
			@Override
			protected void execute(IProgressMonitor monitor) throws org.eclipse.core.runtime.CoreException,
					java.lang.reflect.InvocationTargetException, InterruptedException {
				try {
					result[0] = getProcessHandler().processAll(monitor);
				} catch (ProcessFailureException e) {
					if (showError) {
						TemplateEngineUIUtil.showError(e.getMessage(), e.getCause());
					}
					result[0] = new IStatus[] {
							new Status(IStatus.ERROR, CUIPlugin.getPluginId(), IStatus.ERROR, e.getMessage(), e) };
				}
			}
		};
		try {
			wmo.run(monitor);
		} catch (InterruptedException ie) {
			throw new RuntimeException(ie);
		} catch (InvocationTargetException ite) {
			throw new RuntimeException(ite.getTargetException());
		}
		return result[0];
	}
}
