/*
* Copyright (c) 2009-2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.web.client.ui.common.stream.transformers;
import org.eurekastreams.web.client.jsni.WidgetJSNIFacadeImpl;
/**
* Convert urls into hyperlinks.
*/
public class HyperlinkTransformer
{
/**
* JSNI facade.
*/
private WidgetJSNIFacadeImpl jsni;
/**
* Constructor.
*
* @param inJsni
* the JSNI to escape the html content.
*/
public HyperlinkTransformer(final WidgetJSNIFacadeImpl inJsni)
{
jsni = inJsni;
}
/**
* Renders the content with urls converted to hyperlinks.
*
* @param inContent
* the content to hyperlink
* @return the content with urls converted to hyperlinks.
*/
public String transform(final String inContent)
{
String bodyText = inContent;
if (bodyText != null && !bodyText.equals(""))
{
int searchIndex = 0;
int startIndex = 0;
do
{
int[] urlIndex = new int[3];
urlIndex[0] = bodyText.indexOf("http://", searchIndex);
urlIndex[1] = bodyText.indexOf("https://", searchIndex);
urlIndex[2] = bodyText.indexOf("www.", searchIndex);
startIndex = -1;
for (int i : urlIndex)
{
if (i > -1)
{
if (startIndex == -1)
{
startIndex = i;
}
else if (i < startIndex)
{
startIndex = i;
}
}
}
if (startIndex >= 0)
{
int endIndex = -1;
int[] endUrlIndex = new int[9 + 4];
endUrlIndex[0] = bodyText.indexOf(" ", startIndex);
endUrlIndex[1] = bodyText.indexOf("\n", startIndex);
endUrlIndex[2] = bodyText.indexOf(". ", startIndex);
endUrlIndex[3] = bodyText.indexOf("! ", startIndex);
endUrlIndex[4] = bodyText.indexOf("? ", startIndex);
endUrlIndex[5] = bodyText.indexOf("!\n", startIndex);
endUrlIndex[6] = bodyText.indexOf("?\n", startIndex);
endUrlIndex[7] = bodyText.indexOf(".\n", startIndex);
endUrlIndex[8] = bodyText.indexOf(", ", startIndex);
endUrlIndex[9] = bodyText.indexOf(",\n", startIndex);
endUrlIndex[9 + 1] = bodyText.indexOf("<", startIndex);
endUrlIndex[9 + 2] = bodyText.indexOf(">", startIndex);
endUrlIndex[9 + 3] = bodyText.indexOf(" ", startIndex);
for (int x = 0; x < endUrlIndex.length; x++)
{
if (endUrlIndex[x] > -1)
{
// if endindex has not been set or if there is a closer end index.
if (endIndex == -1 || endUrlIndex[x] < endIndex)
{
endIndex = endUrlIndex[x];
}
}
}
// this deals with end indexes being at the end of the string.
if (endIndex == -1)
{
endIndex = bodyText.length();
// if the last character before the end is a '.', don't include in the link.
char lastChar = bodyText.charAt(bodyText.length() - 1);
if (lastChar == '.' || lastChar == '?' || lastChar == '!')
{
endIndex--;
}
}
// just in case we're nested in parens, peel them off
if (openParenCount(bodyText, startIndex) > 0)
{
while (endIndex >= startIndex && bodyText.charAt(endIndex - 1) == ')')
{
endIndex--;
}
}
String url = bodyText.substring(startIndex, endIndex);
String linkableUrl = bodyText.substring(startIndex, endIndex);
if (linkableUrl.startsWith("www."))
{
linkableUrl = "http://" + linkableUrl;
}
String linkHtml = "<a target=\"_blank\" href=\"" + linkableUrl + "\">" + url + "</a>";
searchIndex = startIndex + linkHtml.length();
bodyText = bodyText.substring(0, startIndex) + linkHtml + bodyText.substring(endIndex);
}
}
while (startIndex >= 0);
}
return bodyText;
}
/**
* Return the count of open parens to the left of the input position.
*
* @param text
* the text to check
* @param position
* the position to check
* @return the count of open parens to the left of the input position
*/
private int openParenCount(final String text, final int position)
{
int nestCount = 0;
for (int i = 0; i < position; i++)
{
if (isInHrefBlock(text, i))
{
continue;
}
if (text.charAt(i) == ')')
{
if (nestCount > 0)
{
nestCount--;
}
}
else if (text.charAt(i) == '(')
{
nestCount++;
}
}
return nestCount;
}
/**
* Test whether the character at the input position is inside a hyperlink tag.
*
* @param content
* the content to check
* @param pos
* the position to check in the content
* @return whether the character at the input position is inside a hyperlink tag
*/
private boolean isInHrefBlock(final String content, final int pos)
{
for (int p = pos - 1; p >= 0; p--)
{
String block = content.substring(p, pos).toLowerCase();
if (block.contains("</a>"))
{
return false;
}
if (block.contains("<a "))
{
return true;
}
}
return false;
}
}