package com.ejie.y42b.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;

import com.ejie.y42b.constantes.Y42bAgendaConstantes;

/**
 * 
 *  
 * 
 */
public class Y42bUtils {
	private static Y42bUtils INSTANCE = null;
	private static final int posCIF = 23;

	private static final Logger logger = LoggerFactory
			.getLogger(Y42bUtils.class);

	// Private constructor suppresses
	/**
     * 
     */
	private Y42bUtils() {

	}

	// creador sincronizado para protegerse de posibles problemas multi-hilo
	// otra prueba para evitar instanciación múltiple
	/**
     * 
     */
	private synchronized static void createInstance() {
		if (Y42bUtils.INSTANCE == null) {
			Y42bUtils.INSTANCE = new Y42bUtils();
		}
	}

	/**
	 * 
	 * @return INSTANCE
	 */
	public static Y42bUtils getInstance() {
		if (Y42bUtils.INSTANCE == null) {
			Y42bUtils.createInstance();
		}
		return Y42bUtils.INSTANCE;
	}

	/**
	 * Convierte a UTF8
	 * 
	 * @param label
	 *            String
	 * @return temp
	 */
	public static String convertToUTF8(String label) {
		String temp = "";

		try {
			temp = new String(label.getBytes("ISO-8859-1"), "UTF8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		return temp;
	}

	/**
	 * Convierte de UTF8 a ISO
	 * 
	 * @param label
	 *            String
	 * @return temp
	 */
	public static String convertToISO(String label) {
		String temp = "";
		if (label == null) {
			return "";
		}
		try {

			// temp = new String(label.getBytes("UTF-8"), "windows-1251");
			temp = new String(label.getBytes("UTF-8"), "ISO-8859-1");
			// temp = new String(label.getBytes(), "ISO-8859-1");
		} catch (UnsupportedEncodingException e) {
			Y42bUtils.logger.error(e.getMessage());
		}

		return temp;
	}

	/**
	 * Parsea un string de fecha con el formato correspondiente al idioma del
	 * locale y devuelve la fecha.
	 * 
	 * @param dateString
	 *            String
	 * @param locale
	 *            Locale
	 * @return ""
	 * @throws Exception
	 *             Exception
	 */
	public static Date parseDate(String dateString, Locale locale)
			throws Exception {
		if (dateString != null && !dateString.equals("")) {
			DateFormat dateFormat = null;
			if (Y42bAgendaConstantes.CASTELLANO.equals(locale.getLanguage())) {
				dateFormat = new SimpleDateFormat("dd/MM/yyyy");
			} else if (Y42bAgendaConstantes.EUSKERA
					.equals(locale.getLanguage())) {
				dateFormat = new SimpleDateFormat("yyyy/MM/dd");
			} else {
				throw new Exception(
						"Language date parse support not implemented for this language.");
			}
			return dateFormat.parse(dateString);
		}
		return null;
	}

	/**
	 * 
	 * @param strFecha
	 *            string
	 * @return Date
	 */
	public static Date parseDate(String strFecha) {
		SimpleDateFormat formatoDelTexto = new SimpleDateFormat("yyyy-MM-dd");
		formatoDelTexto.setLenient(false);
		// String strFecha = "2007-12-25";
		Date fecha = null;
		try {
			if (strFecha != null) {
				if (strFecha.length() == Y42bAgendaConstantes.NUM_10) {
					fecha = formatoDelTexto.parse(strFecha);
				}
			}

		} catch (ParseException ex) {
			Y42bUtils.logger.error("Fecha incorrecta: " + strFecha);

			ex.printStackTrace();
		}
		return fecha;
	}

	/**
	 * 
	 * @param fecha
	 *            String
	 * @param lang
	 *            String
	 * @return fechaformateada
	 */
	public static String parseDateToString(Date fecha, String lang) {
		// String formato = "yyyy-MM-dd";
		String fechaFormateada = "";
		// SimpleDateFormat formatoDelTexto = new
		// SimpleDateFormat("yyyy-MM-dd");
		DecimalFormat df = new DecimalFormat("00");

		if (fecha != null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(fecha);

			int dia = calendar.get(Calendar.DAY_OF_MONTH); // dia del mes
			int mes = calendar.get(Calendar.MONTH) + 1; // mes, de 0 a 11
			int anio = calendar.get(Calendar.YEAR); // año

			if (Y42bAgendaConstantes.EUSKERA.equals(lang)) {
				fechaFormateada = df.format(mes) + "/" + df.format(dia) + "/"
						+ anio;
			} else {
				fechaFormateada = df.format(dia) + "/" + df.format(mes) + "/"
						+ anio;
			}
		}
		return fechaFormateada;
	}

	/**
	 * Parsea un string de fecha con el formato correspondiente al idioma del
	 * locale y devuelve la fecha. Recibe un tipo date
	 * 
	 * @param date
	 *            (Date)
	 * @param locale
	 *            the locale
	 * @return the date
	 * @throws Exception
	 *             the exception
	 */
	public static Date parseDate(Date date, Locale locale) throws Exception {
		if (date != null) {
			SimpleDateFormat formatter = null;
			if (Y42bAgendaConstantes.CASTELLANO.equals(locale.getLanguage())) {
				formatter = new SimpleDateFormat("dd/MM/yyyy");
			} else if (Y42bAgendaConstantes.EUSKERA
					.equals(locale.getLanguage())) {
				formatter = new SimpleDateFormat("yyyy/MM/dd");
			} else {
				throw new Exception(
						"Language date parse support not implemented for this language.");
			}
			return formatter.parse(formatter.format(date));

		}
		return null;
	}

	/**
	 * Convierte un InputStream a String
	 * 
	 * @param is
	 *            InputStream
	 * @return String
	 * @throws IOException
	 *             IOException
	 */
	public static String convertInputStreamToString(InputStream is)
			throws IOException {
		/*
		 * To convert the InputStream to String we use the Reader.read(char[]
		 * buffer) method. We iterate until the Reader return -1 which means
		 * there's no more data to read. We use the StringWriter class to
		 * produce the string.
		 */
		if (is != null) {
			Writer writer = new StringWriter();

			char[] buffer = new char[Y42bAgendaConstantes.NUM_1024];
			try {
				Reader reader = new BufferedReader(new InputStreamReader(is,
						"UTF-8"));
				int n;
				while ((n = reader.read(buffer)) != -1) {
					writer.write(buffer, 0, n);
				}
			} finally {
				is.close();
			}
			return writer.toString();
		} else {
			return "";
		}
	}

	/**
	 * Obtiene longitud de cualquier inputStream
	 * 
	 * @param is
	 *            InputStram
	 * @return String
	 * @throws IOException
	 */
	public static int getLongitudInputStream(InputStream is) {
		int n = 0;
		if (is != null) {
			try {
				while ((n = is.read()) != -1) {
					n++;
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return n;
	}

	/**
	 * Muestra la etiqueta parseada para una estructura json - arbol
	 * 
	 * @param lblEs
	 *            Castellano
	 * @param lblEu
	 *            Euskera
	 * @return printlabel
	 */
	public static String printTreeLabel(String lblEs, String lblEu) {
		return Y42bUtils.isLanguage(lblEs, lblEu);
	}

	/**
	 * Muestra la etiqueta en el idioma correspondiente
	 * 
	 * @param lblEs
	 *            Castellano
	 * @param lblEu
	 *            Euskera
	 * @return language
	 */
	private static String isLanguage(String lblEs, String lblEu) {
		// Idioma
		Locale locale = LocaleContextHolder.getLocale();
		if (Y42bAgendaConstantes.EUSKERA.equals(locale.getLanguage())) {
			return lblEu;
		} else {
			return lblEs;
		}

	}

	/**
	 * Filtra caracteres antes de ingreso en DB
	 * 
	 * @param input
	 *            String
	 * @return filtro
	 */
	public static String az_filtroDB(String input) {

		// Comprueba que no contenga caracteres prohibidos
		/*
		 * El caracter '+' representa una o más veces El caracter '^' dentro de
		 * los corchetes es un NOT, permite encontrar cualquier carácter que NO
		 * se encuentre dentro del grupo indicado
		 */
		// Pattern p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");
		Pattern p = Pattern.compile("[^A-Za-z0-9@ _()-áéíóúñÁÉÍÓÚÑ]");
		Matcher m = p.matcher(input);
		StringBuffer sb = new StringBuffer();
		boolean resultado = m.find();
		boolean caracteresIlegales = false;
		while (resultado) {
			caracteresIlegales = true;
			m.appendReplacement(sb, "");
			resultado = m.find();
		}

		// Añade el ultimo segmento de la entrada a la cadena
		m.appendTail(sb);

		if (caracteresIlegales) {
			Y42bUtils.logger
					.info("La cadena contenía caracteres ilegales que han sido suprimidos");
		}

		return sb.toString();
	}

	/**
	 * Filtra caracteres antes de ingreso en DB
	 * 
	 * @param input
	 *            String
	 * @return filtro
	 */
	public static String filtroDB(String input) {

		input.replace("''", "");
		return input.replace("/", "");
	}

	/**
	 * Normaliza datos de entrada de formularios a 0 - Para combos normalmente
	 * 
	 * 
	 * @param input
	 *            input
	 * @return "" vacio
	 */
	public static String normalizarCero(String input) {

		String rt = "";
		if (input == null) {
			rt = Y42bAgendaConstantes.CERO;
		} else if ("".equals(input)) {
			rt = Y42bAgendaConstantes.CERO;
		} else {
			rt = input;
		}

		return rt;
	}

	/**
	 * Normaliza datos de entrada de formularios a "" - excepto combos
	 * 
	 * @param input
	 *            String
	 * @return String
	 */
	public static String normalizarVacio(String input) {

		String rt = Y42bAgendaConstantes.VACIO;
		if (input != null) {
			if (!"null".equals(input)) {
				rt = input;
			}
		}

		return rt;
	}

	/**
	 * Static method to obtain properties
	 * 
	 * @param nombreFichero
	 *            String
	 * @return properties Properties
	 */
	public static Properties loadProperties(String nombreFichero) {
		Y42bUtils u = new Y42bUtils();
		return u.getProperties(nombreFichero);

	}

	/**
	 * Método que carga el fichero de propiedades
	 * 
	 * @param nombreFichero
	 *            String
	 * @return Properties
	 */
	public Properties getProperties(String nombreFichero) {
		Properties pLog = new Properties();
		InputStream configLog = null;
		try {
			String propertiesLog = nombreFichero;
			configLog = this.getClass().getResourceAsStream(propertiesLog);
			pLog.load(configLog);
			configLog.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				configLog.close();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		return pLog;
	}

	/**
	 * Calcula la letra correspondiente a un DNI
	 * 
	 * @param nif
	 *            NIF a partir del cual se calculará su correspondiente letra
	 * @return Letra calculada para el DNI del NIF
	 */
	public static char calcularLetraNIF(String nif) {
		String cadena = "TRWAGMYFPDXBNJZSQVHLCKE";
		int dni = 0;
		int pos = 0;

		try {
			dni = Integer.parseInt(nif.substring(0, nif.length() - 1));
			pos = dni % Y42bUtils.posCIF;
			return cadena.charAt(pos);
		} catch (NumberFormatException nfe) {
			return '!';
		}
	}

	/**
	 * 
	 * Convierte los caracteres especiales a código HTML
	 * 
	 * @param tag
	 *            Cadena de texto original
	 * 
	 * @return Cadena de texto reemplazada
	 */
	public static String encodeHtmlTag(String tag) {
		if (tag == null) {
			return null;
		}

		int length = tag.length();

		StringBuffer encodedTag = new StringBuffer(2 * length);

		for (int i = 0; i < length; i++) {
			char ch = tag.substring(i, i + 1).charAt(0);

			if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0'
					&& ch <= '9') {
				// safe
				encodedTag.append(ch);
			} else if (Character.isWhitespace(ch)) {
				// paranoid version: whitespaces are unsafe - escape
				// conversion of (int)ch is naive
				encodedTag.append("&#").append((int) ch).append(";");
			} else if (Character.isISOControl(ch)) {
				// paranoid version:isISOControl which are not isWhitespace
				// removed !
				// do nothing do not include in output !
			} else {
				// paranoid version
				// the rest is unsafe, including <127 control chars
				encodedTag.append("&#" + (int) ch + ";");
			}
		}

		return encodedTag.toString();
	}

	/**
	 * 
	 * Escapa caracteres del string que provocan error en JSON
	 * 
	 * @param tag
	 *            Cadena de texto original
	 * 
	 * @return Cadena de texto reemplazada
	 */

	public static String quote(String string) {
		if (string == null || string.length() == 0) {
			// return "\"\"";
			return "";
		}

		char c = 0;
		int i;
		int len = string.length();
		StringBuilder sb = new StringBuilder(len + 4);
		String t;

		// sb.append('"');
		for (i = 0; i < len; i += 1) {
			c = string.charAt(i);
			switch (c) {
			case '\\':
			case '"':
				sb.append('\\');
				sb.append(c);
				break;
			case '/':
				// if (b == '<') {
				sb.append('\\');
				// }
				sb.append(c);
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\r':
				sb.append("\\r");
				break;
			default:
				if (c < ' ') {
					t = "000" + Integer.toHexString(c);
					sb.append("\\u" + t.substring(t.length() - 4));
				} else {
					sb.append(c);
				}
			}
		}
		// sb.append('"');
		return sb.toString();
	}

	public static final String unescapeHTML(String s, int f) {
		String[][] escape = { { "&lt;", "<" }, { "&gt;", ">" },
				{ "&amp;", "&" }, { "&quot;", "\"" }, { "&aacute;", "á" },
				{ "&acute;", "´" }, { "&Aacute;", "Á" }, { "&eacute;", "é" },
				{ "&Eacute;", "É" }, { "&iacute;", "í" }, { "&Iacute;", "Í" },
				{ "&oacute;", "ó" }, { "&Oacute;", "Ó" }, { "&uacute;", "ú" },
				{ "&Uacute;", "Ú" }, { "&ntilde;", "ñ" }, { "&Ntilde;", "Ñ" },
				{ "&apos;", "'" }, { "&deg;", "º" }, { "&agrave;", "à" },
				{ "&Agrave;", "À" }, { "&acirc;", "â" }, { "&auml;", "ä" },
				{ "&Auml;", "Ä" }, { "&Acirc;", "Â" }, { "&aring;", "å" },
				{ "&Aring;", "Å" }, { "&aelig;", "æ" }, { "&AElig;", "Æ" },
				{ "&ccedil;", "ç" }, { "&Ccedil;", "Ç" }, { "&eacute;", "é" },
				{ "&Eacute;", "É" }, { "&egrave;", "è" }, { "&Egrave;", "È" },
				{ "&ecirc;", "ê" }, { "&Ecirc;", "Ê" }, { "&euml;", "ë" },
				{ "&Euml;", "Ë" }, { "&iuml;", "ï" }, { "&Iuml;", "Ï" },
				{ "&ocirc;", "ô" }, { "&Ocirc;", "Ô" }, { "&ouml;", "ö" },
				{ "&Ouml;", "Ö" }, { "&oslash;", "ø" }, { "&Oslash;", "Ø" },
				{ "&szlig;", "ß" }, { "&ugrave;", "ù" }, { "&Ugrave;", "Ù" },
				{ "&ucirc;", "û" }, { "&Ucirc;", "Û" }, { "&uuml;", "ü" },
				{ "&Uuml;", "Ü" }, { "&nbsp;", " " }, { "&reg;", "\u00a9" },
				{ "&copy;", "\u00ae" }, { "&euro;", "\\\\'80" },
				{ "&Ccedil;", "Ç" }, { "&ccedil;", "ç" }, { "&uml;", "¨" },
				{ "&iquest;", "¿" }, { "&middot;", "·" },
				{ "&lineSeparator;", "{\\\\par \\\\pard}" },
				{ "&separator;", "{\\\\sb \\\\sb}" },
				{ "&negritaini;", "\\\\b " },
				{ "&negritafin;", "\\\\b0 \\\\'20" },
				{ "&italicini;", "\\\\i " },
				{ "&italicfin;", "\\\\i0 \\\\'20" },
				{ "&subrayadoini;", "\\\\ul " },
				{ "&subrayadofin;", "\\\\ul0 \\\\'20" },
				{ "&bullet;", "\\\\'95" }, { "&tachadoini;", "\\\\strike" },
				{ "&tachadofin;", "\\\\strike0" },

		};
		int i, j, k;

		if (s != null) {
			i = s.indexOf("&", f);
			if (i > -1) {
				j = s.indexOf(";", i);
				// --------
				// we don't start from the beginning
				// the next time, to handle the case of
				// the &
				// thanks to Pieter Hertogh for the bug fix!
				f = i + 1;
				// --------
				if (j > i) {
					// ok this is not most optimized way to
					// do it, a StringBuffer would be better,
					// this is left as an exercise to the reader!
					String temp = s.substring(i, j + 1);
					// search in escape[][] if temp is there
					k = 0;
					while (k < escape.length) {
						if (escape[k][0].equals(temp))
							break;
						else
							k++;
					}
					if (k < escape.length) {
						s = s.substring(0, i) + escape[k][1]
								+ s.substring(j + 1);
						return unescapeHTML(s, f); // recursive call
					}
				}
			}
		}
		return s;
	}

}