package it.mice.voila.wizard.plugin;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.IDialogPage;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.osgi.framework.Bundle;

/**
 * The "New" wizard page allows setting the container for the new file as well
 * as the file name. The page will only accept file name without the extension
 * OR with the extension that matches the expected one (mpe).
 */

public class NewProjectWizardStylesPage extends WizardPage {
	private Browser helpBrowser;
	private Tree tree;
	private TreeItem selectedItem;

	/**
	 * Constructor for SampleNewWizardPage.
	 * 
	 * @param pageName
	 */
	public NewProjectWizardStylesPage() {
		super("Page1", "Style of Computing, Implementation Pattern, Refercence Stack and Samples",
				getImageDescriptor("/icons/wizard.gif"));
		setDescription(
				"This page allow you to select the MDD wizard to use by navigating thru defined Style of Computing, for each style of computing, navigate thru all defined Implementation Patterns, for each Pattern, navigate thru all defined Reference Stack, and for each reference stack, select the sample to get start on.");
	}

	public TreeItem getSelectedItem() {
		return selectedItem;
	}

	/**
	 * @see IDialogPage#createControl(Composite)
	 */
	public void createControl(Composite parent) {

		Composite masterContainer = new Composite(parent, SWT.NULL);

		masterContainer.setLayout(new FormLayout());

		Sash sash = createSash(masterContainer);
		createHelpBrowser(masterContainer, sash);
		createTree(masterContainer, sash);

		setControl(masterContainer);

		tree.setSelection(tree.getItem(0));
		setPageComplete(false);
	}

	private Sash createSash(Composite masterContainer) {
		// Create the sash first, so the other controls
		// can be attached to it.
		final Sash sash = new Sash(masterContainer, SWT.VERTICAL);
		FormData data = new FormData();
		data.top = new FormAttachment(0, 0); // Attach to top
		data.bottom = new FormAttachment(100, 0); // Attach to bottom
		data.left = new FormAttachment(32, 0); // Attach halfway across
		sash.setLayoutData(data);
		sash.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				// Reattach to the left edge, and use the x value of the event to
				// determine the offset from the left
				((FormData) sash.getLayoutData()).left = new FormAttachment(0, event.x);

				// Until the parent window does a layout, the sash will not be redrawn in
				// its new location. So, force a layout.
				sash.getParent().layout();
			}
		});
		return sash;
	}

	private void createHelpBrowser(Composite masterContainer, Sash sash) {
		helpBrowser = new Browser(masterContainer, SWT.BORDER);

		// GridData gd = new GridData(GridData.FILL_BOTH);
		// gd.minimumWidth = 400;

		FormData data = new FormData();
		data = new FormData();
		data.top = new FormAttachment(0, 0);
		data.bottom = new FormAttachment(100, 0);
		data.left = new FormAttachment(sash, 0);
		data.right = new FormAttachment(100, 0);

		helpBrowser.setLayoutData(data);
	}

	private void createTree(final Composite parent, Sash sash) {
		final List styles = fetchStyles();

		tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
		// GridData gd = new GridData(GridData.FILL_BOTH);
		// gd.minimumWidth = 200;

		FormData data = new FormData();
		data.top = new FormAttachment(0, 0);
		data.bottom = new FormAttachment(100, 0);
		data.left = new FormAttachment(0, 0);
		data.right = new FormAttachment(sash, 0);

		tree.setLayoutData(data);

		tree.setItemCount(styles.size());
		tree.addListener(SWT.SetData, new Listener() {
			public void handleEvent(Event event) {
				TreeItem item = (TreeItem) event.item;
				TreeItem parentItem = item.getParentItem();
				if (parentItem == null) {
					IConfigurationElement config = (IConfigurationElement) styles.get(tree.indexOf(item));
					item.setText(config.getAttribute("name"));
					item.setData("type", "style");
					item.setData("config", config);
					item.setImage(getImage("icons/style.gif"));
					List patterns = fetchPattern(config.getAttribute("id"));
					item.setItemCount(patterns.size());
					setExpanded(item, config);
					if (tree.indexOf(item) == 0) {
						updateHelpBrowser(config);
					}
				} else {
					IConfigurationElement parentConfig = (IConfigurationElement) parentItem.getData("config");
					if (parentItem.getData("type").equals("style")) {
						List patterns = fetchPattern(parentConfig.getAttribute("id"));
						IConfigurationElement config = (IConfigurationElement) patterns.get(parentItem.indexOf(item));
						item.setText(config.getAttribute("name"));
						item.setData("type", "pattern");
						item.setImage(getImage("icons/pattern.gif"));
						item.setData("config", config);
						List stacks = fetchStack(config.getAttribute("id"));
						item.setItemCount(stacks.size());
						setExpanded(item, config);
					} else if (parentItem.getData("type").equals("pattern")) {
						List stacks = fetchStack(parentConfig.getAttribute("id"));
						IConfigurationElement config = (IConfigurationElement) stacks.get(parentItem.indexOf(item));
						item.setText(config.getAttribute("name"));
						item.setData("type", "stack");
						item.setImage(getImage("icons/stack.gif"));
						item.setData("config", config);
						List samples = fetchSample(config.getAttribute("id"));
						item.setItemCount(samples.size());
						setExpanded(item, config);
					} else {
						List samples = fetchSample(parentConfig.getAttribute("id"));
						IConfigurationElement config = (IConfigurationElement) samples.get(parentItem.indexOf(item));
						item.setText(config.getAttribute("name"));
						item.setData("type", "sample");
						item.setImage(getImage("icons/archetype.gif"));
						item.setData("config", config);
					}
				}
			}

			private void setExpanded(TreeItem item, IConfigurationElement config) {
				if (config.getAttribute("expanded") != null && config.getAttribute("expanded").equals("true")) {
					item.setExpanded(true);
				}
			}

		});

		tree.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				TreeItem item = (TreeItem) event.item;
				// System.out.println("Selected: " + item.getText());
				IConfigurationElement config = (IConfigurationElement) item.getData("config");
				if (item.getData("type").equals("sample") && config.getAttribute("active") != null
						&& config.getAttribute("active").equals("true")) {
					setPageComplete(true);
					selectedItem = item;
					IConfigurationElement stackConfig = (IConfigurationElement) item.getParentItem().getData("config");
					((NewProjectWizard) getWizard()).getProjectPage().setBundlePrefixKey(config, stackConfig);
				} else {
					setPageComplete(false);
				}
				updateHelpBrowser(config);
			}
		});
	}

	private void updateHelpBrowser(IConfigurationElement config) {
		try {
			Bundle contribBundle = Platform.getBundle(config.getDeclaringExtension().getContributor().getName());
			URL url = contribBundle.getEntry(config.getAttribute("helpFile"));
			/*
			 * FileInputStream fis = (FileInputStream)url.getContent(); byte[] content = new
			 * byte[fis.available()]; fis.read(content); helpBrowser.setText(new
			 * String(content));
			 */

			helpBrowser.setUrl(FileLocator.toFileURL(url).toExternalForm());
		} catch (Exception e) {
			helpBrowser.setText("<h3>Help file not available for the current selection.</h3>");
		}
	}

	private Image getImage(String imageURL) {
		return getImageDescriptor(imageURL).createImage();
	}

	private static ImageDescriptor getImageDescriptor(String imageURL) {
		return ActivatorPlugin.imageDescriptorFromPlugin(ActivatorPlugin.PLUGIN_ID, imageURL);
	}

	private List fetchStyles() {
		return fetchChildren(ActivatorPlugin.PLUGIN_ID + ".computingStyle", null, null);
	}

	private List fetchPattern(String styleId) {
		return fetchChildren(ActivatorPlugin.PLUGIN_ID + ".implementationPattern", "styleId", styleId);
	}

	private List fetchStack(String patternId) {
		return fetchChildren(ActivatorPlugin.PLUGIN_ID + ".technologyStack", "patternId", patternId);
	}

	private List fetchSample(String stackId) {
		return fetchChildren(ActivatorPlugin.PLUGIN_ID + ".sampleArchetype", "stackId", stackId);
	}

	private List fetchChildren(String extensionPoint, String attributeId, String attributeValue) {
		final List children = new ArrayList();
		IExtensionRegistry registry = Platform.getExtensionRegistry();
		IExtensionPoint extpoint = registry.getExtensionPoint(extensionPoint);
		if (extpoint != null) {
			IExtension[] extensions = extpoint.getExtensions();
			for (int i = 0; i < extensions.length; i++) {
				IConfigurationElement[] config = extensions[i].getConfigurationElements();
				for (int j = 0; j < config.length; j++) {
					if (attributeId == null || config[j].getAttribute(attributeId).equals(attributeValue)) {
						children.add(config[j]);
					}
				}
			}
		}
		return children;
	}
}