package com.ejie.ad74a.util.comun;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * UtilString para todas las utilidades que tengas que ver con String
 * 
 * @author GFI
 * 
 */
public final class Utilidades {
	private static final Logger LOGGER = LoggerFactory.getLogger(Utilidades.class);

	/**
	 * Constructor de UtilString
	 */
	private Utilidades() {
	}

	// Constantes isValidNif
	private static final int TAM_NIF = 9;
	private static final String LETRAS_NIF = "TRWAGMYFPDXBNJZSQVHLCKE";
	private static final int NUM_LETRAS_NIF = 23;
	private static final int POSICION_LETRA_NIF = 8;

	/**
	 * Devuelve true en caso de que la cadena sea:
	 * <li><b>null</b></li>
	 * <li><b>length == 0</b></li>.<br>
	 * 
	 * @param cadena String campo a revisar si es vacío
	 * @return isEmpty Boolean
	 */
	public static Boolean isEmpty(String cadena) {
		return cadena == null || cadena.trim().length() == 0;
	}

	/**
	 * Devuelve true en caso de que la lista sea:
	 * <li><b>null</b></li>
	 * <li><b>length == 0</b></li>.<br>
	 * 
	 * @param lista {@link List<?>}
	 * @return {@link boolean}
	 */
	public static Boolean isEmptyList(List<?> lista) {
		return lista == null || lista.isEmpty();
	}

	/**
	 * 
	 * @param codigo
	 * @return
	 */
	public static Boolean isEmptyNumber(Long codigo) {
		return codigo == null || codigo == 0;
	}

	/**
	 * 
	 * @param codigo
	 * @return
	 */
	public static Boolean isEmptyNumber(int codigo) {
		return codigo == 0;
	}

	/**
	 * comprueba si blanco o null
	 * 
	 * @param s String
	 * @return boolean
	 */
	public static boolean esBlancoNulo(String s) {
		return (s == null || "".equals(s));
	}

	public static boolean esNulo(Object o) {
		return (o == null);
	}

	/**
	 * Parsea un string a Integer. Si es null devuelve 0
	 * 
	 * @param s String
	 * @return Integer
	 */
	public static Integer getIntegerToString(String s) {

		return (null != s && !s.equalsIgnoreCase("")) ? Integer.valueOf(s) : new Integer(0);

	}

	/**
	 * Devuelve un String con el número que contiene la cadena recibida. Retorna
	 * null si no es un String.
	 * 
	 * @param integerInteger Integer numero a formatear
	 * @return integerInteger String
	 */
	public static String getStringFromInteger(Integer integerInteger) {
		return integerInteger != null ? integerInteger.toString() : null;
	}

	/**
	 * Parsea un string a Long
	 * 
	 * @param s String
	 * @return Integer
	 */
	public static Long getLongToString(String s) {

		try {
			return null != s ? Long.valueOf(s) : null;
		} catch (Exception e) {
			return null;
		}

	}

	/**
	 * Validar email.
	 * 
	 * emailStr String boolean
	 *
	 * @param emailStr the email str
	 * @return true, if successful
	 */
	public static boolean validarEmail(String emailStr) {

		Pattern VALID_EMAIL_ADDRESS_REGEX = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$",
				Pattern.CASE_INSENSITIVE);

		Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailStr);
		return matcher.find();
	}

	/**
	 * Validar nif.
	 * 
	 * nifStr String boolean
	 *
	 * @param nifStr the nif str
	 * @return true, if successful
	 */
	public static boolean isValidNif(String nifStr) {
		Utilidades.LOGGER.trace("isValidNif {}", nifStr);
		boolean resultado = false;
		try {
			String nif = nifStr.toUpperCase();
			if (nif.startsWith("T")) {
				resultado = (nif.length() <= Integer.valueOf(Utilidades.TAM_NIF));
			} else {
				if (nif.length() == Utilidades.TAM_NIF) {
					if (nif.startsWith("X")) {
						nif = Utilidades.concat("0", nif.substring(1));
					} else if (nif.startsWith("Y")) {
						nif = Utilidades.concat("1", nif.substring(1));
					} else if (nif.startsWith("Z")) {
						nif = Utilidades.concat("2", nif.substring(1));
					}
					if (nif.matches("[0-9]{8}[" + Utilidades.LETRAS_NIF + "]")) {
						int dni = Integer.parseInt(nif.substring(0, Utilidades.POSICION_LETRA_NIF));
						char letraCalculada = Utilidades.LETRAS_NIF.charAt(dni % Utilidades.NUM_LETRAS_NIF);
						if (letraCalculada == nif.charAt(Utilidades.POSICION_LETRA_NIF)) {
							resultado = true;
						}
					}
				} else {
					resultado = false;
				}
			}
		} catch (Exception e) {
			resultado = false;
		}

		return resultado;
	}

	/**
	 * Devuelve true en caso de que la cadena represente un eMail
	 * 
	 * @param str {@link String}
	 * @return {@link boolean}
	 */
	public static boolean isValidNie(String str) {
		Utilidades.LOGGER.trace("isValidNie {}", str);
		boolean resultado = false;
		try {
			String nie = str.toUpperCase();

			// Comprobar si empieza con una letra valida
			if (nie.startsWith("X") || nie.startsWith("Y") || nie.startsWith("Z")) {
				resultado = isValidDni(nie.replace("X", "0").replace("Y", "1").replace("Z", "2"));
			} else {
				resultado = false;
			}
		} catch (Exception e) {
			resultado = false;
		}

		return resultado;
	}

	/**
	 * Devuelve true en caso de que la cadena represente un eMail
	 * 
	 * @param str {@link String}
	 * @return {@link boolean}
	 */
	public static boolean isValidDni(String str) {
		Utilidades.LOGGER.trace("isValidDni {}", str);
		boolean resultado = false;
		String dni = str.toUpperCase();
		// Comprobar si empieza con un numero (digito numerico)
		if (Character.isDigit(dni.charAt(0))) {
			// if (dni.startsWith("X") || dni.startsWith("Y") || dni.startsWith("Z")) {
			resultado = Utilidades.isValidNif(dni);
		} else {
			resultado = false;
		}

		return resultado;
	}

	/**
	 * Metodo que obtiene una cadena con los parámetros recibidos
	 * 
	 * @param str {@link String[]}
	 * @return {@link String}
	 */
	public static String concat(String... str) {
		StringBuilder resultado = new StringBuilder();
		for (String string : str) {
			resultado.append(string);
		}
		return resultado.toString();
	}

	public static String getLabelFromResource(String baseName, String code, Locale locale) {

		ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
		source.setBasename(baseName);
		source.setCacheSeconds(1);
		source.setFallbackToSystemLocale(false);
		source.setDefaultEncoding("UTF-8");
		// hay procesos programados que al ejecutarse el locale
		// LocaleContextHolder.getLocale() te coge el en_US
		if (locale.equals(Locale.US)) {
			locale = new Locale("es");
		}
		String desc = source.getMessage(code, null, locale);
		return desc;
	}

	public static String getLabelFromResourceWithParams(String baseName, String code, Locale locale, Object[] params) {

		ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
		source.setBasename(baseName);
		source.setCacheSeconds(1);
		source.setFallbackToSystemLocale(false);
		source.setDefaultEncoding("UTF-8");
		// hay procesos programados que al ejecutarse el locale
		// LocaleContextHolder.getLocale() te coge el en_US
		if (locale.equals(Locale.US)) {
			locale = new Locale("es");
		}
		String desc = source.getMessage(code, params, locale);
		return desc;
	}

	/**
	 * Devuelve el string pasado con el Translate(UPPER()))) pero en java
	 * 
	 * @param texto String
	 * @return String
	 */
	public static String upperTranslateString(String texto) {
		return (texto == null || texto.trim().length() == 0) ? texto
				: texto.toUpperCase().replaceAll("\u00c1", "A").replaceAll("\u00c9", "E").replaceAll("\u00cd", "I")
						.replaceAll("\u00d3", "O").replaceAll("\u00da", "U");
	}

	/**
	 * Devuelve true si la cadena está vacía o si tiene una longitud inferior a la
	 * pasada por parámetro
	 * 
	 * @param cadena   String cadena a revisar si tiene la longitud correcta
	 * @param longitud int, longitud a validar
	 * @return Boolean true - si la cadena está vacía o la longitud es inferior
	 */
	public static boolean validarLongitud(String cadena, int longitud) {
		return ((!Utilidades.isEmpty(cadena) && cadena.length() <= longitud) || (Utilidades.isEmpty(cadena)));
	}

	/**
	 * Devuelve true si la cadena tiene la misma longitud que la pasada por
	 * parámetro
	 * 
	 * @param cadena   String cadena a revisar si tiene la longitud correcta
	 * @param longitud int, longitud a validar
	 * @return Boolean true - si la cadena está vacía o la longitud es inferior
	 */
	public static boolean validarLongitudExacta(String cadena, int longitud) {
		return (!Utilidades.isEmpty(cadena) && cadena.length() == longitud);
	}

	/**
	 * Devuelve true si el valor esta comprendido entre los numeros desde hasta
	 * parámetro
	 * 
	 * @param numDesde int para validar el valor minimo del número
	 * @param numHasta int, numero maximo permitido para valorar el número
	 * @param numero   int, numero a validar
	 * @return Boolean true - si el numero a validar esta fuera del rango
	 */
	public static boolean validarRango(int numDesde, int numHasta, int numero) {
		return (numero >= numDesde && numero <= numHasta);
	}

	public static int getLength(String string) {
		if (!Utilidades.esBlancoNulo(string)) {
			return string.length();
		} else {
			return 0;
		}
	}

	public static String listToJsonArray(List<?> lista) {
		try {
			final StringWriter sw = new StringWriter();
			final ObjectMapper mapper = new ObjectMapper();

			mapper.writeValue(sw, lista);

			String listString = sw.toString();
			sw.close();
			return listString;
		} catch (IOException e) {
			Utilidades.LOGGER.error("Error al parsear el array a string");
			return null;
		}
	}

	public static BigDecimal monedaToBD(String moneda) {

		String monedaTransf = (moneda == null) ? null : moneda.replaceAll("[^\\.,\\d]*", "").replace(",", ".");
		if (StringUtils.isBlank(monedaTransf)) {// Formato incorrecto
			return null;
		}
		return new BigDecimal(monedaTransf.trim());

	}

	public static String BDtoMonedaNDecimales(BigDecimal moneda, Integer nDecimales) {
		if (moneda == null) {
			return null;
		}
		NumberFormat nf = NumberFormat.getCurrencyInstance(new Locale("es", "ES"));
		nf.setMaximumFractionDigits(nDecimales);
		return nf.format(moneda);
	}

	public static String BDtoMoneda(BigDecimal moneda) {
		if (moneda == null) {
			return null;
		}

		return NumberFormat.getCurrencyInstance(new Locale("es", "ES")).format(moneda);
	}

	public static String BDto2DecimalMoneda(Double expresion) {
		if (expresion == null) {
			return null;
		}

		return NumberFormat.getCurrencyInstance(new Locale("es", "ES")).format(expresion);
	}

	public static boolean validarPasaporte(String pasaporte) {

		String patronPasaporte = "^[A-Za-z0-9]{9}$";

		Pattern pattern = Pattern.compile(patronPasaporte);
		Matcher matcher = pattern.matcher(pasaporte);

		return matcher.matches();
	}

	/**
	 * Si el string no es nulo o vacío, devuelve el prefijo concatenado al string.
	 * Si es nulo devuelve <code>""</code>
	 * 
	 * @param string
	 * @return
	 */
	public static String stringWithPrefix(String string, String prefix) {
		StringBuilder result = new StringBuilder();
		if (StringUtils.isNotBlank(string)) {
			result.append(prefix).append(string);
		}
		return result.toString();
	}

	/**
	 * Si el string no es nulo o vacío, devuelve el string concatenado al sufijo. Si
	 * es nulo devuelve <code>""</code>
	 * 
	 * @param string
	 * @return
	 */
	public static String stringWithSuffix(String string, String suffix) {
		StringBuilder result = new StringBuilder();
		if (StringUtils.isNotBlank(string)) {
			result.append(string).append(suffix);
		}
		return result.toString();
	}

	/**
	 * Si la cadena es nula se convierte a cadena vacia.
	 *
	 * @param cadena the cadena
	 * @return the string
	 */
	public static String convertirSiNullACadVacia(String cadena) {
		if (cadena == null) {
			return "";
		} else {
			return cadena;
		}

	}
}
