/*******************************************************************************
 * Copyright (c) 2001, 2021 IBM Corporation and others.
 * All rights reserved. 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
 *	   David Schneider, david.schneider@unisys.com - [142500] WTP properties pages fonts don't follow Eclipse preferences
 *******************************************************************************/
package org.eclipse.wst.xml.ui.internal.wizards;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;
import org.eclipse.wst.common.uriresolver.internal.util.URIHelper;
import org.eclipse.wst.xml.core.internal.XMLCorePlugin;
import org.eclipse.wst.xml.core.internal.catalog.provisional.ICatalogEntry;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.util.DOMContentBuilder;
import org.eclipse.wst.xml.core.internal.contentmodel.util.NamespaceInfo;
import org.eclipse.wst.xml.core.internal.preferences.XMLCorePreferenceNames;
import org.eclipse.wst.xml.ui.internal.Logger;
import org.eclipse.wst.xml.ui.internal.dialogs.NamespaceInfoErrorHelper;
import org.eclipse.wst.xml.ui.internal.dialogs.SelectFileOrXMLCatalogIdPanel;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages;
import org.eclipse.wst.xml.ui.internal.nsedit.CommonEditNamespacesDialog;

import com.ibm.icu.text.Collator;

public class NewXMLWizard extends NewModelWizard {
	protected static final int CREATE_FROM_GRAMMAR = 0;
	protected static final int CREATE_FROM_SCRATCH = 1;

	protected static final String[] createFromRadioButtonLabel = {XMLWizardsMessages._UI_RADIO_XML_FROM_DTD_OR_SCHEMA, XMLWizardsMessages._UI_RADIO_XML_FROM_SCRATCH};

	protected static final String[] filePageFilterExtensions = {".xml"}; //$NON-NLS-1$
	protected static String[] browseGrammarFilterExtensions = {".xsd", ".dtd", ".ent", ".mod"}; //$NON-NLS-1$
	
	protected static final int OPTIONAL_ELEMENT_DEPTH_LIMIT_DEFAULT_VALUE = 2;
	
	protected static final long XML_EDITOR_FILE_SIZE_LIMIT = 26214400; // 25 mb

	protected NewFilePage newFilePage;
	/**
	 * @deprecated clients should not be allowed to change start page
	 */
	protected StartPage startPage;
	private StartPage fCreateXMLFromWizardPage;
	protected SelectGrammarFilePage selectGrammarFilePage;
	protected SelectRootElementPage selectRootElementPage;

	protected String cmDocumentErrorMessage;

	protected NewXMLGenerator generator;
	private NewXMLTemplatesWizardPage fNewXMLTemplatesWizardPage;


	public NewXMLWizard() {
		setWindowTitle(XMLWizardsMessages._UI_WIZARD_CREATE_NEW_TITLE);
		ImageDescriptor descriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_WIZBAN_GENERATEXML);
		setDefaultPageImageDescriptor(descriptor);
		generator = new NewXMLGenerator();
	}


	public NewXMLWizard(IFile file, CMDocument cmDocument) {
		this();

		generator.setGrammarURI(URIHelper.getPlatformURI(file));
		generator.setCMDocument(cmDocument);
	}


	public static void showDialog(Shell shell, IFile file, IStructuredSelection structuredSelection) {
		String[] errorInfo = new String[2];
		// (cs) the URI argument to createCMDocument needs to be a fully
		// qualified URI
		//
		CMDocument cmDocument = NewXMLGenerator.createCMDocument(URIHelper.getPlatformURI(file), errorInfo);
		if (errorInfo[0] == null) {
			NewXMLWizard wizard = new NewXMLWizard(file, cmDocument);
			wizard.init(PlatformUI.getWorkbench(), structuredSelection);
			wizard.setNeedsProgressMonitor(true);
			WizardDialog dialog = new WizardDialog(shell, wizard);
			dialog.create();
			dialog.getShell().setText(XMLWizardsMessages._UI_DIALOG_NEW_TITLE);
			dialog.setBlockOnOpen(true);
			dialog.open();
		}
		else {
			MessageDialog.openInformation(shell, errorInfo[0], errorInfo[1]);
		}
	}

	public void addPages() {
		String grammarURI = generator.getGrammarURI();
		
		// new file page
		newFilePage = new NewFilePage(fSelection);
		newFilePage.setTitle(XMLWizardsMessages._UI_WIZARD_CREATE_XML_FILE_HEADING);
		newFilePage.setDescription(XMLWizardsMessages._UI_WIZARD_CREATE_XML_FILE_EXPL);
		newFilePage.defaultName = (grammarURI != null) ? URIHelper.removeFileExtension(URIHelper.getLastSegment(grammarURI)) : "NewFile"; //$NON-NLS-1$
		Preferences preference = XMLCorePlugin.getDefault().getPluginPreferences();
		String ext = preference.getString(XMLCorePreferenceNames.DEFAULT_EXTENSION);
		newFilePage.defaultFileExtension = "." + ext; //$NON-NLS-1$
		newFilePage.filterExtensions = filePageFilterExtensions;
		addPage(newFilePage);

		if (grammarURI == null) {
			// create xml from page
			fCreateXMLFromWizardPage = new StartPage("StartPage", createFromRadioButtonLabel, new String[]{"org.eclipse.wst.sse.ui.preferences.xml.templates"}, XMLWizardsMessages.NewXMLTemplatesWizardPage_6) //$NON-NLS-1$
			{
				public void createControl(Composite parent) {
					super.createControl(parent);
				}

				public void setVisible(boolean visible) {
					super.setVisible(visible);
					getRadioButtonAtIndex(getCreateMode()).setSelection(true);
					getRadioButtonAtIndex(getCreateMode()).setFocus();

					// Set the help context for each button
					PlatformUI.getWorkbench().getHelpSystem().setHelp(fCreateXMLFromWizardPage.getRadioButtonAtIndex(0), IXMLWizardHelpContextIds.XML_NEWWIZARD_CREATEXML2_HELPID);
					PlatformUI.getWorkbench().getHelpSystem().setHelp(fCreateXMLFromWizardPage.getRadioButtonAtIndex(1), IXMLWizardHelpContextIds.XML_NEWWIZARD_CREATEXML3_HELPID);
				}
			};


			fCreateXMLFromWizardPage.setTitle(XMLWizardsMessages._UI_WIZARD_CREATE_XML_HEADING);
			fCreateXMLFromWizardPage.setDescription(XMLWizardsMessages._UI_WIZARD_CREATE_XML_EXPL);
			addPage(fCreateXMLFromWizardPage);
		}

		// selectGrammarFilePage
		selectGrammarFilePage = new SelectGrammarFilePage();
		addPage(selectGrammarFilePage);

		// select root element page
		selectRootElementPage = new SelectRootElementPage();
		selectRootElementPage.setTitle(XMLWizardsMessages._UI_WIZARD_SELECT_ROOT_HEADING);
		selectRootElementPage.setDescription(XMLWizardsMessages._UI_WIZARD_SELECT_ROOT_EXPL);
		addPage(selectRootElementPage);

		// from "scratch"
		fNewXMLTemplatesWizardPage = new NewXMLTemplatesWizardPage();
		addPage(fNewXMLTemplatesWizardPage);
	}


	public IWizardPage getStartingPage() {
		WizardPage result = null;
		if (startPage != null) {
			result = startPage;
		}
		else {
			result = newFilePage;
		}
		return result;
	}


	public int getCreateMode() {
		String grammarURI = generator.getGrammarURI();

		int result = CREATE_FROM_SCRATCH;
		if (grammarURI != null) {
			result = CREATE_FROM_GRAMMAR;
		}
		else if (fCreateXMLFromWizardPage != null) {
			int selectedIndex = fCreateXMLFromWizardPage.getSelectedRadioButtonIndex();
			if (selectedIndex != -1) {
				result = selectedIndex;
			}
		}
		return result;
	}


	public IWizardPage getNextPage(IWizardPage currentPage) {
		WizardPage nextPage = null;
		if (currentPage == startPage) {
			nextPage = newFilePage;
		}
		else if (currentPage == newFilePage) {
			if (generator.getGrammarURI() == null)
				nextPage = fCreateXMLFromWizardPage;
			else
				nextPage = selectRootElementPage;
		}
		else if (currentPage == fCreateXMLFromWizardPage) {
			int createMode = getCreateMode();
			if (createMode == CREATE_FROM_SCRATCH) {
				nextPage = fNewXMLTemplatesWizardPage;
			}
			else if (generator.getGrammarURI() == null) {
				nextPage = selectGrammarFilePage;
			}
			else {
				nextPage = selectRootElementPage;
			}
		}
		else if (currentPage == selectGrammarFilePage) {
			nextPage = selectRootElementPage;
		}
		return nextPage;
	}


	public boolean canFinish() {
		boolean result = false;

		IWizardPage currentPage = getContainer().getCurrentPage();
		// can finish on: new file page, create from & template page if creating from scratch, select root element page
		if ((currentPage == newFilePage && generator.getGrammarURI() == null) || (fCreateXMLFromWizardPage != null && fCreateXMLFromWizardPage.getSelectedRadioButtonIndex() == CREATE_FROM_SCRATCH) || (currentPage == selectRootElementPage)) {
			result = currentPage.isPageComplete();
		}
		return result;
	}


	public boolean performFinish() {
		boolean result = super.performFinish();
		// save user options for next use
		fNewXMLTemplatesWizardPage.saveLastSavedPreferences();
		
		String fileName = null;
		try {

			String[] namespaceErrors = generator.getNamespaceInfoErrors();
			if (namespaceErrors != null) {
				String title = namespaceErrors[0];
				String message = namespaceErrors[1];
				result = MessageDialog.openQuestion(getShell(), title, message);
			}

			if (result) {
				fileName = newFilePage.getFileName();
				if ((new Path(fileName)).getFileExtension() == null) {
					newFilePage.setFileName(fileName.concat(newFilePage.defaultFileExtension));
				}

				final IFile newFile = newFilePage.createNewFile();
				if (!newFile.isLinked()) {
					final String xmlFileName = newFile.getLocation().toOSString();
					final String grammarFileName = fileName;
	
					if (getContainer().getCurrentPage() == selectRootElementPage) {
	
						int limit = selectRootElementPage.getOptionalElementDepthLimit();
						generator.setOptionalElementDepthLimit(limit);
						setNeedsProgressMonitor(true);
						getContainer().run(true, false, new IRunnableWithProgress(){
							public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
								progressMonitor.beginTask(XMLWizardsMessages._UI_WIZARD_GENERATING_XML_DOCUMENT, IProgressMonitor.UNKNOWN);
								try {
									generator.createXMLDocument(newFile, xmlFileName);
								} catch (Exception exception) {
									Logger.logException("Exception completing New XML wizard " + grammarFileName, exception); //$NON-NLS-1$
								}
								progressMonitor.done();
							}
						});
					}
					else {
						// put template contents into file
						String templateString = fNewXMLTemplatesWizardPage.getTemplateString();
						generator.createTemplateXMLDocument(newFile, templateString);
					}
					newFile.refreshLocal(IResource.DEPTH_ONE, null);
				}
				IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
				BasicNewResourceWizard.selectAndReveal(newFile, workbenchWindow);
				openEditor(newFile);
			}
		}
		catch (Exception e) {
			Logger.logException("Exception completing New XML wizard " + fileName, e); //$NON-NLS-1$
		}
		return result;
	}

	public void openEditor(IFile file) {
		long length = 0;
		IPath location = file.getLocation();
		if (location != null) {
			File localFile = location.toFile();
			length = localFile.length();
		}
		if(length < XML_EDITOR_FILE_SIZE_LIMIT) {
			// Open editor on new file.
			String editorId = null;
			try {
				IEditorDescriptor editor = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getLocation().toOSString(), file.getContentDescription().getContentType());
				if (editor != null) {
					editorId = editor.getId();
				}
			}
			catch (CoreException e1) {
				// editor id could not be retrieved, so we can not open editor
				return;
			}
			IWorkbenchWindow dw = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
			try {
				if (dw != null) {
					IWorkbenchPage page = dw.getActivePage();
					if (page != null) {
						page.openEditor(new FileEditorInput(file), editorId, true);
					}
				}
			}
			catch (PartInitException e) {
				// editor can not open for some reason
				return;
			}
		}
	}


	protected String getDefaultSystemId() {
		String relativePath = "platform:/resource/" + newFilePage.getContainerFullPath().toString() + "/dummy"; //$NON-NLS-1$ //$NON-NLS-2$
		return URIHelper.getRelativeURI(generator.getGrammarURI(), relativePath);
	}


	/**
	 * SelectGrammarFilePage
	 */
	class SelectGrammarFilePage extends WizardPage {
		protected SelectFileOrXMLCatalogIdPanel panel;

		SelectGrammarFilePage() {
			super("SelectGrammarFilePage"); //$NON-NLS-1$
		}

		public void createControl(Composite parent) {
			Composite composite = new Composite(parent, SWT.NONE);
			PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTSOURCE_HELPID);
			composite.setLayout(new GridLayout());
			composite.setLayoutData(new GridData(GridData.FILL_BOTH));
			setControl(composite);

			panel = new SelectFileOrXMLCatalogIdPanel(composite);
			panel.setLayoutData(new GridData(GridData.FILL_BOTH));

			SelectFileOrXMLCatalogIdPanel.Listener listener = new SelectFileOrXMLCatalogIdPanel.Listener() {
				public void completionStateChanged() {
					updateErrorMessage();
				}
			};
			panel.setListener(listener);
			Dialog.applyDialogFont(parent);
		}

		public void setVisible(boolean visible) {
			super.setVisible(visible);
			if (visible) {
				if (getCreateMode() == CREATE_FROM_GRAMMAR) {
					setTitle(XMLWizardsMessages._UI_WIZARD_SELECT_GRAMMAR_FILE_TITLE);
					setDescription(XMLWizardsMessages._UI_WIZARD_SELECT_GRAMMAR_FILE_DESC);
					panel.setFilterExtensions(browseGrammarFilterExtensions);
				}
				generator.setGrammarURI(null);
				generator.setCMDocument(null);
				cmDocumentErrorMessage = null;
			}
			panel.setVisibleHelper(visible);
		}

		public String getURI() {
			String uri = panel.getXMLCatalogURI();
			if (uri == null) {
				IFile file = panel.getFile();
				if (file != null) {
					uri = URIHelper.getPlatformURI(file);
				}
			}
			return uri;
		}

		public boolean isPageComplete() {
			return (getURI() != null) && (getErrorMessage() == null);
		}

		public String getXMLCatalogId() {
			return panel.getXMLCatalogId();
		}

		public ICatalogEntry getXMLCatalogEntry() {
			return panel.getXMLCatalogEntry();
		}

		public String computeErrorMessage() {
			String errorMessage = null;
			String uri = getURI();
			if (uri != null) {
				if (!URIHelper.isReadableURI(uri, false)) {
					errorMessage = XMLWizardsMessages._UI_LABEL_ERROR_CATALOG_ENTRY_INVALID;
				}
			}
			return errorMessage;
		}


		public void updateErrorMessage() {
			String errorMessage = computeErrorMessage();
			setErrorMessage(errorMessage);
			setPageComplete(isPageComplete());
		}
	}


	/**
	 * SelectRootElementPage
	 */
	class SelectRootElementPage extends WizardPage implements SelectionListener {
		protected Combo combo;
		protected Button[] radioButton;
		protected PageBook pageBook;
		protected XSDOptionsPanel xsdOptionsPanel;
		protected DTDOptionsPanel dtdOptionsPanel;
		protected Text limitOptionalElementDepthTextControl;
		protected Button limitOptionalElementDepthCheckButtonControl;
		 


		SelectRootElementPage() {
			super("SelectRootElementPage"); //$NON-NLS-1$
		}

		public void createControl(Composite parent) {
			// container group
			Composite containerGroup = new Composite(parent, SWT.NONE);
			PlatformUI.getWorkbench().getHelpSystem().setHelp(containerGroup, IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT_HELPID);
			containerGroup.setLayout(new GridLayout());
			containerGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			setControl(containerGroup);

			// select root element
			Label containerLabel = new Label(containerGroup, SWT.NONE);
			containerLabel.setText(XMLWizardsMessages._UI_LABEL_ROOT_ELEMENT);
			combo = new Combo(containerGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
			combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			combo.addSelectionListener(this);

			// Options
			{
				Group group = new Group(containerGroup, SWT.NONE);
				group.setText(XMLWizardsMessages._UI_WIZARD_CONTENT_OPTIONS);

				GridLayout layout = new GridLayout();
				layout.numColumns = 1;
				layout.makeColumnsEqualWidth = true;
				layout.marginWidth = 0;
				group.setLayout(layout);
				group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

				radioButton = new Button[4];

				radioButton[0] = new Button(group, SWT.CHECK);
				radioButton[0].setText(XMLWizardsMessages._UI_WIZARD_CREATE_OPTIONAL_ATTRIBUTES);
				radioButton[0].setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
				radioButton[0].setSelection(false);
				PlatformUI.getWorkbench().getHelpSystem().setHelp(radioButton[0], IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT1_HELPID);

				radioButton[1] = new Button(group, SWT.CHECK);
				radioButton[1].setText(XMLWizardsMessages._UI_WIZARD_CREATE_OPTIONAL_ELEMENTS);
				radioButton[1].setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
				radioButton[1].setSelection(false);
				PlatformUI.getWorkbench().getHelpSystem().setHelp(radioButton[1], IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT2_HELPID);

				radioButton[1].addSelectionListener(new SelectionAdapter(){
					public void widgetSelected(SelectionEvent selectionEvent) {
						boolean enabled = radioButton[1].getSelection();
						limitOptionalElementDepthCheckButtonControl.setEnabled(enabled);
						enabled = enabled && limitOptionalElementDepthCheckButtonControl.getSelection();
						limitOptionalElementDepthTextControl.setEnabled(enabled);
					}
				});
				Composite composite = new Composite(group, SWT.NONE);
				GridLayout gridLayout = new GridLayout();
				gridLayout.marginHeight = 0;
				gridLayout.marginWidth = 0;
				gridLayout.numColumns = 2;
				gridLayout.marginLeft = 20;
				composite.setLayout(gridLayout);
				limitOptionalElementDepthCheckButtonControl = new Button(composite, SWT.CHECK);
				limitOptionalElementDepthCheckButtonControl.setText(XMLWizardsMessages._UI_WIZARD_LIMIT_OPTIONAL_ELEMENT_DEPTH);
				limitOptionalElementDepthCheckButtonControl.setEnabled(false);
				limitOptionalElementDepthCheckButtonControl.setSelection(true);
				limitOptionalElementDepthCheckButtonControl.addSelectionListener(new SelectionAdapter(){
					public void widgetSelected(SelectionEvent selectionEvent) {
						boolean enabled = limitOptionalElementDepthCheckButtonControl.getSelection();
						limitOptionalElementDepthTextControl.setEnabled(enabled);
					}
				});
				limitOptionalElementDepthTextControl = new Text(composite, SWT.BORDER);
				limitOptionalElementDepthTextControl.setText(Integer.toString(OPTIONAL_ELEMENT_DEPTH_LIMIT_DEFAULT_VALUE));
				limitOptionalElementDepthTextControl.setEnabled(false);
				GridData gridaData = new GridData();
				gridaData.widthHint = 25;
				limitOptionalElementDepthTextControl.setLayoutData(gridaData);
				limitOptionalElementDepthTextControl.addListener(SWT.Verify, new Listener() {
					public void handleEvent(Event event) {
						String string = event.text;
						char[] chars = new char[string.length()];
						string.getChars(0, chars.length, chars, 0);
						for (int i = 0; i < chars.length; i++) {
							if (!('0' <= chars[i] && chars[i] <= '9')) {
								event.doit = false;
								return;
							}
						}
					}
				});
				
				radioButton[2] = new Button(group, SWT.CHECK);
				radioButton[2].setText(XMLWizardsMessages._UI_WIZARD_CREATE_FIRST_CHOICE);
				radioButton[2].setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
				radioButton[2].setSelection(true);
				PlatformUI.getWorkbench().getHelpSystem().setHelp(radioButton[2], IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT3_HELPID);

				radioButton[3] = new Button(group, SWT.CHECK);
				radioButton[3].setText(XMLWizardsMessages._UI_WIZARD_FILL_ELEMENTS_AND_ATTRIBUTES);
				radioButton[3].setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
				radioButton[3].setSelection(true);
				PlatformUI.getWorkbench().getHelpSystem().setHelp(radioButton[3], IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT4_HELPID);
				/*
				 * radioButton = new Button[2];
				 * 
				 * radioButton[0] = new Button(group, SWT.RADIO);
				 * radioButton[0].setText(XMLWizardsMessages.getString("_UI_WIZARD_CREATE_REQUIRED"));
				 * radioButton[0].setLayoutData(new
				 * GridData(GridData.FILL_HORIZONTAL));
				 * radioButton[0].setSelection(true);
				 * WorkbenchHelp.setHelp(radioButton[0],
				 * XMLBuilderContextIds.XMLC_CREATE_REQUIRED_ONLY);
				 * 
				 * radioButton[1] = new Button(group, SWT.RADIO);
				 * radioButton[1].setText(XMLWizardsMessages.getString("_UI_WIZARD_CREATE_OPTIONAL"));
				 * radioButton[1].setLayoutData(new
				 * GridData(GridData.FILL_HORIZONTAL));
				 * WorkbenchHelp.setHelp(radioButton[1],
				 * XMLBuilderContextIds.XMLC_CREATE_REQUIRED_AND_OPTION);
				 */
			}

			// add the grammar specific generation options
			//
			{
				pageBook = new PageBook(containerGroup, SWT.NONE);
				pageBook.setLayoutData(new GridData(GridData.FILL_BOTH));
				xsdOptionsPanel = new XSDOptionsPanel(this, pageBook);
				dtdOptionsPanel = new DTDOptionsPanel(this, pageBook);
				pageBook.showPage(xsdOptionsPanel);
			}
		}

		public void widgetSelected(SelectionEvent event) {
			int index = combo.getSelectionIndex();
			String rootElementName = (index != -1) ? combo.getItem(index) : null;
			generator.setRootElementName(rootElementName);
		}

		public void widgetDefaultSelected(SelectionEvent event) {
			// do nothing
		}

		public void setVisible(boolean visible) {
			super.setVisible(visible);

			if (visible) {
				try {
					if (generator.getGrammarURI() == null) {
						generator.setGrammarURI(selectGrammarFilePage.getURI());
						generator.setXMLCatalogEntry(selectGrammarFilePage.getXMLCatalogEntry());
					}
					Assert.isNotNull(generator.getGrammarURI());

					if (generator.getCMDocument() == null) {
						final String[] errorInfo = new String[2];
						final CMDocument[] cmdocs = new CMDocument[1];
						Runnable r = new Runnable() {
							public void run() {
								cmdocs[0] = NewXMLGenerator.createCMDocument(generator.getGrammarURI(), errorInfo);
							}
						};
						org.eclipse.swt.custom.BusyIndicator.showWhile(Display.getCurrent(), r);

						generator.setCMDocument(cmdocs[0]);
						cmDocumentErrorMessage = errorInfo[1];
					}

					combo.removeAll();
					if ((generator.getCMDocument() != null) && (cmDocumentErrorMessage == null)) {
						CMNamedNodeMap nameNodeMap = generator.getCMDocument().getElements();
						List<String> nameNodeList = new ArrayList<>();

						for (int i = 0; i < nameNodeMap.getLength(); i++) {
							CMElementDeclaration cmElementDeclaration = (CMElementDeclaration) nameNodeMap.item(i);
							Object value = cmElementDeclaration.getProperty("Abstract"); //$NON-NLS-1$
							if (value != Boolean.TRUE) {
								nameNodeList.add(cmElementDeclaration.getElementName());
							}
						}

						String[] nameNodeArray = nameNodeList.toArray(new String[nameNodeList.size()]);
						if (nameNodeArray.length > 0) {
							Arrays.sort(nameNodeArray, Collator.getInstance());
						}

						String defaultRootName = (String) (generator.getCMDocument()).getProperty("http://org.eclipse.wst/cm/properties/defaultRootName"); //$NON-NLS-1$
						int defaultRootIndex = -1;
						for (int i = 0; i < nameNodeArray.length; i++) {
							String elementName = nameNodeArray[i];

							combo.add(elementName);
							if ((defaultRootName != null) && defaultRootName.equals(elementName)) {
								defaultRootIndex = i;
							}
						}

						if (nameNodeArray.length > 0) {
							defaultRootIndex = defaultRootIndex != -1 ? defaultRootIndex : 0;
							combo.select(defaultRootIndex);
							generator.setRootElementName(combo.getItem(defaultRootIndex));
						}
					}

					if (generator.getGrammarURI().endsWith("xsd")) //$NON-NLS-1$
					{
						pageBook.showPage(xsdOptionsPanel);
						generator.setDefaultSystemId(getDefaultSystemId());
						generator.createNamespaceInfoList();

						// Provide default namespace prefix if none
						for (int i = 0; i < generator.namespaceInfoList.size(); i++) {
							NamespaceInfo nsinfo = generator.namespaceInfoList.get(i);
							if (((nsinfo.prefix == null) || (nsinfo.prefix.trim().length() == 0)) && ((nsinfo.uri != null) && (nsinfo.uri.trim().length() != 0))) {
								nsinfo.prefix = getDefaultPrefix(generator.namespaceInfoList);
							}
						}
						xsdOptionsPanel.setNamespaceInfoList(generator.namespaceInfoList);
					}
					else if (generator.getGrammarURI().endsWith("dtd")) //$NON-NLS-1$
					{
						pageBook.showPage(dtdOptionsPanel);
						dtdOptionsPanel.update();
					}
				}
				catch (Exception e) {
					// XMLBuilderPlugin.getPlugin().getMsgLogger().writeCurrentThread();
				}

				/*
				 * String errorMessage = computeErrorMessage(); if
				 * (errorMessage == null) super.setVisible(visible);
				 */

				updateErrorMessage();
			}
		}

		private String getDefaultPrefix(List<NamespaceInfo> nsInfoList) {
			String defaultPrefix = "p"; //$NON-NLS-1$
			if (nsInfoList == null) {
				return defaultPrefix;
			}

			Vector<String> v = new Vector<>();
			for (int i = 0; i < nsInfoList.size(); i++) {
				NamespaceInfo nsinfo = nsInfoList.get(i);
				if (nsinfo.prefix != null) {
					v.addElement(nsinfo.prefix);
				}
			}

			if (v.contains(defaultPrefix)) {
				String s = defaultPrefix;
				for (int j = 0; v.contains(s); j++) {
					s = defaultPrefix + Integer.toString(j);
				}
				return s;
			}
			return defaultPrefix;
		}
		
		public int getOptionalElementDepthLimit() {
			int depth = -1;
			if(radioButton[1].getSelection() && limitOptionalElementDepthCheckButtonControl.getSelection()) {
				try {
					depth = Integer.parseInt(limitOptionalElementDepthTextControl.getText());
				} catch( Exception exception) {}
			}
			return depth;
		}

		public boolean isPageComplete() {
			boolean complete = ((generator.getRootElementName() != null) && (generator.getRootElementName().length() > 0)) && (getErrorMessage() == null);

			if (complete) {
				/*
				 * int buildPolicy = radioButton[0].getSelection() ?
				 * DOMContentBuilder.BUILD_ONLY_REQUIRED_CONTENT :
				 * DOMContentBuilder.BUILD_ALL_CONTENT;
				 */
				int buildPolicy = 0;
				if (radioButton[0].getSelection()) {
					buildPolicy = buildPolicy | DOMContentBuilder.BUILD_OPTIONAL_ATTRIBUTES;
				}
				if (radioButton[1].getSelection()) {
					buildPolicy = buildPolicy | DOMContentBuilder.BUILD_OPTIONAL_ELEMENTS;
				}
				if (radioButton[2].getSelection()) {
					buildPolicy = buildPolicy | DOMContentBuilder.BUILD_FIRST_CHOICE | DOMContentBuilder.BUILD_FIRST_SUBSTITUTION;
				}
				if (radioButton[3].getSelection()) {
					buildPolicy = buildPolicy | DOMContentBuilder.BUILD_TEXT_NODES;
				}

				generator.setBuildPolicy(buildPolicy);
			}

			return complete;
		}

		public String computeErrorMessage() {
			String errorMessage = null;

			if (cmDocumentErrorMessage != null) {
				errorMessage = cmDocumentErrorMessage;
			}
			else if ((generator.getRootElementName() == null) || (generator.getRootElementName().length() == 0)) {
				errorMessage = XMLWizardsMessages._ERROR_ROOT_ELEMENT_MUST_BE_SPECIFIED;
			}

			return errorMessage;
		}


		public void updateErrorMessage() {
			String errorMessage = computeErrorMessage();
			if (errorMessage == null) {
				if (xsdOptionsPanel.isVisible()) {

					errorMessage = xsdOptionsPanel.computeErrorMessage();
				}
				else if (dtdOptionsPanel.isVisible()) {
					errorMessage = dtdOptionsPanel.computeErrorMessage();
				}
			}
			setErrorMessage(errorMessage);
			setPageComplete(isPageComplete());
		}
	}

	// //////////////End SelectRootElementPage



	public static GridLayout createOptionsPanelLayout() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.marginWidth = 0;
		gridLayout.horizontalSpacing = 0;
		return gridLayout;
	}



	/**
	 * 
	 */
	class XSDOptionsPanel extends Composite {
		protected String errorMessage = null;
		protected SelectRootElementPage parentPage;
		protected CommonEditNamespacesDialog editNamespaces;
		private IPath currentPath = null;

		public XSDOptionsPanel(SelectRootElementPage parentPage, Composite parent) {
			super(parent, SWT.NONE);
			this.parentPage = parentPage;

			setLayout(createOptionsPanelLayout());
			setLayoutData(new GridData(GridData.FILL_BOTH));
		}
		
		private CommonEditNamespacesDialog getEditNamespaces() {
			if (editNamespaces == null) {
				Composite co = new Composite(this, SWT.NONE);
				co.setLayout(new GridLayout());
				String tableTitle = XMLWizardsMessages._UI_LABEL_NAMESPACE_INFORMATION;
				editNamespaces = new CommonEditNamespacesDialog(co, null, tableTitle, true, true);
				this.layout();
			}
			return editNamespaces;
		}

		public void setNamespaceInfoList(List list) {
			CommonEditNamespacesDialog editDialog = getEditNamespaces();
			
		    if (newFilePage != null) {
		      IPath newPath = newFilePage.getContainerFullPath();
		      if (newPath != null) {
		        if (!newPath.equals(currentPath)) {
	                String resourceURI = "platform:/resource" + newPath.toString() + "/dummy"; //$NON-NLS-1$ //$NON-NLS-2$
	                String resolvedPath = URIHelper.normalize(resourceURI, null, null);
	                resolvedPath = URIHelper.removeProtocol(resolvedPath);
	                
	                currentPath = new Path(resolvedPath);
	                editDialog.setResourcePath(currentPath);
		        }
		      }
		    }
		    editDialog.setNamespaceInfoList(list);
		    editDialog.updateErrorMessage(list);
		}

		public void updateErrorMessage(List namespaceInfoList) {
			NamespaceInfoErrorHelper helper = new NamespaceInfoErrorHelper();
			errorMessage = helper.computeErrorMessage(namespaceInfoList, null);
			parentPage.updateErrorMessage();
		}


		public String computeErrorMessage() {
			return errorMessage;
		}
	}


	/**
	 * 
	 */
	public class DTDOptionsPanel extends Composite implements ModifyListener {
		protected Group group;
		protected Text systemIdField;
		protected Text publicIdField;
		protected SelectRootElementPage parentPage;

		public DTDOptionsPanel(SelectRootElementPage parentPage, Composite parent) {
			super(parent, SWT.NONE);
			this.parentPage = parentPage;
			setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			setLayout(createOptionsPanelLayout());
			Group group = new Group(this, SWT.NONE);
			group.setText(XMLWizardsMessages._UI_LABEL_DOCTYPE_INFORMATION);

			GridLayout layout = new GridLayout();
			layout.numColumns = 2;
			group.setLayout(layout);
			group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			Label publicIdLabel = new Label(group, SWT.NONE);
			publicIdLabel.setText(XMLWizardsMessages._UI_LABEL_PUBLIC_ID);
			publicIdField = new Text(group, SWT.SINGLE | SWT.BORDER);
			publicIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			publicIdField.addModifyListener(this);
			PlatformUI.getWorkbench().getHelpSystem().setHelp(publicIdField, IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT5_HELPID);

			Label systemIdLabel = new Label(group, SWT.NONE);
			systemIdLabel.setText(XMLWizardsMessages._UI_LABEL_SYSTEM_ID);
			systemIdField = new Text(group, SWT.SINGLE | SWT.BORDER);
			systemIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			systemIdField.addModifyListener(this);
			PlatformUI.getWorkbench().getHelpSystem().setHelp(systemIdField, IXMLWizardHelpContextIds.XML_NEWWIZARD_SELECTROOTELEMENT6_HELPID);
		}

		public void update() {
			String thePublicId = null;
			String theSystemId = null;
			ICatalogEntry xmlCatalogEntry = generator.getXMLCatalogEntry();

			if (xmlCatalogEntry != null) {
				if (xmlCatalogEntry.getEntryType() == ICatalogEntry.ENTRY_TYPE_PUBLIC) {
					thePublicId = xmlCatalogEntry.getKey();
					theSystemId = xmlCatalogEntry.getAttributeValue(ICatalogEntry.ATTR_WEB_URL);
					if (theSystemId == null) {
						theSystemId = generator.getGrammarURI().startsWith("http:") ? generator.getGrammarURI() : URIHelper.getLastSegment(generator.getGrammarURI()); //$NON-NLS-1$
					}
				}
				else {
					theSystemId = xmlCatalogEntry.getKey();
				}
			}
			else {
				theSystemId = getDefaultSystemId();
			}

			publicIdField.setText(thePublicId != null ? thePublicId : ""); //$NON-NLS-1$
			systemIdField.setText(theSystemId != null ? theSystemId : ""); //$NON-NLS-1$
		}

		public void modifyText(ModifyEvent e) {
			generator.setSystemId(systemIdField.getText());
			generator.setPublicId(publicIdField.getText());
			parentPage.updateErrorMessage();
		}

		public String computeErrorMessage() {
			return null;
		}
	}


}
