//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// 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:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.publishing.services;

import java.io.File;
import java.io.StringWriter;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.regex.Matcher;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.epf.common.utils.FileUtil;
import org.eclipse.epf.common.xml.XSLTProcessor;
import org.eclipse.epf.library.ILibraryManager;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.configuration.ConfigurationFilter;
import org.eclipse.epf.library.edit.IFilter;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.configuration.GuidanceGroupingItemProvider;
import org.eclipse.epf.library.edit.configuration.GuidanceItemProvider;
import org.eclipse.epf.library.util.LibraryUtil;
import org.eclipse.epf.library.util.ResourceHelper;
import org.eclipse.epf.publishing.PublishingPlugin;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.TermDefinition;

/**
 * Build the glossary file foe the published configuration.
 * 
 * @author Jinhua Xi
 * @since 1.0
 */
public class GlossaryBuilder {

	public static final String GLOSSARY_BACKPATH = "./../"; //$NON-NLS-1$

	private AdapterFactory adapterFactory;

	private static final Class ITreeItemContentProviderClass = ITreeItemContentProvider.class;

	// generated glossary html file relative to the publishing dir
	private static final String GLOSSARY_HTML_FILE = "process/glossary.htm"; //$NON-NLS-1$

	private static final String GLOSSARY_INDEX_HTML_FILE = "process/glossary/index.htm"; //$NON-NLS-1$	

	private static final String GLOSSARY_NAVIG_HTML_FILE = "process/glossary/navig.htm"; //$NON-NLS-1$

	// xsl template
	private static final String GLOSSARY_XSL_FILE = "xsl/glossary.xsl"; //$NON-NLS-1$

	private static final String GLOSSARY_INDEX_XSL_FILE = "xsl/glossary_index.xsl"; //$NON-NLS-1$	

	private static final String GLOSSARY_NAVIG_XSL_FILE = "xsl/glossary_navig.xsl"; //$NON-NLS-1$

	// list to hold all glossary items.
	private GlossaryList glossaryItems = new GlossaryList();

	public GlossaryBuilder() {

	}

	public void execute(MethodConfiguration config, String pubDir,
			String title, IProgressMonitor monitor) {
		if (monitor.isCanceled()) {
			return;
		}

		glossaryItems.clear();
		IFilter configFilter = new ConfigurationFilter(config, null);
		adapterFactory = TngAdapterFactory.INSTANCE
				.getConfigurationView_AdapterFactory(configFilter);
		// iterate thru configuration to get all glossary items
		iterate(config, monitor);

		// create the glossary file
		createGlossary(pubDir, title);

	}

	/**
	 * Iterate thru the configuration tree and find all term definition elements
	 * in the configuration
	 * 
	 * @param obj
	 * @param parent
	 */
	private void iterate(Object obj, IProgressMonitor monitor) {
		if (monitor.isCanceled()) {
			return;
		}

		// Get the adapter from the factory.
		ITreeItemContentProvider treeItemContentProvider = (ITreeItemContentProvider) adapterFactory
				.adapt(obj, ITreeItemContentProviderClass);

		// Either delegate the call or return nothing.
		if (treeItemContentProvider != null) {
			Collection items = treeItemContentProvider.getChildren(obj);
			for (Iterator it = items.iterator(); it.hasNext();) {
				if (monitor.isCanceled()) {
					return;
				}

				// create bookmark
				Object itorObj = LibraryUtil.unwrap(it.next());
				if (itorObj instanceof GuidanceGroupingItemProvider) {
					iterate(itorObj, monitor);
				} else if (itorObj instanceof GuidanceItemProvider) {
					iterate(itorObj, monitor);
				} else if (itorObj instanceof TermDefinition) {
					// create a glossary entry for the TermDefinition
					// System.out.println(itorObj);
					glossaryItems.add((TermDefinition) itorObj);
				}

			}
		}
	}

	private void createGlossary(String pubDir, String title) {
		try {
			URL url = new URL(PublishingPlugin.getDefault().getInstallURL(),
					GLOSSARY_XSL_FILE);
			if (url == null) {
				System.out
						.println("Unable to get glossary xsl template " + GLOSSARY_XSL_FILE); //$NON-NLS-1$
				return;
			}

			String xsl_uri = Platform.resolve(url).getPath();
			StringBuffer xml = glossaryItems.getXml();

			File f = new File(pubDir, GLOSSARY_HTML_FILE);
			File parent = f.getParentFile();
			if (!parent.exists()) {
				parent.mkdirs();
			}

			// geenrate the html
			Properties xslParams = PublishingPlugin.getDefault().getProperties(
					"/xsl/resources.properties"); //$NON-NLS-1$
			// Properties xslParams = new Properties();
			xslParams.setProperty("title", title); //$NON-NLS-1$			
			StringWriter sw = new StringWriter();
			XSLTProcessor.transform(xsl_uri, xml.toString(), xslParams, sw);
			sw.flush();
			// String content = sw.getBuffer().toString();

			// need to decode the urls
			String content = ResourceHelper.decodeUrlsInContent(sw.getBuffer()
					.toString());
			FileUtil.writeUTF8File(f.getAbsolutePath(), fixContent(content));

			// // fix the element links
			// FileWriter output = new FileWriter(f);
			// output.write(fixContent(content));
			// output.flush();
			// output.close();
			sw.close();

			// also save the glossary navigation header html file
			url = new URL(PublishingPlugin.getDefault().getInstallURL(),
					GLOSSARY_INDEX_XSL_FILE);
			if (url == null) {
				System.out
						.println("Unable to get glossary xsl template " + GLOSSARY_INDEX_XSL_FILE); //$NON-NLS-1$
				return;
			}

			xsl_uri = Platform.resolve(url).getPath();
			f = new File(pubDir, GLOSSARY_INDEX_HTML_FILE);
			sw = new StringWriter();
			XSLTProcessor.transform(xsl_uri, xml.toString(), xslParams, sw);
			sw.flush();

			FileUtil.writeUTF8File(f.getAbsolutePath(), sw.toString());

			sw.close();

			// also save the glossary navigation header html file
			url = new URL(PublishingPlugin.getDefault().getInstallURL(),
					GLOSSARY_NAVIG_XSL_FILE);
			if (url == null) {
				System.out
						.println("Unable to get glossary xsl template " + GLOSSARY_NAVIG_XSL_FILE); //$NON-NLS-1$
				return;
			}

			xsl_uri = Platform.resolve(url).getPath();
			f = new File(pubDir, GLOSSARY_NAVIG_HTML_FILE);
			sw = new StringWriter();
			XSLTProcessor.transform(xsl_uri, xml.toString(), xslParams, sw);
			sw.flush();

			FileUtil.writeUTF8File(f.getAbsolutePath(), sw.toString());

			sw.close();

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private String fixContent(String source) {
		StringBuffer sb = new StringBuffer();
		Matcher m = ResourceHelper.p_link_ref.matcher(source);

		while (m.find()) {
			String urltext = m.group(1);
			String linkedText = m.group(2);

			urltext = fixUrlText(urltext);

			// update the url text
			String text = "<a " + urltext + ">" + linkedText + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

			m.appendReplacement(sb, text);
		}

		m.appendTail(sb);
		return sb.toString();
	}

	private String fixUrlText(String urltext) {
		String guid = ResourceHelper.getGuidFromUrl(urltext);
		if (guid == null) {
			return urltext;
		}

		ILibraryManager manager = LibraryService.getInstance()
				.getCurrentLibraryManager();
		MethodElement e = manager != null ? manager.getMethodElement(guid)
				: null;
		if (e == null) {
			return urltext;
		}

		// if the element is a TermDefinition, use the bookmark in the file
		// otherwise, find the path to the element
		String href = ""; //$NON-NLS-1$
		if (e instanceof TermDefinition) {
			href = "#" + e.getName(); //$NON-NLS-1$
		} else {
			// one level back
			href = "../" + ResourceHelper.getElementPath(e).replace(File.separatorChar, '/') + ResourceHelper.getFileName(e, ".html"); //$NON-NLS-1$ //$NON-NLS-2$
		}
		StringBuffer sb = new StringBuffer();
		Matcher m = ResourceHelper.p_link_href_picker
				.matcher(" " + urltext + " "); //$NON-NLS-1$ //$NON-NLS-2$
		if (m.find()) {
			m.appendReplacement(sb, " href=\"" + href + "\" "); //$NON-NLS-1$ //$NON-NLS-2$
			m.appendTail(sb);

			return sb.toString();
		}

		return urltext;
	}
}
