//
// https://www.ramecera.it/myscrewdriver.html
// e-mail: screwdriver@ramecera.it
//
/* 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 */
package it.ramecera.salad.everyday;

import java.io.File;
import java.io.FilenameFilter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Pattern;
// import org.eclipse.jface.dialogs.MessageDialog;

import org.apache.log4j.Logger;

import it.ramecera.salad.file.FileBase;
import it.ramecera.salad.graphic.Placard;

/**
 * <p>
 * Various utility methods.
 * </p>
 * <p>
 * Company: Ramecera™ ​​<br>
 * Creation date: 2020-04-09<br>
 * Last updated: 2020-09-24S<br>
 * </p>
 * <p class = "history ">
 * Changes:<br>
 * </p>
 * 
 * @author M. Maglioni */

public class Mix {

	// CONSTANT
	/** 2 spaces */
	public final static String DOUBLEBLANK = "  ";

	/**
	 * <p>
	 * First make a trim. If the first character is a capital letter,
	 * this method converts it to lower case; otherwise it does nothing.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-06-20
	 * <p>
	 * Modifications:<br>
	 * </p>
	 * 
	 * @param g the complete path of file
	 * @return la lowercase string */
	public static String lowercaseFirstChar(final String g) {
		if (g == null) {
			return null;
		}
		String s = g.trim();
		if (s.equals("")) {
			return s;
		}
		char ini = s.charAt(0);
		if (ini > 64 & ini < 91) { // if it is capitalized
			String iniziale = s.substring(0, 1);
			String resto = s.substring(1);
			return iniziale.toLowerCase() + resto;
		} else {
			return s;
		}
	}

	/**
	 * <p>
	 * First make a trim. If the first character is an lowercase letter,
	 * this method converts it to uppercase; otherwise it does nothing.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-06-20
	 * <p>
	 * Modifications:<br>
	 * </p>
	 * 
	 * @param g the complete path of file
	 * @return la uppercase string */
	public static String uppercaseFirstChar(final String g) {
		if (g == null) {
			return null;
		}
		String s = g.trim();
		if (s.equals("")) {
			return s;
		}
		char ini = s.charAt(0);
		if (ini > 96 & ini < 123) { // if it is lowercase
			String iniziale = s.substring(0, 1);
			String resto = s.substring(1);
			return iniziale.toUpperCase() + resto;
		} else {
			return s;
		}
	}

	/**
	 * <p>
	 * Given a complete file path, it produces an array of 3 strings
	 * containing respectively: the path, the file, the character (slash
	 * or backslash) that separates the path from the file. Example:
	 * /monte/mare/stella.bmp produces: / monte / mare, stella.bmp, /.
	 * <br>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * <p>
	 * Modifications:<br>
	 * </p>
	 * 
	 * @param g the complete path of file
	 * @return the 3 elements produced */
	public static String[] separaPath(final String g) {
		String e[] = new String[3];
		if (g.indexOf(92) > -1) { // character 92 is the backslash
			e[2] = "\\";
		} else {
			e[2] = "/";
		}
		String h = g.replaceAll("\\x5c", "/");
		String[] d = h.split("\\x2f");
		e[1] = d[d.length - 1];
		if (g.equals(e[1])) {
			e[2] = "";
			e[0] = "";
		} else {
			e[0] = g.substring(0, g.length() - 1 - e[1].length());
		}
		return e;
	}

	/**
	 * <p>
	 * Given a complete path of files, it produces an array of 3 strings
	 * containing respectively: the path, the name of the file without
	 * extension and without final dot, the extension without initial
	 * dot. Example: /monte/mare/stella.bmp produces: / monte / mare,
	 * stella, bmp.<br>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param g the complete path of file
	 * @return the 3 elements produced */
	public static String[] analizzaPath(final String g) {
		String e[] = new String[3];
		String h = g.replaceAll("\\x5c", "/");// the hex 5c is the
											  // backslash
		String[] d = h.split("\\x2f");// hex 2f is slash
		e[1] = d[d.length - 1];
		if (g.equals(e[1])) {
			e[0] = "";
		} else {
			e[0] = g.substring(0, g.length() - 1 - e[1].length());
		}
		e[2] = estraiExtension(e[1]);
		if (e[2] == null) {
			e[2] = "";
		}
		e[1] = e[1].substring(0, e[1].length() - e[2].length() - 1);
		return e;
	}

	/**
	 * <p>
	 * It could have been an overload of the previous method, but the
	 * name was changed because only the type of return changes.
	 * <p>
	 * Creation date: 11 apr 2019<br>
	 * Last updated: 11 apr 2019<br>
	 * <p>
	 * Modifications:<br>
	 * </p>
	 * 
	 * @param file the complete path of file
	 * @return i 3 elements produced */
	public static FileBase analizzaPathBase(File file) {
		String e[] = analizzaPath(file.getPath());
		FileBase fb = new FileBase(e[0], e[1], e[2], 0);
		return fb;
	}

	/**
	 * <p>
	 * Given a string, it produces 3 different versions of the same:
	 * </p>
	 * <ul>
	 * <li>all lowercase</li>
	 * <li>all uppercase</li>
	 * <li>all words with initials capital</li>
	 * </ul>
	 * <p>
	 * The text is compacted to eliminate double spaces.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * </p>
	 * 
	 * @param s the phrase to convert
	 * @return the 3 elements produced */
	public static String[] like_A(final String s) {
		String s1 = compattaSpazi_B(s);
		String[] u = new String[3];
		if (s1.equals("")) {
			u[0] = "";
			u[1] = "";
			u[2] = "";
			return u;
		}
		u[0] = s1.toLowerCase();
		u[1] = s1.toUpperCase();
		String v[] = u[0].split(Candies.SPACE);
		String z = "";
		for (String t : v) {
			z += Candies.SPACE + t.substring(0, 1).toUpperCase() + t
					.substring(1);
		}
		u[2] = z.substring(1);
		return u;
	}

	/**
	 * <p>
	 * Extracts the bits that make up an integer. All the bits minus the
	 * last one, the one indicating the sign, are extracted; therefore,
	 * for a 32-bit integer, the 31 bits further left are extracted.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param i the number to be sent
	 * @return the array of bits */
	public static Boolean[] sbitta_A(final int i) {
		Boolean[] b = new Boolean[Integer.SIZE - 1];
		double p;
		int u;
		for (int j = 0; j < Integer.SIZE - 1; j++) {
			p = Math.pow(2, j);
			u = (int) Math.round(p);
			b[j] = Boolean.valueOf((i & u) == u);
		}
		return b;
	}

	/**
	 * <p>
	 * Creation of a sequence of identical characters in quantity q.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param c the character to be appended
	 * @param q the amount of spaces to be appended
	 * @return the string of q spaces */
	public static String piastrelle(final char c, final int q) {
		String sequenza = "", car = String.valueOf(c);
		for (int i = 0; i < q; i++)
			sequenza = sequenza.concat(car);
		return sequenza;
	}

	/**
	 * <p>
	 * Creation of a sequence of groups of identical characters in
	 * quantity q. It differs from the previous one in that it
	 * accumulates groups of characters instead of a single character.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param s the group of characters to be appended
	 * @param q the amount of spaces to be appended
	 * @return the string of q spaces */
	public static String piastrelle(final String s, final int q) {
		String sequenza = "";
		for (int i = 0; i < q; i++)
			sequenza = sequenza.concat(s);
		return sequenza;
	}

	/**
	 * <p>
	 * Calculation of an array of characters starting from its
	 * hexadecimal code. We speak of ordinary characters, that is,
	 * within the ASCII set.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param m character array to convert
	 * @return ordinary character array
	 * @throws ExactException occurs if the hexadecimal code is
	 *         incorrect */
	public static char[] daEsadAChar(char[] m)

			throws ExactException {

		if (m.length % 2 != 0)
			throw new ExactException(
					"The quantity of characrters is not an even number.");
		if (!Pattern.matches("\\p{XDigit}+", String.copyValueOf(m)))
			throw new ExactException(
					"Any characters not between 0 and f are present.");
		char[] ml = new char[m.length];
		int[] k = new int[m.length];
		char[] n = new char[m.length / 2];
		// I convert to lowercase
		for (int i = 0; i < m.length; i++) {
			if (Character.isDigit(m[i]))
				ml[i] = m[i];
			else
				ml[i] = Character.toLowerCase(m[i]);
		}
		// I convert each character into an integer
		for (int i = 0; i < m.length; i++) {
			if (ml[i] < 'a')
				k[i] = ml[i] - 48;
			else
				k[i] = ml[i] - 87;
		}
		// I calculate the true character
		for (int i = 0; i < m.length; i += 2) {
			n[i / 2] = (char) (k[i] * 16 + k[i + 1]);
		}
		return n;
	}

	/**
	 * <p>
	 * Calculation of an array of characters starting from its
	 * hexadecimal code. We speak of ordinary characters, that is,
	 * within the ASCII set.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m character array to convert
	 * @return ordinary character array
	 * @throws ExactException trigger if the hexadecimal code is
	 *         incorrect */
	public static byte[] daEsadAByte(byte[] m)

			throws ExactException {

		char v = 0;
		if (m.length % 2 != 0)
			throw new ExactException(
					"The quantity of characrters is not even: "
							+ m.length + ".");
		for (int j = 0; j < m.length; j++) {
			v = (char) (m[j]);
			if (!Pattern.matches("\\p{XDigit}+", Character.toString(
					v))) {
				throw new ExactException("At position " + j
						+ " any characters not between 0 and f are present: "
						+ v + " cioè " + m[j]);
			}
		}
		byte[] ml = new byte[m.length]; // the same input array
									    // convert
									    // lowercase
		int[] k = new int[m.length];
		byte[] n = new byte[m.length / 2];
		// I convert to lowercase
		for (int i = 0; i < m.length; i++) {
			v = (char) (m[i]);
			if (Character.isDigit(v))
				ml[i] = m[i];
			else
				ml[i] = (byte) ((Character.toLowerCase(v)) - 127);
		}
		// I convert each character into an integer
		for (int i = 0; i < m.length; i++) {
			if (ml[i] < -30) // -30 = character a
				k[i] = ml[i] + 79; // -79 = zero character
			else
				k[i] = ml[i] + 40; // the character W 87, distant 10
								   // positions from to
		}
		// I calculate the true character
		for (int i = 0; i < m.length; i += 2) {
			n[i / 2] = (byte) ((k[i] * 16 + k[i + 1]) - 127);
		}
		return n;
	}

	/**
	 * <p>
	 * Calculation of an array of characters starting from its
	 * hexadecimal code. We speak of Unicode characters, therefore 4
	 * hexadecimal characters for each character.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m character array to convert
	 * @return ordinary character array
	 * @throws ExactException occurs if the hexadecimal code is
	 *         incorrect */
	public static char[] daEsadACharUnicode(char[] m)
			throws ExactException {
		if (m.length % 4 != 0)
			throw new ExactException(
					"The quantity of characters is not a multiple of 4.");
		if (!Pattern.matches("\\p{XDigit}+", String.copyValueOf(m)))
			throw new ExactException(
					"Any characters not between 0 and f are present.");
		char[] ml = new char[m.length];
		int[] k = new int[m.length];
		char[] n = new char[m.length / 4];
		// I convert to lowercase
		for (int i = 0; i < m.length; i++) {
			if (Character.isDigit(m[i]))
				ml[i] = m[i];
			else
				ml[i] = Character.toLowerCase(m[i]);
		}
		// I convert each character into an integer
		for (int i = 0; i < m.length; i++) {
			if (ml[i] < 'a')
				k[i] = ml[i] - 48;
			else
				k[i] = ml[i] - 87;
		}
		// I calculate the true character
		for (int i = 0; i < m.length; i += 4) {
			n[i / 4] = (char) (k[i] * 4096 + k[i + 1] * 256 + k[i + 2]
					* 16 + k[i + 3]);
		}
		return n;
	}

	/**
	 * <p>
	 * Calculation of an array of hexadecimal codes starting from an
	 * array of ordinary characters, that is, within the ASCII set.
	 * Obviously the output is twice as long.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m character array to convert
	 * @return lowercase hexadecimal character array
	 * @see "prog. bigExport_1.1.0, data class of Export"
	 * @see "prog. bigExport_2.0.0, data class of DiExport"
	 * @since 1.2.2 */
	public static char[] daCharAdEsad(char[] m) {
		int[] k = new int[m.length];
		char[] n = new char[m.length * 2];
		char[] c = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'a', 'b', 'c', 'd', 'e', 'f' };
		for (int i = 0; i < m.length; i++)
			k[i] = m[i];
		for (int i = 0; i < m.length; i++) {
			n[i * 2] = c[k[i] / 16];
			n[i * 2 + 1] = c[k[i] % 16];
		}
		return n;
	}

	/**
	 * <p>
	 * Encrypting a string from a key. The encrypted output is further
	 * transformed into hexadecimal. As a result, the output is twice as
	 * long.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m character array to convert
	 * @param key encryption key
	 * @return encrypted character array
	 * @throws ExactException incorrect use */
	public static char[] crittaSemplice_A(char[] m, final String key)

			throws ExactException {

		if (m == null | key == null) {
			throw new ExactException("One or some given parameters"
					+ " are null.");
		}
		String chiave1 = key;
		while (chiave1.length() < m.length) {
			chiave1 += chiave1;
		}
		char[] z = new char[m.length];
		String chiave2 = chiave1.substring(0, m.length);
		char[] c = chiave2.toCharArray();
		for (int i = 0; i < z.length; i++)
			z[i] = (char) (m[i] ^ c[i]);
		return daCharAdEsad(z);
	}

	/**
	 * <p>
	 * Decryption of a string, to be coupled to what obtained with the
	 * crittaSemplice_A method. The string is first transformed from
	 * hexadecimal to ASCII, then decrypted with the same key with which
	 * it was encrypted. Obviously the output is half the length.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m character array to convert
	 * @param key encryption key
	 * @return encrypted character array
	 * @throws ExactException incorrect use */
	public static char[] decrittaSemplice_A(char[] m, final String key)

			throws ExactException {

		if (m == null | key == null) {
			throw new ExactException(
					"One or some given parameters are null.");
		}
		String chiave1 = key;
		if (m.length % 2 != 0) {
			throw new ExactException(
					"The quantity of characters to decript is not an even number.");
		}
		while (chiave1.length() < m.length / 2) {
			chiave1 += chiave1;
		}
		char[] z = new char[m.length / 2];
		char[] m1 = Mix.daEsadAChar(m);
		String chiave2 = chiave1.substring(0, z.length);
		char[] c = chiave2.toCharArray();
		for (int i = 0; i < z.length; i++)
			z[i] = (char) (m1[i] ^ c[i]);
		return z;
	}

	/**
	 * <p>
	 * Calculation of a 6-character array of the domain [A-Z0-9]
	 * starting from a long integer not greater than 36 raised to 6.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * 
	 * @param m integer long
	 * @return character array of the domain [A-Z0-9 ] */
	public static char[] daLong6Char(final long m) {
		long xm = m;
		int q = 0;
		long w = 0;
		char[] n = new char[6];
		char[] c = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
				'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
				'W', 'X', 'Y', 'Z' };
		for (int i = 5; i > -1; i--) {
			w = (long) Math.pow(36, i);
			q = (int) (xm / w);
			n[i] = c[q];
			xm -= q * w;
		}
		return n;
	}

	/**
	 * <p>
	 * Calculation of a 3-character array of the domain [A-Z0-9]
	 * starting from a long integer not exceeding 36 raised to 3.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * 
	 * @param m integer long
	 * @return character array of the domain [A-Z0-9 ]
	 * @since 2.0.0 */
	public static char[] daLong3Char(final long m) {
		long xm = m;
		int q = 0;
		long w = 0;
		char[] n = new char[3];
		char[] c = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
				'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
				'W', 'X', 'Y', 'Z' };
		for (int i = 2; i > -1; i--) {
			w = (long) Math.pow(36, i);
			q = (int) (xm / w);
			n[i] = c[q];
			xm -= q * w;
		}
		return n;
	}

	/**
	 * <p>
	 * Calculation of an array of 1 or 2 characters of the domain [A-Z]
	 * starting from an integer not greater than 701 (26 + 26 26 - 1).
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m number integer long
	 * @return domain character array [AZ] */
	public static char[] daLong2Char(final int m) {
		int xm = m;
		int q = 0;
		long w = 0;
		char[] n2 = new char[2];
		char[] n1 = new char[1];
		char[] c = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
				'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
				'V', 'W', 'X', 'Y', 'Z' };
		if (xm < 26) {
			n1[0] = c[xm];
			return n1;
		} else {
			xm -= 26;
			for (int i = 1; i > -1; i--) {
				w = (long) Math.pow(26, i);
				q = (int) (xm / w);
				n2[i] = c[q];
				xm -= q * w;
			}
			return n2;
		}
	}

	/**
	 * <p>
	 * Calculation of an array of hexadecimal codes starting from an
	 * array of Unicode characters.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param m character array to convert
	 * @return lowercase hexadecimal character array */
	public static char[] fromCharToEsadUnicode(char[] m) {
		int[] k = new int[m.length]; // I prepare an array of integers
									 // in
									 // help
									 // of the input array
		char[] n = new char[m.length * 4]; // I prepare the output
										   // array,
										   // long
										   // the quadruple
		char[] c = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'a', 'b', 'c', 'd', 'e', 'f' };
		for (int i = 0; i < m.length; i++)
			k[i] = m[i]; // I transform the input array into integers
		for (int i = 0; i < m.length; i++) {
			n[i * 4] = c[k[i] / 4096];
			n[i * 4 + 1] = c[(k[i] % 4096) / 256];
			n[i * 4 + 2] = c[(k[i] % 256) / 16];
			n[i * 4 + 3] = c[(k[i] % 16)];
		}
		return n;
	}

	/**
	 * <p>
	 * Work around the error that occurs when using the main main "args"
	 * argument.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param args the same array coming from the main.
	 * @return a null string or the first argument.
	 * @since 1.0.0 */
	public static String un_arg(String[] args) {
		if (args.length == 0) {
			return "";
		}
		return args[0];
	}

	/**
	 * <p>
	 * Simple routine to put two double angle quotes, before and after a
	 * string.
	 * </p>
	 * <p>
	 * creation date: 2020-03-10<br>
	 * 
	 * @param a the input string
	 * @return the string with the double angle quotes */
	final public static String dress_A(final String a) {
		String s = Candies.CAAP + a + Candies.CACH;
		return s;
	}

	/**
	 * <p>
	 * Simple routine to make sure that a path indication actually ends
	 * with slash or backslash. If not, add it.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * 10/04 08: added the trim
	 * 
	 * @param y the path to check
	 * @return the path complete with slash or backslash */
	public static String dress_C(final String y) {
		String s = y.trim();
		if (!s.endsWith("/") & !s.endsWith("\\"))
			s += System.getProperty("file.separator");
		return s;
	}

	/**
	 * <p>
	 * Simple routine to make sure that a path indication actually ends
	 * with slash. If not, add it.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 
	 * @param y the path to check
	 * @return the complete path of slash */
	public static String dress_CU(final String y) {
		String s = y.trim();
		if (!s.endsWith("/") & !s.endsWith("\\"))
			s += "/";
		return s;
	}

	/**
	 * <p>
	 * Simple routine to make sure that the indication of a path
	 * actually ends with slash or backslash, but with different
	 * criteria compared to vesti_CU. If not, add it.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * 10/04 08: added the trim
	 * 
	 * @param y the path to be checked
	 * @return the path complete with slash or backslash */
	public static String dress_D(final String y) {
		String s = y.trim();
		// if there is at least one backslash
		if (s.indexOf(92) > -1 & !s.endsWith("\\")) {
			s += "\\";
			// if there is at least one slash
		} else if (s.indexOf(47) > -1 & !s.endsWith("/")) {
			s += "/";
		} else if (!s.endsWith("/") & !s.endsWith("\\")) {
			s += System.getProperty("file.separator");
		}
		return s;
	}

	/**
	 * <p>
	 * Simple routine to delay code execution.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param thousandths duration of the delay in thousandths of a
	 *        second */
	public static void ritardo0(final long thousandths) {
		long i = System.currentTimeMillis();
		while (System.currentTimeMillis() < (i + thousandths)) {
		}
		;
	}

	/**
	 * <p>
	 * Routine to count the occurrence of a certain character in a
	 * string. It is a faster method than transforming the whole string
	 * into many characters and then counting.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param s the string to be examined
	 * @param t the character to be examined search for
	 * @return how many times */
	public static int charQ(final String s, final char t) {
		int i = 0, j = 0;
		if (s == null)
			return i;
		int tn = t;
		j = s.indexOf(tn, j);
		while (j != -1) {
			i++;
			j = s.indexOf(tn, j + 1);
		}
		return i;
	}

	/**
	 * <p>
	 * Routine for finding the last occurrence of a given character in a
	 * string.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param s the string to be examined
	 * @param t the character to be search for
	 * @return how many times */
	public static int ultimaPosizione(final String s, final char t) {
		int j = 0, jW = -1;
		if (s == null)
			return -1;
		int tn = t;
		j = s.indexOf(tn, j);
		while (j != -1) {
			jW = j;
			j = s.indexOf(tn, j + 1);
		}
		return jW;
	}

	/**
	 * <p>
	 * Routine to extract the extension from a file name. Return null if
	 * there is no extension.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * <p>
	 * Modifications: 2020-04-09: replaced the last return from return
	 * null to return ""<br>
	 * 
	 * @param g the file name to be analyzed
	 * @return how many times */
	public static String estraiExtension(final String g) {
		/* split according to the point character */
		String u[] = g.split("\\x2e");
		String e = null;
		if (u.length == 1) {
			return null;
		} else {
			e = u[u.length - 1].toLowerCase();
		}
		/* if the extension contains neither slash nor backslash, it is
		 * OK */
		if (e.indexOf(47) == -1 & e.indexOf(92) == -1) {
			return e;
		} else { /* otherwise it is not an extension */
			return "";
		}
	}

	/**
	 * <p>
	 * Routine to find the last occurrence of a given string in a
	 * string.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param s the string to be examined
	 * @param t the string to be examined search for
	 * @return how many times */
	public static int ultimaPosizione(final String s, final String t) {
		int j = 0, jW = -1;
		if (s == null)
			return -1;
		j = s.indexOf(t, j);
		while (j != -1) {
			jW = j;
			j = s.indexOf(t, j + 1);
		}
		return jW;
	}

	/**
	 * <p>
	 * Routine for counting the occurrence of a given substring in a
	 * string.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param tutto string to be examined
	 * @param parte substring from search for
	 * @return how many times */
	public static int stringheQ(final String tutto,
			final String parte) {
		int i = 0, j = 0;
		if (tutto == null)
			return i;
		String p1 = parte;
		int pL = parte.length();
		j = tutto.indexOf(p1, j);
		while (j != -1) {
			i++;
			j = tutto.indexOf(p1, j + pL);
		}
		return i;
	}

	/**
	 * <p>
	 * Routine to verify that the content of a string is an integer,
	 * compatible with the int type. Warning, using Pattern.matches ("\\
	 * d +", xxxxx) I would also verify the absence of the + or - sign.
	 * I don't need to.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 10/11 / 08: added trim on the input parameter 2020-04-09: null
	 * possibility provided
	 * </p>
	 * 
	 * @param s string to be verified
	 * @return true or false if the content is numeric or not
	 * @since 1.2.2 */
	public static boolean verificaIntero(final String s) {
		int m;
		try {
			m = Integer.parseInt(s.trim());
			/* just to not have the hassle of the warning: the local
			 * variable is never read */
			if ((m + 1) == (m + 1)) {
				m = 0;
			}
			return true;
		} catch (NumberFormatException e) {
			return false;
		} catch (NullPointerException e) {
			return false;
		}
	}

	/**
	 * <p>
	 * Routine to verify that the content of a string is an integer,
	 * compatible with the long type. Warning, using Pattern.matches
	 * ("\\ d +", xxxxx) I would also verify the absence of the + or -
	 * sign. I don't need to.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 10/11 / 08: added the trim on the input parameter 2020-04-09:
	 * null possibility provided
	 * </p>
	 * 
	 * @param s string to be verified
	 * @return true or false if the content is numeric or not
	 * @since 1.2.2 */
	public static boolean verificaLong(final String s) {
		long m;
		try {
			m = Long.parseLong(s.trim());
			/* just to not have the hassle of the warning: the local
			 * variable is never read */
			if ((m + 1) == (m + 1)) {
				m = 0;
			}
			return true;
		} catch (NumberFormatException e) {
			return false;
		} catch (NullPointerException e) {
			return false;
		}
	}

	/** Routine to verify that the content of a string is an integer,
	 * compatible with the short type.
	 * 
	 * @param s string to check
	 * @return true or false if the content is numeric or not
	 * @since 1.2.2 */
	public static boolean verificaShort(final String s) {
		int m;
		try {
			m = Short.parseShort(s);
			if ((m + 1) == (m + 1)) {
				/* just to not have the hassle of the warning: the local
				 * variable is never read */
				m = 0;
			}
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	/**
	 * <p>
	 * Implementation of the accept method for the FilenameFilter
	 * interface.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @return a new object FilenameFilter
	 * @param filter the pattern to be compared, to implement
	 *        filtering */
	public static final FilenameFilter fileFilter(final String filter) {
		final String s = filter;
		return new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				String path = new File(name).getName();
				return Pattern.matches(s, path);
			}
		};
	}

	/**
	 * <p>
	 * Implementation of the accept method for the FilenameFilter
	 * interface.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @return a new FilenameFilter
	 * @since 1.2.1 object */
	public static final FilenameFilter filterDirectory() {
		return new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return new File(dress_CU(dir.getPath()) + name)
						.isDirectory();
			}
		};
	}

	/**
	 * <p>
	 * Implementation of the accept method for the FilenameFilter
	 * interface.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @param filter filter for searching
	 * @return a new FilenameFilter object */
	public static final FilenameFilter filtroDirectory(
			final String filter) {
		final String s = filter;
		return new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				File file = new File(dress_CU(dir.getPath()) + name);
				String path = file.getName();
				return file.isDirectory() & Pattern.matches(s, path);
			}
		};
	}

	/**
	 * <p>
	 * Convenience for checking the nullity of a string.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @return true if the string is a null object or an empty string
	 * @param s the string to be checked */
	public static final boolean isNothing(final String s) {
		return s == null || s.equals("");
	}

	/**
	 * <p>
	 * If it is a color of those expected for CSS.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @return true If the color to be checked is a color of those
	 *         provided for the CSS
	 * @param s string to evaluate */
	public static final boolean isCssColor(final String s) {
		String t = s.toLowerCase();
		int i = 0;
		for (; i < Universal.cssColorE.length; i++) {
			if (t.equals(Universal.cssColorE[i].toLowerCase()))
				break;
		}
		return i < Universal.cssColorE.length;
	}

	/**
	 * <p>
	 * Compact a phrase (string) containing more than one blank between
	 * words in a phrase containing individual blanks. An alternative
	 * algorithm for obtaining an identical result is found in
	 * Strings.compatta_A (String).<br>
	 * Ex: "___John__goes_to____school___"<br>
	 * becomes: "John goes to school"
	 * </p>
	 * <p>
	 * Deprecated 2013- 08-29 because it is too slow, replaced with
	 * it.ramecera.salad.everyday.Strings.compatta_A.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 2020-04-09: added final to parameter a, and slightly modified the
	 * algorithm<br>
	 * 2020-04-09: added trim<br>
	 * </p>
	 * 
	 * @param a the string to be compacted
	 * @return the compacted string */
	public static String compactingSpaces_A(final String a) {
		if (a == null)
			return null;
		int j;
		String b = a.trim();
		/* algorithm: all look for a double blank, then glue the two
		 * substrings so that it becomes a single blank; cycle until
		 * there are no more */
		j = b.lastIndexOf(DOUBLEBLANK, b.length());
		while (j != -1) {
			b = b.substring(0, j) + b.substring(j + 1);
			j = b.lastIndexOf(DOUBLEBLANK, j - 1);
		}
		return b.trim();
	}

	/** Transform any empty string into a null string.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * 
	 * @param s the string to be tested
	 * @return the resulting string
	 * @since 1.2.2 */
	public static String stringaNulla(final String s) {
		if (s != null && s.equals(""))
			return null;
		else
			return s;
	}

	/** Transform any null string into an empty string.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param s the string to be tested
	 * @return the resulting string
	 * @since 1.2.2 */
	public static String nonNullo(final String s) {
		if (s == null)
			return "";
		else
			return s;
	}

	/** Turn any null string into a zero.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * 2020-04-09: changed the time with the or double
	 * </p>
	 * 
	 * @param s the string to be tested
	 * @return the resulting string
	 * @since 1.3.0 */
	public static int nonNulloInt(final String s) {
		if (s == null || !verificaIntero(s))
			return 0;
		else
			return Integer.parseInt(s);
	}

	/** Cut the first n characters of a string, and if the string is
	 * shorter this method does nothing: it just returns the string.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param s the string to be cut
	 * @param i how many characters you want to cut
	 * @return the resulting string */
	public static String taglia(final String s, final int i) {
		if (s == null)
			return "";
		if (s.length() > i)
			return s.substring(0, i);
		else
			return s;
	}

	/**
	 * <p>
	 * Delete n characters at the bottom of a string, if they coincide
	 * with the string supplied to the second parameter.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * 
	 * @param s the string to be shortened
	 * @param tail the string to be compared with the tail of the string
	 *        s
	 * @return the resulting string
	 * @since 1.3.0, SVutensiliJ4_1.3.0 */
	public static String tagliaLaCoda(final String s,
			final String tail) {
		if (s != null && s.endsWith(tail))
			return s.substring(0, s.length() - tail.length());
		else
			return s;
	}

	/** Latin numeral adverbs */
	//
	// public static String [] adverbNumerale = {
	// "", "semel", "bis", "ter", "quater", "quinquies", "sexies",
	// "F"
	// "octies", "novies",
	// "decies", "undecies", "duodecies", "ter decies", "quater decies",
	// "quindecies", "sedecies",
	// "septies decies", "octies decies", "novies decies",
	// "vicies", "vicies semel", "vicies bis", "vicies ter",
	// "vicies quater",
	// "vicies quinquies",
	// "vicies sexies", "vicies septies", "duodetricies", "undetricies",
	// "tricies", "tricies semel", "tricies bis", "tricies ter",
	// "tricies quater",
	// "tricies quinquies", "tricies sexies", "tricies septies",
	// "Duodequadragies"
	// "undequadragies", "quadragies", "quadragies semel", "quadragies
	// BIS",
	// "quadragies ter",
	// "quadragies quater", "quadragies quinquies", "quadragies sexies",
	// "quadragies septies",
	// "duodequinquagies", "undequinquagies"
	// };
	// they are different: 13, 14, 16, 18, 19
	public static String[] avverbioNumerale = { "", "semel", "bis",
			"ter", "quater", "quinquies", "sexies", "septies", "octies",
			"novies", "decies", "undecies", "duodecies", "terdecies",
			"quaterdecies", "quindecies", "sex decies",
			"septies decies", "duodevicies", "undevicies", "vicies",
			"vicies semel", "vicies bis", "vicies ter", "vicies quater",
			"vicies quinquies", "vicies sexies", "vicies septies",
			"duodetricies", "undetricies", "tricies", "tricies semel",
			"tricies bis", "tricies ter", "tricies quater",
			"tricies quinquies", "tricies sexies", "tricies septies",
			"duodequadragies", "undequadragies", "quadragies",
			"quadragies semel", "quadragies bis", "quadragies ter",
			"quadragies quater", "quadragies quinquies",
			"quadragies sexies", "quadragies septies",
			"duodequinquagies", "undequinquagies" };

	/**
	 * <p>
	 * Cleans a phrase (string) clean from the characters TAB, CR, LF,
	 * FF, VT and compacts everything.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * 2020-04-09: the replacement must not be with a null string but
	 * with a space character<br>
	 * </p>
	 * 
	 * @param a the string to be compacted
	 * @return the compacted string
	 * @since 1.4.0, toolsJ4_2.0.0 */
	@Deprecated
	public static String compattaSpazi_B(final String a) {
		if (a == null)
			return null;
		String t = a.replaceAll("[\\t\\n\\x0B\\f\\r]", " "); // 2020-04-09
		return compactingSpaces_A(t);
	}

	/**
	 * <p>
	 * Closes multiple statements and related connection.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @param statement the array of statements of the connection to the
	 *        DB
	 * @param connection the connection to the DB
	 * @since salad_2.0.0 */
	public static void collapse(Statement[] statement,
			Connection connection) {
		try {
			for (int i = 0; i < statement.length; i++) {
				if (statement[i] != null)
					statement[i].close();
			}
		} catch (SQLException e0) {
		}
		try {
			if (connection != null)
				connection.close();
		} catch (SQLException e1) {
		}
	}

	/** Closes multiple statements and related connection.
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Changes:<br>
	 * </p>
	 * 
	 * @param statement the statement of the connection to the DB
	 * @param connection the connection to the DB
	 * @since salad_2.0.0 */
	public static void collapse(Statement statement,
			Connection connection) {
		try {
			if (statement != null)
				statement.close();
			if (connection != null)
				connection.close();
		} catch (SQLException e1) {
		}
	}

	/**
	 * <p>
	 * Externation of a message, exposes a sign and writes it on the
	 * sysout.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09
	 * </p>
	 * <p>
	 * Modifications:<br>
	 * 10/01 / 11: facilitation of braces introduced instead of
	 * corporals<br>
	 * </p>
	 * 
	 * @param m the message */
	public static void disclosing(final String m) {
		/* x7d is the closing brace */
		String m0 = m.replaceAll("\\x7d", "»");
		/* x7b is the opening brace */
		String m1 = m0.replaceAll("\\x7b", "«");
		System.out.println("Placard: " + m1);
		new Placard(null, m1, "Warning");
	}

	/**
	 * <p>
	 * Routine for externalizing an error. There is no extension.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * <p>
	 * Changes:
	 * </p>
	 * 
	 * @param m my message
	 * @param t message title
	 * @param logger obvious */
	static public void discloseError(final String m, final String t,
			Logger logger) {
		/* x7d is the closing brace */
		String m0 = m.replaceAll("\\x7d", "»");
		/* x7b is the opening brace */
		String m1 = m0.replaceAll("\\x7b", "«");
		new Placard(null, m1, t);
		logger.error(t + ": " + m1);
	}

	/**
	 * <p>
	 * Routine for externalizing an error. There is no extension.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * <p>
	 * Changes:
	 * </p>
	 * 
	 * @param m my message
	 * @param t message title
	 * @param logger obvious */
	static public void discloseInfo(final String m, final String t,
			Logger logger) {
		/* x7d is the closing brace */
		String m0 = m.replaceAll("\\x7d", "»");
		/* x7b is the opening brace */
		String m1 = m0.replaceAll("\\x7b", "«");
		new Placard(null, m1, t);
		logger.info(t + ": " + m1);
	}

	/**
	 * <p>
	 * Routine for the externalization of a warning. There is no
	 * extension.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * Last updated: 2020-04-09<br>
	 * </p>
	 * <p>
	 * Changes:
	 * </p>
	 * 
	 * @param m my message
	 * @param t message title
	 * @param logger obvious */
	static public void discloseWarning(final String m, final String t,
			Logger logger) {
		/* x7d is the closing brace */
		String m0 = m.replaceAll("\\x7d", "»");
		/* x7b is the opening brace */
		String m1 = m0.replaceAll("\\x7b", "«");
		new Placard(null, m1, t);
		logger.warn(t + ": " + m1);
	}

	/**
	 * <p>
	 * Method to switch from a software version in the form 3, 4.2, or
	 * 2.0.11 to the form 3000000, 4002000, 2000011.
	 * </p>
	 * <p>
	 * Creation date: 2020-04-09<br>
	 * data last modification: 2020-04-09
	 * </p>
	 * 
	 * @param x the string indicating the version
	 * @param message the message to be displayed in case of
	 *        irregularity
	 * @param code error code
	 * @return the number representing the absolute version
	 * @throws ExactException ordinary exception */
	public static int absoluteVersion(final String x,
			final String message, final int code)

			throws ExactException {

		int sostanza = 0;
		ExactException ee = new ExactException();
		/* if a dash is present, only what is left of the dash is taken
		 * into account; if it is not present, what is there is worth;
		 * the possible presence of an alphabetical string in the queue
		 * is not considered */
		String g[] = x.split("\\x2d");
		/* is divided into substrings by adopting the dot as a
		 * separator */
		String h[] = g[0].split("\\x2e");
		/* the possible presence of an alphabetical string in the queue
		 * is not considered */
		if (h.length == 1 && h[0].matches("\\d") || (h.length == 2
				&& h[0].matches("\\d+") && h[1].matches(
						"\\p{Alpha}+"))) {
			sostanza = Integer.valueOf(h[0]) * 1000000;
		} else if (h.length == 2 && h[0].matches("\\d+") && h[1]
				.matches("\\d+")) {
			sostanza = Integer.valueOf(h[0]) * 1000000 + Integer
					.valueOf(h[1]) * 1000;
		} else if (h.length == 3 && h[0].matches("\\d+") && h[1]
				.matches("\\d+") && h[2].matches("\\p{Upper}+")) {
			sostanza = Integer.valueOf(h[0]) * 1000000 + Integer
					.valueOf(h[1]) * 1000;
		} else if (h.length == 3 && h[0].matches("\\d+") && h[1]
				.matches("\\d+") && h[2].matches("\\d+")) {
			sostanza = Integer.valueOf(h[0]) * 1000000 + Integer
					.valueOf(h[1]) * 1000 + Integer.valueOf(h[2]);
		} else if (h.length == 4 && h[0].matches("\\d+") && h[1]
				.matches("\\d+") && h[2].matches("\\d+") && h[3]
						.matches("\\p{Alpha}+")) {
			sostanza = Integer.valueOf(h[0]) * 1000000 + Integer
					.valueOf(h[1]) * 1000 + Integer.valueOf(h[2]);
		} else {
			ee.code = code;
			ee.datum = message;
			throw ee;
		}
		return sostanza;
	}

	/**
	 * <p>
	 * Creation date: 2020-05-29<br>
	 * Last updated: 2020-05-29<br>
	 * Class: Mix
	 * 
	 * @author M. Maglioni
	 *         <p>
	 *         Description: it trasnform the format of a version from
	 *         string n.n.n to an integer, base is 1000. Example: 3.5.1
	 *         becomes 3005001.
	 *         </p>
	 * @param v the version formatted n.n.n
	 * @return the version as an integer */
	public static Integer versionFormat_A(final String v) {
		String[] x = v.split("\\x2e");
		int xd = x.length;
		switch (xd) {
		case 1:
			if (x[0].matches("\\d{1,3}")) {
				return Integer.valueOf(x[0]) * 1000000;
			} else {
				return null;
			}
		case 2:
			if (x[0].matches("\\d{1,3}") & x[1].matches("\\d{1,3}")) {
				return Integer.valueOf(x[0]) * 1000000 + Integer
						.valueOf(x[1]) * 1000;
			} else {
				return null;
			}
		case 3:
			if (x[0].matches("\\d{1,3}") & x[1].matches("\\d{1,3}")
					& x[2].matches("\\d{1,3}")) {
				return Integer.valueOf(x[0]) * 1000000 + Integer
						.valueOf(x[1]) * 1000 + Integer.valueOf(x[2]);
			} else {
				return null;
			}
		default:
			return null;
		}
	}
}
