package net.returnvoid.tools;

import java.util.ArrayList;
import java.util.Calendar;

/*
 * This code is copyright (c) Diana Lange 2017
 *
 * The library is published under the Creative Commons license NonCommercial 4.0.
 * Please check https://creativecommons.org/licenses/by-nc/4.0/ for more information.
 * 
 * This program is distributed in the hope that it will be useful, but without any warranty.
 */

/**
 * A collection of functions to format Strings or to parse other data types to
 * String in a certain way.
 * 
 *
 * @author Diana Lange
 *
 */
public class StringTools {

	/**
	 * This class is just a collection of static functions and there shouldn't
	 * be any instances of it.
	 */
	private StringTools() {
	}

	/**
	 * Returns a String containing the current time (yyyymmdd_hhmmss).
	 * 
	 * @return The timestamp.
	 */
	static public String timestamp() {
		return String.format("%1$tY%1$tm%1$td_%1$tH%1$tM%1$tS", Calendar.getInstance());
	}

	/**
	 * Parses the given int to a String. The output String will contain
	 * <b>digits</b> numbers and a sign. Empty spaces will be filled with zeroes
	 * and too many numbers will be cut. Example:<br>
	 * 
	 * <pre>
	 * StringTools.nf(3, 4); // "+0003"
	 * StringTools.nf(-1999, 3); // "-999"
	 * </pre>
	 * 
	 * @param val
	 *            The number that should be parsed.
	 * @param digits
	 *            The number of numbers that should be in the output String.
	 * @return The parsed and formated String.
	 */
	static public String nf(int val, int digits) {
		return StringTools.nfs(val, digits, 0);
	}

	/**
	 * Parses the given value to a String. The output String will contain
	 * <b>d1</b> numbers before the point separator, <b>d2</b> numbers after the
	 * point separator and a sign. Empty spaces will be filled with zeroes and
	 * too many numbers will be cut. Example:<br>
	 * 
	 * <pre>
	 * StringTools.nfs(3.5, 2, 2); // "+03.50"
	 * StringTools.nfs(-1999, 3, 2); // "-999.00"
	 * </pre>
	 * 
	 * @param val
	 *            The number that should be parsed.
	 * @param d1
	 *            The number of numbers before the point.
	 * @param d2
	 *            The number of numbers after the point.
	 * @return The parsed and formated String.
	 */
	static public String nfs(float val, int d1, int d2) {
		String txt = "" + val;
		txt = txt.replaceAll("[+-]", "");

		String[] splitted = txt.split("[.,]");
		String sub1 = splitted.length > 0 ? splitted[0] : txt;
		String sub2 = splitted.length > 1 ? splitted[1] : "0";

		if (sub1.length() < d1) {
			int num = d1 - sub1.length() - 1;
			num = (int) Math.pow(10, num);
			sub1 = ("" + num).replaceAll("\\d", "" + 0) + sub1;
		} else if (sub1.length() > d1) {
			sub1 = sub1.substring(sub1.length() - d1, sub1.length());
		}

		if (sub2.length() < d2) {
			int num = d2 - sub2.length() - 1;
			num = (int) Math.pow(10, num);
			sub2 = sub2 + ("" + num).replaceAll("\\d", "" + 0);
		} else if (sub2.length() > d2) {
			sub2 = sub2.substring(0, d2);
		}

		return (val < 0 ? "-" : "+") + sub1 + (sub2.length() > 0 ? "." + sub2 : "");

	}

	// join: since java 8.0 already implemented in String, but not in early
	// releases...

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>.
	 * 
	 * @param list
	 *            A float array which should be joined.
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @return The joined String.
	 */
	static public String join(float[] list, String separator) {
		String txt = "";

		for (float t : list) {
			txt += t + separator;
		}

		return txt.substring(0, txt.length() - separator.length());
	}

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>.
	 * 
	 * @param list
	 *            A float array which should be joined.
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @return The joined String.
	 */
	static public String join(int[] list, String separator) {
		String txt = "";

		for (int t : list) {
			txt += t + separator;
		}

		return txt.substring(0, txt.length() - separator.length());
	}

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>.
	 * 
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @param elements
	 *            One or more elements that should be joined.
	 * @return The joined String.
	 */
	static public String join(String separator, Object... elements) {
		return StringTools.join(elements, separator);
	}

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>.
	 * 
	 * @param list
	 *            A float array which should be joined.
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @return The joined String.
	 */
	static public String join(Object[] list, String separator) {
		String txt = "";

		for (Object t : list) {
			txt += t + separator;
		}

		return txt.substring(0, txt.length() - separator.length());
	}

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>.
	 * 
	 * @param list
	 *            A float array which should be joined.
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @return The joined String.
	 */
	static public String join(ArrayList<String> list, String separator) {
		String txt = "";

		for (String t : list) {
			txt += t + separator;
		}

		return txt.substring(0, txt.length() - separator.length());
	}

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>. The elements of the list will be
	 * parsed to a String. This String will contain <b>d1</b> numbers before the
	 * point separator, <b>d2</b> numbers after the point separator and a sign.
	 * Empty spaces will be filled with zeroes and too many numbers will be cut.
	 * Example: <br>
	 * 
	 * <pre>
	 * float[] vals = { 3.4, -267.45, -23.246 };
	 * StringTools.joinAndFormat(vals, ",", 2, 2); // "+03.40,-67.45,-23.24"
	 * 
	 * </pre>
	 * 
	 * @param list
	 *            A float array which should be joined.
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @param d1
	 *            The number of numbers before the point.
	 * @param d2
	 *            The number of numbers after the point.
	 * @return The joined String.
	 */
	static public String joinAndFormat(float[] list, String separator, int d1, int d2) {
		String txt = "";

		for (float t : list) {
			txt += StringTools.nfs(t, d1, d2) + separator;
		}

		return txt.substring(0, txt.length() - separator.length());
	}

	/**
	 * Joins a list of elements to one single String. The elements of the list
	 * will be separated by <b>separator</b>. The elements of the list will be
	 * parsed to a String. This String will contain <b>digits</b> numbers and a
	 * sign. Empty spaces will be filled with zeroes and too many numbers will
	 * be cut. Example: <br>
	 * 
	 * <pre>
	 * int[] vals = { 3, 1999, -23 };
	 * StringTools.joinAndFormat(vals, ",", 3); // "+003,+999,-023"
	 * 
	 * </pre>
	 * 
	 * @param list
	 *            A float array which should be joined.
	 * @param separator
	 *            A String which will be used to separate the elements of the
	 *            input list.
	 * @param digits
	 *            The number of numbers for each list element.
	 * @return The joined String.
	 */
	static public String joinAndFormat(int[] list, String separator, int digits) {
		String txt = "";

		for (int t : list) {
			txt += StringTools.nf(t, digits) + separator;
		}

		return txt.substring(0, txt.length() - separator.length());
	}

	/**
	 * Will maybe be moved to StringTools. Puts escaped quotations marks around
	 * the input. Used for creating Strings representing JSON Objects.
	 * 
	 * @param txt
	 *            The input text.
	 * @return The input text with added quotations marks.
	 */
	public static String getStringEcp(String txt) {
		return "\"" + txt + "\"";
	}

	/**
	 * Will maybe be moved to StringTools. Creates an escaped key-array value
	 * pair (e.g. \"key\" : [\"val1\", \"val2\"]). Used for creating Strings
	 * representing JSON Objects.
	 * 
	 * @param key
	 *            The key of the key-value pair.
	 * @param values
	 *            A list of String values.
	 * @return A string containing the escaped key-array value pair.
	 */
	public static String getKeyValue(String key, ArrayList<String> values) {

		String txt = "";

		if (values != null && values.size() > 0) {
			for (String v : values) {
				txt += StringTools.getStringEcp(v) + ",";
			}

			txt = txt.substring(0, txt.length() - 1);
		}
		return StringTools.getStringEcp(key) + " : [" + txt + "]";
	}

	/**
	 * Will maybe be moved to StringTools. Creates an escaped key-array value
	 * pair (e.g. \"key\" : \"val\"). Used for creating Strings representing
	 * JSON Objects.
	 * 
	 * @param key
	 *            The key of the key-value pair.
	 * @param value
	 *            The value of the key-value pair.
	 * @param escapeValue
	 *            Defines if the value part should be escaped. Should be false,
	 *            if the value is already escaped or the value is a pre-formated
	 *            array-string.
	 * @return A string containing the escaped key-value pair.
	 */
	public static String getKeyValue(String key, String value, boolean escapeValue) {

		return StringTools.getStringEcp(key) + " : " + (escapeValue ? StringTools.getStringEcp(value) : value);
	}

	/**
	 * Will maybe be moved to StringTools. Creates an escaped key-array value
	 * pair (e.g. \"key\" : \"val\"). Used for creating Strings representing
	 * JSON Objects.
	 * 
	 * @param key
	 *            The key of the key-value pair.
	 * @param value
	 *            The value of the key-value pair.
	 * @return A string containing the escaped key-value pair.
	 */
	public static String getKeyValue(String key, String value) {

		return StringTools.getStringEcp(key) + " : " + StringTools.getStringEcp(value);
	}
}