/*
* Copyright 2012 Axel Winkler, Daniel Dunér
*
* This file is part of Daxplore Presenter.
*
* Daxplore Presenter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Daxplore Presenter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Daxplore Presenter. If not, see <http://www.gnu.org/licenses/>.
*/
package org.daxplore.presenter.shared;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Static helper methods that can be used both on the client side (GWT) and
* on the server side (Java).
*/
public class SharedTools {
/**
* Combine a list of objects into a single string using a separator
* between each object.
*
* <p>The method {@link Object#toString()} is used to get a string
* representation of each object.</p>
*
* <p><b>The code:</b>
* <pre>{@code
* String[] numbers = {"one", "two", "three"};
* String jointNumbers = join(numbers, "~");
* System.out.println(jointNumbers);
* }</pre>
* <b>Results in the output:</b> <i>one~two~three</i></p>
*
* @param <T>
* a generic type that can be anything
* @param iter
* an iterable (for example a list) of objects
* @param seperator
* the string used as a separator
* @return the joint string
*/
public static <T> String join(Iterable<T> iter, String seperator) {
Iterator<T> i = iter.iterator();
StringBuilder sb = new StringBuilder();
if (i.hasNext()) {
for (;;) {
sb.append(i.next().toString());
if (!i.hasNext()) {
break;
}
sb.append(seperator);
}
}
return sb.toString();
}
/**
* Combine an array of objects into a single string using a separator
* between each object.
*
* <p>The method toString() is used to get a string representation of each
* object.</p>
*
* <p><b>The code:</b>
* <pre>{@code
* String[] numbers = {"one", "two", "three"};
* String jointNumbers = join(numbers, "~");
* System.out.println(jointNumbers);
* }</pre>
* <b>Results in the output:</b> <i>one~two~three</i></p>
*
* @param <T>
* a generic type that can be anything
* @param iter
* an array of objects
* @param seperator
* the string used as a separator
* @return the joint string
*/
public static <T> String join(T[] array, String seperator) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < (array.length - 1); i++) {
sb.append(array[i].toString());
sb.append(seperator);
}
sb.append(array[array.length - 1]);
return sb.toString();
}
/**
* Combine an array of ints into a single string using a separator
* between each number.
*
* <p><b>The code:</b>
* <pre>{@code
* int[] numbers = {1, 2, 3};
* String jointNumbers = join(numbers, "~");
* System.out.println(jointNumbers);
* }</pre>
* <b>Results in the output:</b> <i>1~2~3</i></p>
*
* @param <T>
* a generic type that can be anything
* @param array
* an array of ints
* @param seperator
* the string used as a separator
* @return the joint string
*/
public static String join(int[] array, String seperator) {
Integer[] wrap = new Integer[array.length];
for (int i = 0; i < wrap.length; i++) {
wrap[i] = array[i];
}
return join(wrap, seperator);
}
/**
* Get a map from parameters in a String "var1=a&var2=b&var3=c".
*
* <p>Splits on the character '&' and creates key-value pairs given in the
* key=value format.</p>
*
* @param tokens
* a string containing the tokens
* @return a linked hash map that contains the key-value pairs
* @throws IllegalArgumentException
* thrown if the token string is in an incorrect format or there
* are duplicate keys
*/
public static LinkedHashMap<String, String> parseTokens(String tokens) throws IllegalArgumentException {
String[] arStr = tokens.split("&");
LinkedHashMap<String, String> params = new LinkedHashMap<>();
for (int i = 0; i < arStr.length; i++) {
String[] substr = arStr[i].split("=");
if (substr.length == 2 && !substr[0].equals("")) {
if (params.containsKey(substr[0])) {
throw new IllegalArgumentException("Duplicate key: '" + substr[0] + "'");
}
params.put(substr[0], substr[1]);
} else {
throw new IllegalArgumentException("Bad key-value definition: '" + tokens + "'");
}
}
return params;
}
/**
* Justify a string with wordwrap.
*
* <p>Code taken from
* <a href=http://www.rgagnon.com/javadetails/java-0013.html>rgagnon.com</a>.
* </p>
*
* @param text
* the text
* @param width
* the max character-width of a line
* @return the string
*/
public static String justifyLeft(String text, int width) {
StringBuffer buf = new StringBuffer(text);
int lastspace = -1;
int linestart = 0;
int i = 0;
while (i < buf.length()) {
if (buf.charAt(i) == ' ') {
lastspace = i;
}
if (buf.charAt(i) == '\n') {
lastspace = -1;
linestart = i + 1;
}
if (i > linestart + width - 1) {
if (lastspace != -1) {
buf.setCharAt(lastspace, '\n');
linestart = lastspace + 1;
lastspace = -1;
} else {
buf.insert(i, '\n');
linestart = i + 1;
}
}
i++;
}
return buf.toString();
}
/**
* Justify a string left with wordwrap, formatted so that it works in HTML.
*
* <p><b>Note:</b> Mutilates proper HTML by replacing <code><br /></code>
* tag with <code><br><code>.</p>
*
* @param text
* the text
* @param width
* the max character-width of a line
* @return the string
*/
public static String justifyHTML(String text, int width) {
String justified = text.replace("<br>","\n").replace("<br />", "\n");
justified = justifyLeft(justified, width);
return justified.replace("\n", "<br>");
}
/**
* Split a text into two lines of approximately equal lengths, formatted
* to work in HTML.
*
* @param text
* the text
* @return the formatted text
*/
public static String splitInTwoHTML(String text) {
int midpoint = text.length() / 2;
for(int i = 0; i<text.length()/2; i++) {
if (midpoint+i < text.length()-1 && text.charAt(midpoint + i)==' ') {
return text.substring(0, midpoint+i) + "<br>" + text.substring(midpoint+i+1);
} else if (text.charAt(midpoint - i)==' ') {
return text.substring(0, midpoint-i) + "<br>" + text.substring(midpoint-i+1);
}
}
return text;
}
/**
* Check if a string matches another string in an array, ignoring case.
*
* @param in
* the string to check for
* @param compareToList
* the list that may contain the string
* @return true, if the list contains the string
*/
public static boolean equalsAnyIgnoreCase(String in, String[] compareToList) {
boolean equals = false;
for (int i = 0; i < compareToList.length; i++) {
equals = equals || in.equalsIgnoreCase(compareToList[i]);
}
return equals;
}
/**
* Check if a string matches another string in an array.
*
* @param in
* the string to check for
* @param compareToList
* the list that may contain the string
* @return true, if the list contains the string
*/
public static boolean equalsAny(String in, String[] compareToList) {
boolean equals = false;
for (int i = 0; i < compareToList.length; i++) {
equals = equals || in.equals(compareToList[i]);
}
return equals;
}
/**
* Split a String into equal length String chunks.
*
* <p>The last part will contain the remainder.</p>
*
* @param string The String to be split
* @param chunkLength The length of the resulting chunks
* @return A List containing the String chunks
*/
public static List<String> splitString(String string, int chunkLength) {
List<String> chunkList = new ArrayList<>((string.length() + chunkLength - 1) / chunkLength);
for (int start = 0; start < string.length(); start += chunkLength) {
chunkList.add(string.substring(start, Math.min(string.length(), start + chunkLength)));
}
return chunkList;
}
}