content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.eclipse.ide.ui.utils;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.URL;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.List;
  
  import org.eclipse.core.runtime.Platform;
  import org.eclipse.jface.internal.text.html.HTMLPrinter;
  import org.eclipse.jface.resource.ImageDescriptor;
  import org.eclipse.jface.resource.JFaceResources;
  import org.eclipse.swt.graphics.FontData;
  import org.eclipse.swt.graphics.RGB;
  import org.osgi.framework.Bundle;
  
  import tern.eclipse.ide.internal.ui.TernUIMessages;
  import tern.eclipse.ide.internal.ui.Trace;
  import tern.eclipse.ide.ui.TernUIPlugin;
  import tern.eclipse.jface.text.HoverLocationListener;
  import tern.server.protocol.completions.Parameter;
  import tern.server.protocol.completions.TernCompletionItem;
  import tern.utils.StringUtils;
  
  /**
   * Provides a set of convenience methods for creating HTML info for tern content
   * assist and hover.
   *
   */
  public class HTMLTernPrinter {
  
  	/**
  	 * Style sheets content.
  	 */
  	private static String fgStyleSheet;
  
  	private static RGB colorInfoBackround = null;
  	private static RGB colorInfoForeground = null;
  
  	private HTMLTernPrinter() {
  	}
  
  	public static void setColorInfoBackround(RGB colorInfoBackround) {
  		HTMLTernPrinter.colorInfoBackround = colorInfoBackround;
  	}
  	
  	public static void setColorInfoForeground(RGB colorInfoForeground) {
  		HTMLTernPrinter.colorInfoForeground = colorInfoForeground;
  	}
  	
  	public static String getAdditionalProposalInfo(TernCompletionItem item,
  			Boolean guess) {
  		StringBuffer buffer = new StringBuffer();
  		ImageDescriptor descriptor = TernUIPlugin.getTernDescriptorManager()
  				.getImageDescriptor(item);
  		startPage(buffer, getTitle(item), descriptor);
  		// doc
  		addDocContent(buffer, item.getDoc());
  		startDefinitionList(buffer);
  		// parameters
  		addParametersContent(buffer, item.getParameters());
  		// return type
  		addReturnTypeContent(buffer, item.getJsType());
  		// origin
  		addOriginContent(buffer, item.getOrigin());
  		// guess?
  		addGuessContent(buffer, guess);
  		// url
  		addURLContent(buffer, item.getURL());
  		endDefinitionList(buffer);
  		endPage(buffer);
  		return buffer.toString();
  	}
  
  	public static void addGuessContent(StringBuffer buffer, Boolean guess) {
  		if (guess != null) {
  			addDefinitionListItem(buffer, "Guess?", guess.toString());
  		}
  	}
  
  	public static void addReturnTypeContent(StringBuffer buffer,
  			String returnType) {
  		if (!StringUtils.isEmpty(returnType)) {
  			buffer.append("<dt><b>Returns:</b></dt>");
  			buffer.append("<dd>");
  			buffer.append("<code>");
  			buffer.append(returnType);
  			buffer.append("</code>");
  			buffer.append("</dd>");
  		}
  	}
  
  	public static void addParametersContent(StringBuffer buffer,
  			List<Parameter> parameters) {
  		if (parameters != null) {
  			buffer.append("<dt><b>Parameters:</b></dt>");
  			for (Parameter parameter : parameters) {
  				buffer.append("<dd>");
  				if (!parameter.isRequired()) {
  					buffer.append("[");
  				}
  				buffer.append("<code>");
  				buffer.append(parameter.getName());
  				buffer.append("</code>");
  				if (!parameter.isRequired()) {
  					buffer.append("]");
  				}
  				buffer.append(" - ");
  				buffer.append("<code>");
  				buffer.append(parameter.getType());
  				buffer.append("</code>");
  				buffer.append("</dd>");
  			}
  		}
  	}
  
  	public static String getTitle(TernCompletionItem item) {
  		String title = item.hasDisplayName() ? item.getDisplayName() : item.getSignature();
  		StringBuilder buffer = new StringBuilder("<b>").append(
  				title).append("</b>");
  		return buffer.toString();
  	}
  
  	public static void addDocContent(StringBuffer buffer, String doc) {
  		buffer.append("<p>");
  		if (doc != null) {
  			buffer.append(doc);
  		}
  		buffer.append("</p>");
  	}
  
  	public static void endPage(StringBuffer buffer) {
  		HTMLPrinter
  				.insertPageProlog(buffer, 0, colorInfoForeground, colorInfoBackround, HTMLTernPrinter.getStyleSheet());
  		HTMLPrinter.addPageEpilog(buffer);
  	}
  
  	public static void addOriginContent(StringBuffer buffer, String origin) {
  		addLinkContent(buffer, "Origin", new StringBuilder(
  				HoverLocationListener.TERN_FILE_PROTOCOL).append(origin).toString(),
  				origin);
  	}
  
  	public static void addDefinitionListItem(StringBuffer buffer, String name,
  			String value) {
  		if (!StringUtils.isEmpty(value)) {
  			buffer.append("<dt><b>");
  			buffer.append(name);
  			buffer.append(":</b></dt>");
  			buffer.append("<dd>");
  			buffer.append(value);
  			buffer.append("</dd>");
  		}
  	}
  
  	public static void addDefinitionListItem(StringBuffer buffer, String name,
  			Collection<String> values) {
  		if (values != null && !values.isEmpty()) {
  			addDefinitionListItem(buffer, name,
  					Arrays.toString(values.toArray()));
  		}
  	}
  
  	public static void addURLContent(StringBuffer buffer, String url) {
  		if (!StringUtils.isEmpty(url)) {
  			addLinkContent(buffer, "See", url, url);
  		}
  	}
  
  	protected static void addLinkContent(StringBuffer buffer, String label,
  			String linkHref, String linkLabel) {
  		buffer.append("<dt><b>");
  		buffer.append(label);
  		buffer.append(":</b></dt>");
  		buffer.append("<dd>");
  		buffer.append("<a href=\"");
  		buffer.append(linkHref);
  		buffer.append("\" >");
  		buffer.append(linkLabel);
  		buffer.append("</a>");
  		buffer.append("</dd>");
  	}
  
  	public static void startDefinitionList(StringBuffer buffer) {
  		buffer.append("<dl>"); //$NON-NLS-1$
  	}
  
  	public static void endDefinitionList(StringBuffer buffer) {
  		buffer.append("</dl>"); //$NON-NLS-1$
  	}
  
  	/**
  	 * Returns the Javadoc hover style sheet with the current Javadoc font from
  	 * the preferences.
  	 * 
  	 * @return the updated style sheet
  	 * @since 3.4
  	 */
  	private static String getStyleSheet() {
  		if (fgStyleSheet == null) {
  			fgStyleSheet = loadStyleSheet("/TernHoverStyleSheet.css"); //$NON-NLS-1$
  		}
  		String css = fgStyleSheet;
  		if (css != null) {
  			FontData fontData = JFaceResources.getFontRegistry().getFontData(
  					JFaceResources.DIALOG_FONT)[0];
  			css = HTMLPrinter.convertTopLevelFont(css, fontData);
  		}
  
  		return css;
  	}
  
  	/**
  	 * Loads and returns the style sheet associated with either Javadoc hover or
  	 * the view.
  	 * 
  	 * @param styleSheetName
  	 *            the style sheet name of either the Javadoc hover or the view
  	 * @return the style sheet, or <code>null</code> if unable to load
  	 * @since 3.4
  	 */
  	private static String loadStyleSheet(String styleSheetName) {
  		Bundle bundle = Platform.getBundle(TernUIPlugin.PLUGIN_ID);
  		URL styleSheetURL = bundle.getEntry(styleSheetName);
  		if (styleSheetURL == null)
  			return null;
  
  		BufferedReader reader = null;
  		try {
  			reader = new BufferedReader(new InputStreamReader(
  					styleSheetURL.openStream()));
  			StringBuffer buffer = new StringBuffer(1500);
  			String line = reader.readLine();
  			while (line != null) {
  				buffer.append(line);
  				buffer.append('\n');
  				line = reader.readLine();
  			}
  
  			FontData fontData = JFaceResources.getFontRegistry().getFontData(
  					JFaceResources.DIALOG_FONT)[0];
  			return HTMLPrinter.convertTopLevelFont(buffer.toString(), fontData);
  		} catch (IOException ex) {
  			Trace.trace(Trace.SEVERE, "Error while loading style sheets", ex);
  			return ""; //$NON-NLS-1$
  		} finally {
  			try {
  				if (reader != null)
  					reader.close();
  			} catch (IOException e) {
  				// ignore
  			}
  		}
  	}
  
  	public static void startPage(StringBuffer buf, String title,
  			ImageDescriptor descriptor) {
  		int imageWidth = 16;
  		int imageHeight = 16;
  		int labelLeft = 20;
  		int labelTop = 2;
  
  		// buf.append("<p>");
  		buf.append("<div style='word-wrap: break-word; position: relative; "); //$NON-NLS-1$
  
  		String imageSrcPath = getImageURL(descriptor);
  		if (imageSrcPath != null) {
  			buf.append("margin-left: ").append(labelLeft).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
  			buf.append("padding-top: ").append(labelTop).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
  		}
  
  		buf.append("'>"); //$NON-NLS-1$
  		if (imageSrcPath != null) {
  			
  			String uri = HoverLocationListener.TERN_DEFINITION_PROTOCOL;
  			buf.append("<a href=\"");
  			buf.append(uri);
  			buf.append("\" >");
  			
  			StringBuffer imageStyle = new StringBuffer(
  					"border:none; position: absolute; "); //$NON-NLS-1$
  			imageStyle.append("width: ").append(imageWidth).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
  			imageStyle.append("height: ").append(imageHeight).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
  			imageStyle.append("left: ").append(-labelLeft - 1).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
  
  			// hack for broken transparent PNG support in IE 6, see
  			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=223900 :
  			buf.append("<!--[if lte IE 6]><![if gte IE 5.5]>\n"); //$NON-NLS-1$
  			String tooltip = "alt='" + TernUIMessages.TernHover_openDeclaration + "' "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  			buf.append("<span ").append(tooltip).append("style=\"").append(imageStyle). //$NON-NLS-1$ //$NON-NLS-2$
  					append("filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='").append(imageSrcPath).append("')\"></span>\n"); //$NON-NLS-1$ //$NON-NLS-2$
  			buf.append("<![endif]><![endif]-->\n"); //$NON-NLS-1$
  
  			buf.append("<!--[if !IE]>-->\n"); //$NON-NLS-1$
  			buf.append("<img ").append(tooltip).append("style='").append(imageStyle).append("' src='").append(imageSrcPath).append("'/>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
  			buf.append("<!--<![endif]-->\n"); //$NON-NLS-1$
  			buf.append("<!--[if gte IE 7]>\n"); //$NON-NLS-1$
  			buf.append("<img ").append(tooltip).append("style='").append(imageStyle).append("' src='").append(imageSrcPath).append("'/>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
  			buf.append("<![endif]-->\n"); //$NON-NLS-1$
  			// if (element != null) {
  			
  			buf.append("</a>"); //$NON-NLS-1$
  			
  			// }
  		}
  		buf.append(title);
  
  		buf.append("</div>"); //$NON-NLS-1$
  		buf.append("<hr />");
  	}
  
  	private static String getImageURL(ImageDescriptor descriptor) {
  		if (descriptor == null) {
  			return null;
  		}
  		String imageName = null;
  		URL imageUrl = TernUIPlugin.getTernDescriptorManager().getImageURL(
  				descriptor);
  		if (imageUrl != null) {
  			imageName = imageUrl.toExternalForm();
  		}
  		return imageName;
  	}
  
  }
  