/*
 * 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.application;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
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.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWizard;
import org.maskat.ui.ISharedImages;
import org.maskat.ui.MaskatNature;
import org.maskat.ui.MaskatUIPlugin;
import org.maskat.ui.Messages;

public class NewMaskatApplicationWizard extends Wizard implements INewWizard {

	/** The wizard ID */
	public static final String WIZARD_ID = MaskatUIPlugin.PLUGIN_ID
			+ ".newMaskatApplicationWizard"; //$NON-NLS-1$
	
	private NewMaskatApplicationWizardPage page;
	
	private IStructuredSelection selection;
	
	/**
	 * Constructor for MaskatHtmlContainerNewWizard.
	 */
	public NewMaskatApplicationWizard() {
		super();
		setWindowTitle(Messages.getString("wizard.application.windowTitle")); //$NON-NLS-1$
		setNeedsProgressMonitor(true);
	}

	/**
	 * Adding the page to the wizard.
	 */

	public void addPages() {
		page = new NewMaskatApplicationWizardPage("createMaskatApplication", selection); //$NON-NLS-1$
		page.setTitle(Messages.getString("wizard.application.tilte")); //$NON-NLS-1$
		page.setDescription(Messages.getString("wizard.application.description")); //$NON-NLS-1$
		
		ImageDescriptor image = MaskatUIPlugin.getImageDescriptor(
				ISharedImages.IMG_WIZBAN_NEWAPPLICATION);
		
		page.setImageDescriptor(image);
		addPage(page);
	}

	/**
	 * This method is called when 'Finish' button is pressed in the wizard. We
	 * will create an operation and run it using wizard as execution context.
	 */
	public boolean performFinish() {

		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
		IResource dir = root.findMember(new Path(page.getDirectory()));
		
		MaskatNature nature = MaskatNature.getNature(dir.getProject());
		String maskatFWPath = nature.getMaskatFrameworkPath().removeTrailingSeparator().toString();
		
		final ApplicationParam param = new ApplicationParam(
				maskatFWPath,
				page.getDirectory(),
				page.getApplicationName(),
				page.getHtmlTitle(),
				page.isSelectedContainerFile(), page.getContainerFileName(),
				page.isSelectedTransitionFile(), page.getTransitionFileName(),
				page.isSelectedLayoutFile(), page.getLayoutFileName(),
				page.isSelectedEventFile(), page.getEventFileName());
				
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor) throws InvocationTargetException {
				try {
					doFinish(param, monitor);
							
				} catch (CoreException e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(),
					Messages.getString("wizard.application.errdialog.title"), //$NON-NLS-1$
					realException.getMessage());
			return false;
		}
		return true;

	}

	private class ApplicationParam {
		public String maskatFWPath;
		public String directory;
		public String applicationName;
		public String htmlTitle;
		
		public String containerFileName;
		public String transitionFileName;
		public String layoutFileName;
		public String eventFileName;
		
		public boolean selectedContainer;
		public boolean selectedTransition;
		public boolean selectedLayout;
		public boolean selectedEvent;
		
		public ApplicationParam(String path, String dir, String app, String title,
				boolean isCont, String container,
				boolean isTrans, String transition,
				boolean isLayout, String layout,
				boolean isEvent, String event) {
			maskatFWPath = path;
			directory = dir;
			applicationName = app;
			htmlTitle = title;
			containerFileName = container;
			transitionFileName = transition;
			layoutFileName = layout;
			eventFileName = event;
			selectedContainer = isCont;
			selectedTransition =isTrans;
			selectedLayout = isLayout;
			selectedEvent = isEvent;
		}
	}

	private void createFile(IFile file, String value) throws CoreException {
		InputStream stream = null;
		try {
			stream = new ByteArrayInputStream(value.getBytes("UTF-8")); //$NON-NLS-1$
			if (file.exists()) {
				throwCoreException(Messages.getString(
						"wizard.application.msg.error.alreadyexists")); //$NON-NLS-1$
			} else {
				file.create(stream, true, null);
			}		
		} catch (UnsupportedEncodingException e) {
			throwCoreException(e.getMessage());
			
		} finally {
			if (stream != null) {
				try {
					stream.close();
				} catch (IOException e) {}
			}
		}
	}
	
	private void doFinish(ApplicationParam param, IProgressMonitor monitor) throws CoreException {
		monitor.beginTask(Messages.getString("wizard.application.tasktext"), 5); //$NON-NLS-1$

		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
		IResource resource = root.findMember(new Path(param.directory));
		IContainer container = (IContainer) resource;
		IFolder folder = container.getFolder(new Path(param.applicationName));
		folder.create(false, true, null);
		monitor.worked(1);
		
		String path = param.applicationName + File.separator ;

		try {
			if (param.selectedContainer) {
				createFile(container.getFile(new Path(path + param.containerFileName)),
					replaceParamater(param, getTemplate("container.template"))); //$NON-NLS-1$
			}
			monitor.worked(1);

			if (param.selectedLayout) {
				createFile(container.getFile(new Path(path + param.layoutFileName)),
					getTemplate("layout.template")); //$NON-NLS-1$
			}
			monitor.worked(1);

			if (param.selectedTransition) {
				createFile(container.getFile(new Path(path + param.transitionFileName)),
					replaceParamater(param, getTemplate("transition.template"))); //$NON-NLS-1$
			}
			monitor.worked(1);
			
			if (param.selectedEvent) {
				createFile(container.getFile(new Path(path + param.eventFileName)),
					getTemplate("event.template")); //$NON-NLS-1$	
			}
			monitor.worked(1);

		} catch (IOException e) {
			throwCoreException(e.getMessage());
			
		}
		monitor.done();
	}
	
	private void throwCoreException(String message) throws CoreException {
		IStatus status = new Status(IStatus.ERROR, MaskatUIPlugin.PLUGIN_ID, IStatus.OK,
				message, null);
		throw new CoreException(status);
	}
	
	private String getTemplate(String templateName) throws IOException {
		InputStream in = null;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try {
			in = this.getClass().getResourceAsStream(templateName);
			BufferedReader reader = new BufferedReader(new InputStreamReader(in));
			PrintWriter pw = new PrintWriter(baos);
			
			String line = null;
			while ((line = reader.readLine()) != null) {
				pw.println(line);
			}
			pw.close();
			
		} finally {
			if (in != null) {
				in.close();
			}
		}
		return baos.toString();		
	}

	private String replaceParamater(ApplicationParam param, String value) {
		String title = param.htmlTitle.replaceAll("<", "&lt;"). //$NON-NLS-1$
			replaceAll(">", "&gt;").replaceAll("\"", "&quot;"); //$NON-NLS-1$
		
		String v = value
				.replaceAll("\\Q${title}\\E", title) //$NON-NLS-1$
				.replaceAll("\\Q${maskatFWPath}\\E", param.maskatFWPath) //$NON-NLS-1$
				.replaceAll("\\Q${layoutFileName}\\E", param.layoutFileName) //$NON-NLS-1$
				.replaceAll("\\Q${eventFileName}\\E", param.eventFileName); //$NON-NLS-1$

		return v;
	}
	
	/**
	 * We will accept the selection in the workbench to see if we can initialize
	 * from it.
	 * 
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.selection = selection;
	}
}
