//------------------------------------------------------------------------------
// 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.net.URL;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.epf.common.utils.FileUtil;
import org.eclipse.epf.common.utils.StrUtil;
import org.eclipse.epf.library.configuration.ElementRealizer;
import org.eclipse.epf.library.layout.ElementLayoutManager;
import org.eclipse.epf.library.layout.HtmlBuilder;
import org.eclipse.epf.library.layout.LayoutResources;
import org.eclipse.epf.library.layout.util.XmlElement;
import org.eclipse.epf.publishing.PublishingPlugin;
import org.eclipse.epf.publishing.PublishingResources;
import org.eclipse.epf.publishing.layout.Bookmark;
import org.eclipse.epf.publishing.layout.BookmarkList;
import org.eclipse.epf.publishing.services.index.DefinitionObject;
import org.eclipse.epf.publishing.services.index.KeyWordIndexHelper;
import org.eclipse.epf.publishing.util.PublishingUtil;


/**
 * Manages the publishing of a Configuration.
 * 
 * @author Jinhua Xi
 * @since 1.0
 */
public class PublishManager extends AbstractPublishManager {

	protected static final String DOC_ROOT = "docroot/"; //$NON-NLS-1$;

	public static final String NO_APPLET_DIRECTORY = "noapplet"; //$NON-NLS-1$

	// public static final String BOOKMARK_SUFFIX = ".bkm"; //$NON-NLS-1$
	public static final String BOOKMARK_SUFFIX_XML = ".xml"; //$NON-NLS-1$

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

	public static final String SPACE_REPLACEMENT = "_"; //$NON-NLS-1$

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

	// public static final String DEFAULT_BOOKMARK_CFG_NAME =
	// "DefaultBookmark.cfg"; //$NON-NLS-1$
	public static final String PUBLISHED_BOOKMARKS_CFG_NAME = "PublishedBookmarks.xml"; //$NON-NLS-1$

	public static final String PUBLISHED_BOOKMARKS_DELIMITER = "*"; //$NON-NLS-1$

	protected static final String BOOKMARK_XSL_FILE = "xsl/bookmark.xsl"; //$NON-NLS-1$

	protected static final String BOOKMARKS_XSL_FILE = "xsl/PublishedBookmarks.xsl"; //$NON-NLS-1$

	protected static final String INDEX_XSL_FILE = "xsl/index.xsl"; //$NON-NLS-1$

	protected static final String TOPNAV_XSL_FILE = "xsl/topnav.xsl"; //$NON-NLS-1$

	protected static final String KEYWORD_DEF_FILE = "keywordindexdef.txt"; //$NON-NLS-1$

	protected static final String PUBLISHING_REPORT_XSL_FILE = "xsl/PublishingReport.xsl"; //$NON-NLS-1$

	protected static final String PUBLISHING_REPORT_HTML_FILE = "PublishingReport.html"; //$NON-NLS-1$

	//AbstractViewBuilder viewBuilder;

	//private boolean debug = false;

	//private boolean sucess = false;

	public PublishManager(/*AbstractViewBuilder viewBuilder*/) {
//		this.viewBuilder = viewBuilder;
//		this.debug = PublishingPlugin.getDefault().isDebugging();
	}

	protected AbstractViewBuilder createViewBuilder() {
		boolean validateExternalLinks = (options != null)
				&& options.checkExtLinks;

		PublishingContentValidator validator = null;
		ElementRealizer realizer = null;
		if ((options != null) && options.publishProcess) {
			validator = new ProcessPublishingContentValidator(pubDir,
					validateExternalLinks);
			realizer = new ProcessPublishingElementRealizer(config, 
					(ProcessPublishingContentValidator)validator);
		} else {
			validator = new PublishingContentValidator(pubDir,
					validateExternalLinks);
			realizer = new PublishingElementRealizer(config, validator);
		}

		validator.setShowBrokenLinks(options.convertBrokenLinks == false);
		validator.setShowExtraInfoForDescriptors(options.showExtraDescriptorInfo);
		
		ElementLayoutManager layoutMgr = new ElementLayoutManager(config,
				pubDir, validator, true);
		layoutMgr.setElementRealizer(realizer);
		HtmlBuilder builder = new HtmlBuilder(layoutMgr);

		return new ConfigurationViewBuilder(builder, options);
	}
	
	protected void prePublish(IProgressMonitor monitor) throws Exception {
		
		//fixOptions(options);

		monitor.subTask(PublishingResources.initializingDirTask_name); //$NON-NLS-1$

		// make sure the publish directory is created
		File f = new File(viewBuilder.getHtmlBuilder().getPublishDir());
		if (!f.exists()) {
			f.mkdirs();
		}

		// copy the configuration files
		monitor.subTask(PublishingResources.copyingFilesTask_name); //$NON-NLS-1$
		copyDocRootFiles();	
		
		// copy localized files
		copyLocalizedFiles();

		// copy user customized files last
		copyCustomizedFiles();
	}
	
	protected void doPublish(IProgressMonitor monitor) throws Exception {
		// don't copy all the content resources
		// let the system scan the content and copy only the required
		// resource
		viewBuilder.getHtmlBuilder().enableContentScan(true);
		viewBuilder.getHtmlBuilder().enableTreeBrowser(true);

		// generate bookmarks and published the contents as needed
		monitor.subTask(PublishingResources.generatingBookmarksTask_name); //$NON-NLS-1$
		generateBookmarks(monitor);

		// write out the index.htm and topnav.htm files
		writeIndexAndTopNavHtml();
		
		String title = options == null ? "" : options.getTitle(); //$NON-NLS-1$

		if (monitor.isCanceled()) {
			return;
		}

		// creating glossary
		if (options == null || options.isGenerateGlossary()) {
			monitor.subTask(PublishingResources.generatingGlossaryTask_name); //$NON-NLS-1$
			new GlossaryBuilder().execute(config, pubDir, title,
					monitor);
		}

		if (monitor.isCanceled()) {
			return;
		}

		// creating content index
		if (options == null || options.isGenerateIndex()) {
			monitor
					.subTask(PublishingResources.generatingBookmarkIndexTask_name); //$NON-NLS-1$
			// new IndexBuilder().execute(config, publishDir, monitor);
			generateBookmarkIndex(pubDir, title, monitor);
		}

//		if (monitor.isCanceled()) {
//			return;
//		}
//
//		// enable searching
//		if (options == null || options.generateSearchDB) {
//			if ( getAppletSearchPath() != null ) {
//				// generating the search index
//				monitor
//						.subTask(PublishingResources
//								.getString("Publishing.generatingSearchIndexTask.name")); //$NON-NLS-1$
//				IndexManager.createIndex(pubDir, monitor);
//			}
//		}
	}
	
	protected void postPublish(IProgressMonitor monitor) throws Exception {
		// finally, generate a report
		getPublishReportUrl();		
	}
	
	

	private void generateBookmarks(IProgressMonitor monitor) {

		java.util.List bookmarks = viewBuilder.buildViews(monitor);
		Bookmark defaultView = viewBuilder.getDefaultView();

		if (monitor.isCanceled()) {
			return;
		}

		// 3. finally, write the published bookmarks file
		writePublishedBookmarks(bookmarks, defaultView);	
	}

	public String getPublishedUrl() {
		if (sucess) {
			String url = getIndexFilePath();
			File f = new File(url);
			if (f.exists()) {
				return url;
			}
		}

		return null;
	}

	protected void copyDocRootFiles() throws Exception {

			URL plugin_url = PublishingPlugin.getDefault().getInstallURL();
			URL url = new URL(plugin_url, DOC_ROOT);
			String fromPath = Platform.resolve(url).getPath();

			// folders that apply to all
			// NOTE: applet images should always be included since it's used in
			// Atlantic configuration
			// applet/help.htm is used in RSA to check character encoding, so
			// need to include this file
			// RATLC00384000 - Process Advisor: FileNotFoundException in RSA log
			// when indexing start on a non-applet published site
			String includes = "*.*, process/**, images/**, index/**, scripts/**, stylesheets/**"; //$NON-NLS-1$

			String excludes = ""; //$NON-NLS-1$

			// based on the selection, copy the other folders
			if (options.useDefaultTreeBrowser) {
				includes += ", noapplet/**"; //$NON-NLS-1$
			}

			//String publishDir = viewBuilder.getHtmlBuilder().getPublishDir();

			LayoutResources.copyDir(fromPath, pubDir, includes, excludes);

	}

	protected void copyCustomizedFiles() throws Exception {
		if (options.bannerImage != null && options.bannerImage.length() > 0) {
			FileUtil.copyFile(options.bannerImage, pubDir + "images"); //$NON-NLS-1$
			options.bannerImage = FileUtil.getFileName(options.bannerImage);
		} else {
			options.bannerImage = "banner.gif"; //$NON-NLS-1$
		}

		if (options.aboutHTML != null && options.aboutHTML.length() > 0) {
			FileUtil.copyFile(options.aboutHTML, pubDir + "about.htm"); //$NON-NLS-1$
		}
	}
	
	
	protected void copyLocalizedFiles() throws Exception {
	
			// copy scripts, rename the localse specific name to the default
			// name
			PublishingPlugin.getDefault().copyLocalizedFiles(
					DOC_ROOT + "scripts/", new File(pubDir, "scripts/"), true, false); //$NON-NLS-1$ //$NON-NLS-2$

			PublishingPlugin.getDefault().copyLocalizedFiles(
					DOC_ROOT + "images/", new File(pubDir, "images/"), true, false); //$NON-NLS-1$ //$NON-NLS-2$
			
			PublishingPlugin.getDefault().copyLocalizedFiles(
					DOC_ROOT, new File(pubDir, "/"), false, false); //$NON-NLS-1$ //$NON-NLS-2$


			if (options.useDefaultTreeBrowser) {
				// copy the applet html files, rename locale specific names
				PublishingPlugin
						.getDefault()
						.copyLocalizedFiles(
								DOC_ROOT + "noapplet/", new File(pubDir, "noapplet/"), false, false); //$NON-NLS-1$ //$NON-NLS-2$
			}

	}

	protected String makeBookmarkFileName(String bookmarkName) {
		return bookmarkName.replace(SPACE_STRING.charAt(0), SPACE_REPLACEMENT
				.charAt(0))
				+ BOOKMARK_SUFFIX_XML;
	}


	private String writeBookmark(Bookmark b) {

		// get the bookmark name from the bookmark url
		String bookmarkFileName = makeBookmarkFileName(StrUtil
				.makeValidFileName(b.getPresentationName()));
		XmlElement xml = b.getXmlElement();

		String buffer = PublishingUtil.getHtml(xml, BOOKMARK_XSL_FILE);
		if (buffer != null) {
			String htmlPath = getBookmarkHtmlPath(bookmarkFileName);
			FileUtil.writeUTF8File(htmlPath, buffer.toString());
		}

		return bookmarkFileName;
	}

	protected void writePublishedBookmarks(List bookmarks, Bookmark defaultView) {
		
		// first write xml for each individual view 
		BookmarkList list = new BookmarkList();

		if ((defaultView == null) && (bookmarks.size() > 0)) {
			defaultView = (Bookmark) bookmarks.get(0);
		}

		for (Iterator it = bookmarks.iterator(); it.hasNext();) {
			Bookmark b = (Bookmark) it.next();
			String fileName = writeBookmark(b);
			list.addBookmark(b.getPresentationName(), fileName,
					(defaultView == b));
		}
		
		// then write the top level bookmark xml
		XmlElement xml = list.getXmlElement();

		String buffer = PublishingUtil.getHtml(xml, BOOKMARKS_XSL_FILE);
		if (buffer != null) {
			String htmlPath = getBookmarkHtmlPath(PUBLISHED_BOOKMARKS_CFG_NAME);
			FileUtil.writeUTF8File(htmlPath, buffer.toString());
		}
	}
	
	protected void writeIndexAndTopNavHtml() {

		XmlElement optionXml = getOptionXml();
		
		String buffer = PublishingUtil.getHtml(optionXml, INDEX_XSL_FILE);
		if (buffer != null) {
			String htmlPath = getIndexFilePath();
			FileUtil.writeUTF8File(htmlPath, buffer.toString());
		}

		buffer = PublishingUtil.getHtml(optionXml, TOPNAV_XSL_FILE);
		if (buffer != null) {
			String htmlPath = viewBuilder.getHtmlBuilder().getPublishDir()
					+ "topnav.htm"; //$NON-NLS-1$
			FileUtil.writeUTF8File(htmlPath, buffer.toString());
		}
	}

	protected XmlElement getOptionXml() {
		boolean showGlossary = (options == null) || options.generateGlossary;
		boolean showIndex = (options == null) || options.generateIndex;

		XmlElement optionXml = new XmlElement("PublishingOption") //$NON-NLS-1$
		.setAttribute("title", (options == null) ? "" : options.title) //$NON-NLS-1$ //$NON-NLS-2$
		.setAttribute(
				"bannerImage", (options == null) ? "" : options.bannerImage) //$NON-NLS-1$ //$NON-NLS-2$
		.setAttribute(
				"feedbackUrl", (options == null) ? "" : options.feedbackURL) //$NON-NLS-1$ //$NON-NLS-2$
		.setAttribute("showGlossary", (showGlossary ? "true" : "false")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		.setAttribute("showIndex", (showIndex ? "true" : "false")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

		return optionXml;
	}
	
	public String getIndexFilePath() {
		return viewBuilder.getHtmlBuilder().getPublishDir() + "index.htm"; //$NON-NLS-1$
	}

	protected String getBookmarkHtmlPath(String boomkarkFile) {
		int indx = boomkarkFile.lastIndexOf(BOOKMARK_SUFFIX_XML);
		return viewBuilder.getHtmlBuilder().getPublishDir()
				+ NO_APPLET_DIRECTORY + File.separatorChar
				+ boomkarkFile.substring(0, indx) + BOOKMARK_SUFFIX_HTML;
	}

	protected void generateBookmarkIndex(String publishDir, String title,
			IProgressMonitor monitor) {
		try {

			URL url = new URL(PublishingPlugin.getDefault().getInstallURL(),
					KEYWORD_DEF_FILE);
			if (url == null) {
				System.out.println("Unable to get index definition file "); //$NON-NLS-1$
				return;
			}

			String deffile = Platform.resolve(url).getPath();
			String charSet = "utf-8"; //$NON-NLS-1$
			String helpFile = null;
			KeyWordIndexHelper indexHelper = new KeyWordIndexHelper(deffile,
					charSet, helpFile);
			DefinitionObject defObj = indexHelper.loadDefinition(publishDir);
			if (defObj != null) {
				defObj.setwwwRoot(publishDir);
				defObj
						.setIndexTitle(PublishingResources.indexLabel_text + " - " + title); //$NON-NLS-1$ //$NON-NLS-2$
			}

			indexHelper.execute(monitor);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * generate the publishing report and return the url
	 * 
	 * @return String the report url
	 */
	public String getPublishReportUrl() {
		String publishDir = viewBuilder.getHtmlBuilder().getPublishDir();
		String file_pathname = PublishingContentValidator.LOGS_FOLDER
				+ File.separator + PUBLISHING_REPORT_HTML_FILE;
		File f = new File(publishDir, file_pathname);
		String report_file = f.getAbsolutePath();
		if (!f.exists()) {
			File errorLog = new File(publishDir,
					PublishingContentValidator.LOGS_FOLDER + File.separator
							+ PublishingContentValidator.ERROR_LOG_FILENAME);
			File warningLog = new File(publishDir,
					PublishingContentValidator.LOGS_FOLDER + File.separator
							+ PublishingContentValidator.WARNING_LOG_FILENAME);
			File infoLog = new File(publishDir,
					PublishingContentValidator.LOGS_FOLDER + File.separator
							+ PublishingContentValidator.INFO_LOG_FILENAME);

			// geenrate the index.htm
			XmlElement reportXml = new XmlElement("PublishingReport"); //$NON-NLS-1$

			reportXml.newChild("pubDir").setAttribute("path", publishDir); //$NON-NLS-1$ //$NON-NLS-2$
			reportXml
					.newChild("errorLog") //$NON-NLS-1$
					.setAttribute(
							"name", PublishingContentValidator.ERROR_LOG_FILENAME) //$NON-NLS-1$
					.setAttribute("path", "./" + errorLog.getName()); //$NON-NLS-1$ //$NON-NLS-2$

			reportXml
					.newChild("warningLog") //$NON-NLS-1$
					.setAttribute(
							"name", PublishingContentValidator.WARNING_LOG_FILENAME) //$NON-NLS-1$
					.setAttribute("path", "./" + warningLog.getName()); //$NON-NLS-1$ //$NON-NLS-2$

			reportXml
					.newChild("infoLog") //$NON-NLS-1$
					.setAttribute(
							"name", PublishingContentValidator.INFO_LOG_FILENAME) //$NON-NLS-1$
					.setAttribute("path", "./" + infoLog.getName()); //$NON-NLS-1$ //$NON-NLS-2$

			// detail information
			PublishingContentValidator validator = (PublishingContentValidator) viewBuilder
					.getHtmlBuilder().getValidator();
			reportXml.addChild(validator.getReport());

			String buffer = PublishingUtil.getHtml(reportXml,
					PUBLISHING_REPORT_XSL_FILE);
			if (buffer != null) {
				FileUtil.writeUTF8File(report_file, buffer.toString());
			}
		}

		return report_file;
	}

}
