Bug 529964: Links in help hovers point to wrong location

  replace relative anchor and image links with absolute links

Change-Id: Id8e5872309f3965bec8f4677920e663f300db062
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/help/hovers/ModuleHelp.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/help/hovers/ModuleHelp.java
index dcd0b5c..98f73bb 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/help/hovers/ModuleHelp.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/help/hovers/ModuleHelp.java
@@ -92,24 +92,32 @@
 	/**
 	 * Retrieve help page for a given module definition.
 	 *
+	 * @param url
+	 *            url to read help from
+	 * @return help content (HTML body node)
+	 */
+	private static IMemento getHtmlContent(final URL url) {
+
+		try {
+			final IMemento rootNode = XMLMemento.createReadRoot(new InputStreamReader(url.openStream(), "UTF-8"));
+			return rootNode.getChild("body");
+		} catch (final Exception e) {
+			Logger.error(Activator.PLUGIN_ID, "Cannot find the module help content ", e);
+		}
+
+		return null;
+	}
+
+	/**
+	 * Retrieve help page for a given module definition.
+	 *
 	 * @param definition
 	 *            module definition to fetch help for
 	 * @return help content (HTML body node)
 	 */
-	private static IMemento getHelpContent(final ModuleDefinition definition) {
-
-		if (definition != null) {
-			final String helpLocation = definition.getHelpLocation(null);
-			final URL url = PlatformUI.getWorkbench().getHelpSystem().resolve(helpLocation, true);
-			try {
-				final IMemento rootNode = XMLMemento.createReadRoot(new InputStreamReader(url.openStream(), "UTF-8"));
-				return rootNode.getChild("body");
-			} catch (final Exception e) {
-				Logger.error(Activator.PLUGIN_ID, "Cannot find the module help content ", e);
-			}
-		}
-
-		return null;
+	private static URL getModuleHelpLocation(final ModuleDefinition definition) {
+		final String helpLocation = definition.getHelpLocation(null);
+		return PlatformUI.getWorkbench().getHelpSystem().resolve(helpLocation, true);
 	}
 
 	/**
@@ -121,7 +129,8 @@
 	 */
 	public static String getModuleHelpTip(final ModuleDefinition definition) {
 
-		final IMemento bodyNode = getHelpContent(definition);
+		final URL helpLocation = getModuleHelpLocation(definition);
+		final IMemento bodyNode = getHtmlContent(helpLocation);
 		if (bodyNode != null) {
 
 			final StringBuffer helpContent = new StringBuffer();
@@ -129,6 +138,8 @@
 				if ("module".equals(node.getString("class"))) {
 					for (final IMemento contentNode : node.getChildren()) {
 						if ("description".equals(contentNode.getString("class"))) {
+							updateRelativeLinks(contentNode, helpLocation);
+
 							final String content = getNodeContent(contentNode);
 							if ((content != null) && (!content.isEmpty()))
 								helpContent.append(content);
@@ -150,6 +161,46 @@
 		return null;
 	}
 
+	/**
+	 * Replace relative links in HTML content with absolute links.
+	 *
+	 * @param contentNode
+	 *            original content
+	 * @param helpLocation
+	 *            original source location
+	 */
+	private static void updateRelativeLinks(IMemento node, URL helpLocation) {
+		if ((node.getType().equals("a")) && (node.getString("href") != null))
+			node.putString("href", resolveUrl(helpLocation, node.getString("href")));
+
+		if ((node.getType().equals("img")) && (node.getString("src") != null))
+			node.putString("src", resolveUrl(helpLocation, node.getString("src")));
+
+		for (final IMemento child : node.getChildren())
+			updateRelativeLinks(child, helpLocation);
+	}
+
+	private static String resolveUrl(URL base, String relativeLocation) {
+		if (relativeLocation.contains("://"))
+			return relativeLocation;
+
+		final String baseLocation = base.toString();
+
+		if (relativeLocation.startsWith("#"))
+			return baseLocation + relativeLocation;
+
+		if (relativeLocation.startsWith("/")) {
+			final int hostPosition = baseLocation.indexOf(base.getHost());
+			return baseLocation.substring(0, hostPosition + base.getHost().length()) + relativeLocation;
+		}
+
+		final int lastPathDelimiter = baseLocation.lastIndexOf('/');
+		if (lastPathDelimiter > 0)
+			return baseLocation.substring(0, lastPathDelimiter + 1) + relativeLocation;
+
+		return "";
+	}
+
 	public static String getImageAndLabel(String imageSrcPath, String label) {
 		final StringBuffer buf = new StringBuffer();
 		final int imageWidth = 16;
@@ -216,13 +267,17 @@
 	public static String getMethodHelpTip(final Method method) {
 
 		// FIXME do not use getDeclaringMethod, see bug 502854
-		final IMemento bodyNode = getHelpContent(ModulesTools.getDeclaringModule(method));
+		final URL helpLocation = getModuleHelpLocation(ModulesTools.getDeclaringModule(method));
+		final IMemento bodyNode = getHtmlContent(helpLocation);
+
 		if (bodyNode != null) {
 
 			for (final IMemento node : bodyNode.getChildren("div")) {
 				if ((method.getName().equals(node.getString("data-method"))) && ("command".equals(node.getString("class")))) {
 					// method found
 
+					updateRelativeLinks(node, helpLocation);
+
 					final StringBuffer helpContent = new StringBuffer();
 
 					HTMLPrinter.addSmallHeader(helpContent, getImageAndLabel(getImageLocation("icons/eobj16/function.png"), createSynopsis(method)));
@@ -447,7 +502,9 @@
 	 */
 	public static String getConstantHelpTip(final Field field) {
 
-		final IMemento bodyNode = getHelpContent(ModulesTools.getDeclaringModule(field));
+		final URL helpLocation = getModuleHelpLocation(ModulesTools.getDeclaringModule(field));
+		final IMemento bodyNode = getHtmlContent(helpLocation);
+
 		if (bodyNode != null) {
 			for (final IMemento node : bodyNode.getChildren("table")) {
 				if ("constants".equals(node.getString("class"))) {
@@ -459,6 +516,8 @@
 						if (field.getName().equals(candidate.getString("data-field"))) {
 							// constant found
 
+							updateRelativeLinks(candidate, helpLocation);
+
 							final StringBuffer helpContent = new StringBuffer();
 
 							HTMLPrinter.addSmallHeader(helpContent, getImageAndLabel(getImageLocation("icons/eobj16/field.png"), field.getName()));