package com.FitBank.common;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.math.BigDecimal;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Clase que implementa servicios generales para en metodos.
 * Es declarada final para que no se hagan subclases de la misma.
 * 
 * @author FitBank
 * @version 1.0
 */
public final class Servicios {

	/** Formato que indica si se trata de timestamps. */
    public static final String FORMATO_FECHA_TIMESTAMP = "TF";

    /** Formato que indica si se trata de fechas normales. */
    public static final String FORMATO_FECHA_NORMAL    = "DF";

    /**
     * Constructor deprecado!
     * Proximamente se cambiara el modo de acceso a privado para prohibir sus instancias.
     * 
     * @deprecated No se debe llamar el constructor puesto que es una clase de servicios.
     */
    public Servicios() {
    }

    /**
     * Metodo que recibe un objeto String y un caracter que es entregado como
     * diferenciador de los objetos encontrados en el objeto inicial.
     * 
     * @param cadena Objeto a ser manipulado.
     * @param separador Caracter(es) de separacion.
     * 
     * @return Cadena manipulada.
     */
    public static String[] split(Object cadena, String separador) {
        return split(String.valueOf(cadena), separador);
    }

    /**
     * Metodo que recibe un objeto String y un caracter que es entregado como
     * diferenciador de los objetos encontrados en el objeto inicial.
     * 
     * @param cadena Cadena a ser manipulada.
     * @param separador Caracter(es) de separacion.
     * 
     * @return Cadena manipulada.
     */
    public static String[] split(String cadena, String separador) {
        if (cadena == null || cadena.equalsIgnoreCase("")) {
            return new String[0];
        }

        int i       = 0,
            count   = 0,
            bandera = 0,
            start,
            stop;

        for (i = 0; i < cadena.length(); i++) {
            if (cadena.charAt(i) == separador.charAt(0)) {
                bandera = 1;
            } else {
                bandera = 0;
            }

            count = count + bandera;
        }

        String[] arreglo = new String[count + 1];
        count = start = 0;

        try {
            while (cadena.indexOf(separador.charAt(0), start) > -1) {
                stop = cadena.indexOf(separador.charAt(0), start);
                arreglo[count++] = cadena.substring(start, stop);
                start = stop + 1;
            }

            arreglo[count] = cadena.substring(start);
        } catch (Exception e) {
            return null;
        }

        return arreglo;
    }

    /**
     * Metodo que devuelve una cadena que contiene varios objetos String con un caracter que los separa.
     * Recibe un arreglo de objetos String y un objeto String que contiene un caracter de separacion.
     * 
     * @param arreglo Arreglo de Cadenas.
     * @param separador Caracter(es) de separacion.
     * 
     * @return Cadena Generada.
     */
    public static String join(String[] arreglo, String separador) {
        int a = 0;
        String cadena = arreglo[0];

        for (a = 1; a < arreglo.length; a++) {
            cadena += separador + arreglo[a];
        }

        return cadena;
    }

    /**
     * Metodo que permite conocer si existe contenido en una cadena,
     * si el objeto String es null devuelve una cadena vacia,
     * caso contrario devuelve el contenido del objeto.
     * 
     * @param verificacion Cadena a ser verificada.
     * 
     * @return Cadena vacia si no hay nada.
     */
    public static String verificarCadena(String verificacion) {
        if (verificacion == null) {
            return "";
        }

        return verificacion;
    }

    /**
     * Metodo que permite generar la cadena de tipo valor#nombreOrigenDB^valor#nombreOrigenDB.
     * 
     * @param s par de strings{valor, origenDb, valor2,origenDB2,...,valorN, origenDBN}.
     * 
     * @return cadena formateada.
     */
    public static String formatValorOrigenDB(String[] s) {
        String format = "";
        int size = s.length % 2 == 0 ?  s.length  : s.length - 1;

        for (int i = 0; i < size; i += 2) {
            format += s[i] + "#" + s[i + 1];

            if (i + 1 != size - 1) {
                format += "^";
            }
        }

        format += "^";

        return format;
    }

    /**
     * Metodo main que genera una instancia Servicios.
     * 
     * @param args Argumentos
     */
    public static void main(String[] args) {
        System.out.println(Servicios.eliminaCeros("00000000"));
    }

    /**
     * Metodo que reemplaza un contenido especifico dentro de un Objeto String.
     * 
     * @param archivo Es el objeto que contiene la cadena en la cual se desea realizar el reemplazo.
     * @param seccion Es el objeto que contiene el nombre de la seccion que se desea reemplazar.
     * @param reemplazo Es el objeto que contiene la cadena que se desea colocar en la seccion determinada.
     * 
     * @return Es el objeto que contiene la cadena con el contenido original ejecutado el reemplazo.
     */
    public static String reemplazarContenido(String archivo, String seccion, String reemplazo) {
        String aReemplazar  = "",
               carga        = "",
               parteInicial = "",
               parteFinal   = "";

        int longitudReemplazo;

        aReemplazar = "<!-- " + seccion + " -->";

        if (archivo.indexOf(aReemplazar) > 0) {
            longitudReemplazo = aReemplazar.length();

            parteInicial = archivo.substring(0, archivo.indexOf(aReemplazar));
            parteFinal   = archivo.substring(archivo.indexOf(aReemplazar) + longitudReemplazo);

            carga = parteInicial + reemplazo + parteFinal;
        } else {
            carga = null;
        }

        return carga;
    }

    /**
     * Metodo que reemplaza un contenido especifico dentro de un Objeto String
     * sin caracteres predefinidos particularmente en el metodo.
     * 
     * @param original Es el objeto que contiene la cadena en la cual se desea realizar el reemplazo.
     * @param seccion Es el objeto que contiene el nombre de la seccion que se desea reemplazar.
     * @param reemplazo Es el objeto que contiene la cadena que se desea colocar en la seccion determinada.
     * @param flag Es un entero que permite determinar la invocacion del metodo.
     * 
     * @return Es el objeto que contiene la cadena con el contenido original ejecutado el reemplazo.
     */
    public static String reemplazarContenido(String original, String seccion, String reemplazo, int flag) {
        String carga        = "",
               parteInicial = "",
               parteFinal   = "";

        int longitudReemplazo;

        if (original.indexOf(seccion) >= 0) {
            longitudReemplazo = seccion.length();

            parteInicial = original.substring(0, original.indexOf(seccion));
            parteFinal   = original.substring(original.indexOf(seccion) + longitudReemplazo);
            carga        = parteInicial + reemplazo + parteFinal;
        } else {
            carga = original;
        }

        return carga;
    }

    /**
     * Metodo que busca una cadena dentro de otra y devuelve el indice del primer caracter de la cadena a buscar.
     * 
     * @param original Es el objeto que contiene la cadena en la cual se desea realizar la busqueda.
     * @param toFind Es el objeto que contiene la cadena que se desea buscar.
     * 
     * @return Es el entero que contiene el indice del primer caracter de la cadena de busqueda,
     *         si la encuentra, si no la encuentra devuelve un valor menor que cero.
     */
    public static int findIndex(String original, String toFind) {
        return original.indexOf(toFind);
    }

    /**
     * Metodo que devuelve el contenido de una subcadena solicitada mediante los indices de limitacion.
     * 
     * @param poInitial Posicion inicial, en indice, de la cadena a buscar, dentro de la cadena original.
     * @param poFinal Posicion final, en indice, de la cadena a buscar, dentro de la cadena original.
     * @param original Cadena Original.
     * 
     * @return Contenido de la subcadena solicitada en un objeto String.
     */
    public static String obtenerCadena(int poInitial, int poFinal, String original) {
        return original.substring(poInitial, poFinal);
    }

    /**
     * Metodo que devuelve el contenido de una subcadena solicitada con su indice de inicio hasta el fin de la misma.
     * 
     * @param poInitial Posicion inicial, en indice, de la cadena a buscar, dentro de la cadena original.
     * @param original Cadena Original.
     * 
     * @return Contenido de la subcadena solicitada en un objeto String.
     */
    public static String obtenerCadena(int poInitial, String original) {
        return original.substring(poInitial);
    }

    /**
     * Metodo que retira caracteres de escape.
     * 
     * @param discriminador Cadena a ser manipulada.
     * 
     * @return Cadena sin los caracteres de escape.
     */
    public static String invertirDiscriminar(String discriminador) {
        try {
            discriminador = discriminador.replaceAll("&lt;",   "<");
            discriminador = discriminador.replaceAll("&gt;",   ">");
            discriminador = discriminador.replaceAll("&apos;", "'");
            discriminador = discriminador.replaceAll("&amp;",  "&");
        } catch (Exception e) {
            System.err.println("Error al invertir discriminar, se continua sin cambios en la cadena");
        }

        return discriminador;
    }

    /**
     * Metodo que agrega caracteres de escape.
     * 
     * @param discriminador Cadena a ser modificada.
     * 
     * @return Cadena modificada.
     */
    public static String discriminar(String discriminador) {
        try {
            discriminador = discriminador.replaceAll("&lt;",   "<");
            discriminador = discriminador.replaceAll("&gt;",   ">");
            discriminador = discriminador.replaceAll("&apos;", "'");
            discriminador = discriminador.replaceAll("&amp;",  "&");

            discriminador = discriminador.replaceAll("&", "&amp;");
            discriminador = discriminador.replaceAll("<", "&lt;");
            discriminador = discriminador.replaceAll(">", "&gt;");
            discriminador = discriminador.replaceAll("'", "&apos;");
        } catch (Exception e) {
            System.err.println("Error al discriminar, se continua sin cambios en la cadena");
        }

        return discriminador;
    }

    /**
     * Busca un elemento dentro de un arreglo, y devuelve valor true del boolean si lo encuentra, caso contrario false.
     * 
     * @param arreglo Arreglo a ser buscado.
     * @param elemento Cadena que se busca.
     * 
     * @return true si lo encontro, false si no.
     */
    public static boolean buscarElemento(Vector arreglo, String elemento) {
        boolean bandera = false;

        for (int i = 0; i < arreglo.size(); i++) {
            if (arreglo.elementAt(i).toString().equalsIgnoreCase(elemento)) {
                bandera = true;
            }
        }

        return bandera;
    }

    /**
     * Metodo que extrae los minutos de la fecha del Servidor Web.
     * 
     * @return String de los minutos.
     */
    protected static String obtenerMinutos() {
        Date vdActual = new Date();
        GregorianCalendar viCalendario = new GregorianCalendar();
        viCalendario.setTime(vdActual);

        String min = String.valueOf(viCalendario.get(Calendar.MINUTE));

        if (min.length() == 1) {
            min = "0" + min;
        }

        return min;
    }

    /**
     * Metodo que extrae la hora de la fecha del sistema.
     * 
     * @return String de la hora(hh).
     */
    protected static String obtenerHora() {
        // System.out.println("obtenerHora()");
        Date vdActual = new Date();
        GregorianCalendar viCalendario = new GregorianCalendar();
        viCalendario.setTime(vdActual);

        String hora = String.valueOf(viCalendario.get(Calendar.HOUR_OF_DAY));

        if (hora.length() == 1) {
            hora = "0" + hora;
        }

        return hora;
    }

    /**
     * Metodo que extrae el Dia de la Fecha Actual del Sistema.
     * 
     * @return String del dia.
     */
    protected static String obtenerDia() {
        Date vdActual = new Date();
        GregorianCalendar viCalendario = new GregorianCalendar();
        viCalendario.setTime(vdActual);

        String dia = String.valueOf(viCalendario.get(Calendar.DAY_OF_MONTH));

        if (dia.length() == 1) {
            dia = "0" + dia;
        }

        return dia;
    }

    /**
     * Metodo que extrae el Mes de la Fecha Actual del Sistema.
     * 
     * @return String del mes.
     */
    protected static String obtenerMes() {
        Date vdActual = new Date();
        int viNumeroMeses = 0;
        GregorianCalendar viCalendario = new GregorianCalendar();
        viCalendario.setTime(vdActual);
        viNumeroMeses = viCalendario.get(Calendar.MONTH);
        ++viNumeroMeses;

        String mes = "" + viNumeroMeses;

        if (mes.length() == 1) {
            mes = "0" + mes;
        }

        return mes;
    }

    /**
     * Metodo que extrae el Anio de la fecha del sistema.
     * 
     * @return String del anio.
     */
    protected static String obtenerAni() {
        Date vdActual = new Date();
        GregorianCalendar viCalendario = new GregorianCalendar();
        viCalendario.setTime(vdActual);

        String anio = String.valueOf(viCalendario.get(Calendar.YEAR));

        return anio;
    }

    /**
     * Metodo que genera la fecha completa en formato Timestamp.
     * 
     * @return String de la fecha completa.
     */
    public static String obtenerFechaAS() {
        String fecha = "";
        fecha = obtenerAni() + "-" + obtenerMes() + "-" + obtenerDia() + " " +
                obtenerHora() + ":" + obtenerMinutos() + ":00";

        return fecha;
    }

    /**
     * Metodo que indica si la fecha pasada en el objeto de parametro se encuentra en el formato TimeStamp.
     * 
     * @param dateValidate Es un objeto que contiene la fecha a validar.
     * 
     * @return Objeto que que indica si el metodo encontro que el objeto pasado
     *         se encuentra en formato TimeStamp(V) si no (F).
     */
    public static boolean esTimeStamp(String dateValidate) {
        return dateValidate.matches("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d-\\d\\d-\\d\\d\\.\\d\\d\\d");
        						//  "\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d\\.\\d\\d\\d");
    }

    /**
     * Metodo que indica si la fecha pasada en el objeto de parametro se encuentra en el formato Date.
     * 
     * @param dateValidate Es un objeto que contiene la fecha a validar.
     * 
     * @return Objeto que que indica si el metodo encontro que el objeto pasado
     *         se encuentra en formato Date(V) si no (F)
     */
    public static boolean esFechaNormal(String dateValidate) {
        return dateValidate.matches("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d-\\d\\d-\\d\\d");
        						// 	"\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d");
    }

    /**
     * Metodo que permite transformar un objeto String a un tipo de dato int.
     * 
     * @param page Objeto que contiene la cadena que se desea pasar a tipo de dato int.
     * 
     * @return Variable con el valor int de la cadena que se envia.
     */
    public static int transformString(String page) {
        int changed;

        try {
            changed = Integer.parseInt(page, 10);

            return changed;
        } catch (Exception exc) {
            System.out.println("ERROR transformString():  " + exc.toString());

            return -1;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Long,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Long, contiene a manera de cadena un numero con decimales.
     * 
     * @return Objeto que contiene el valor numerico de la cadena pasada como parametro al metodo
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static Long toLong(String string) {
        try {
            if (string == null) {
                return null;
            }

            return Long.valueOf(string);
        } catch (Exception exc) {
            System.out.println("Servicios.toLong: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Integer,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Integer, contiene a manera de cadena un numero entero.
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo
     * 		   conservando la asignacion a null del mismo de ser el caso.
     */
    public static Integer toInteger(String string) {
        try {
            if (string == null) {
                return null;
            }

            return Integer.valueOf(string);
        } catch (Exception exc) {
            System.out.println("Servicios.toInteger: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Double,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Double, contiene a manera de cadena un numero entero largo.
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static Double toDouble(String string) {
        try {
            if (string == null) {
                return null;
            }

            return Double.valueOf(string);
        } catch (Exception exc) {
            System.out.println("Servicios.toDouble: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite conservar el null de los objetos Double
     * sin que produzca un error de NullPointerException.
     * 
     * @param objeto Objeto Double
     * 
     * @return Objeto Double
     */
    public static String toDouble(Double objeto) {
        try {
            if (objeto == null) {
                return null;
            }

            return objeto.toString();
        } catch (Exception exc) {
            return null;
        }
    }

    /**
     * Metodo que permite conservar el null de los objetos al ser pasados a String
     * sin que produzca un error de NullPointerException.
     * 
     * @param object Objeto que se desea transformar a String.
     * 
     * @return Objeto transformado a String.
     */
    public static String toString(Object object) {
        try {
            if (object == null) {
                return null;
            }

            return String.valueOf(object);
        } catch (Exception exc) {
            return null;
        }
    }

    /**
     * Metodo que convierte las primeras letras de cada palabra a mayusculas y las restantes en minusculas.
     * 
     * @param object String que se desea transformar a Capitalize.
     * 
     * @return String transformado a Capitalize.
     */
    public static String toCapitalize(String object) {
        String[] palabras = Servicios.split(object, " ");
        object = "";

        for (String palabra : palabras) {
            if (palabra.length() > 1) {
                object += " " + palabra.substring(0, 1).toUpperCase() + palabra.substring(1).toLowerCase();
            } else if (palabra.length() == 1) {
                object += " " + palabra.toUpperCase();
            } else {
                object += " ";
            }
        }

        return object;
    }

    /**
     * Metodo que permite conservar el null o poner un valor por defecto en los objetos
     * al ser pasados a String sin que produzca un error de NullPointerException.
     * 
     * @param object Objeto que se desea transformar a String.
     * @param defaultValue Valor por defecto a ser usado en la conversion a string.
     * 
     * @return Objeto transformado a String.
     */
    public static String toString(Object object, String defaultValue) {
        try {
            if (object == null && defaultValue == null) {
                return null;
            } else if (object == null && defaultValue != null) {
                return defaultValue;
            } else {
                return String.valueOf(object);
            }
        } catch (Exception exc) {
            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Double,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Double, contiene a manera de cadena un numero entero largo.
     * @param defaultValue valor por defecto
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo,
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static Double toDouble(String string, String defaultValue) {
        try {
            if (string == null && defaultValue == null) {
                return null;
            } else if (string == null && defaultValue != null) {
                return Double.valueOf(defaultValue);
            } else {
                return Double.valueOf(string);
            }
        } catch (Exception exc) {
            System.out.println("Servicios.toDouble: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Integer,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Integer, contiene a manera de cadena un numero entero.
     * @param defaultValue valor por defecto
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo,
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static Integer toInteger(String string, String defaultValue) {
        try {
            if (string == null && defaultValue == null) {
                return null;
            } else if (string == null && defaultValue != null) {
                return Integer.valueOf(defaultValue);
            } else {
                return Integer.valueOf(string);
            }
        } catch (Exception exc) {
            System.out.println("Servicios.toInteger: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Double,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Double, contiene a manera de cadena un numero entero largo.
     * @param defaultValue valor por defecto.
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo,
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static BigDecimal toBigDecimal(String string, String defaultValue) {
        try {
            if (string == null && defaultValue == null) {
                return null;
            } else if (string == null && defaultValue != null) {
                return new BigDecimal(defaultValue);
            } else {
                return new BigDecimal(string);
            }
        } catch (Exception exc) {
            System.out.println("Servicios.toBigDecimal: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Double,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param string Objeto que se desea transformar a Double, contiene a manera de cadena un numero entero largo.
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo,
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static BigDecimal toBigDecimal(String string) {
        try {
            if (string == null) {
                return null;
            }

            return new BigDecimal(string);
        } catch (Exception exc) {
            System.out.println("Servicios.toBigDecimal: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite transformar un objeto de la clase String a uno de la clase Double,
     * conservando el null si es que el objeto primitivo tiene esa asignacion cuando se realiza la transformacion.
     * 
     * @param number Objeto que se desea transformar a Double, contiene a manera de cadena un numero entero largo.
     * 
     * @return Objeto que contiene el valor entero de la cadena pasada como parametro al metodo
     *         conservando la asignacion a null del mismo de ser el caso.
     */
    public static BigDecimal toBigDecimal(Number number) {
        try {
            if (number == null) {
                return null;
            }

            return new BigDecimal(number.doubleValue());
        } catch (Exception exc) {
            System.out.println("Servicios.toBigDecimal: " + exc.toString());

            return null;
        }
    }

    /**
     * Metodo que permite truncar el numero de decimales de un numero real.
     * 
     * @param val Contiene el numero real que se quiere truncar.
     * @param trunc Contiene el numero de decimales a los que se quiere truncar.
     * 
     * @return val Retorna el numero truncado.
     * 
     * @throws FitException Excepcion FIT.
     */
    public static double validarDecimal(double val, int trunc) throws FitException {
        String str = "";
        String aux = "";
        StringBuffer cad = new StringBuffer("0.");

        try {
            for (int q = 0; q < trunc; q++) {
                cad.append("0");
            }

            cad.append("5");

            if (val >= Double.parseDouble(String.valueOf(cad))) {
                val = redondearDecimal(val, trunc);
                str = String.valueOf(val);
                aux = Servicios.split(str, ".")[1];

                if (aux.length() > trunc) {
                    aux = aux.substring(0, trunc);
                }

                str = Servicios.split(str, ".")[0] + "." + aux;
                val = Double.parseDouble(str);
            } else {
                val = 0.00;
            }

            return val;
        } catch (Exception e) {
            System.out.println("Servicios.validarDecimal: " + e.toString());

            return 0;
        }
    }

    /**
     * Metodo que redondea el ultimo decimal segun el numero de decimales que se quiera mostrar.
     * 
     * @param val Contiene el numero que se quiere redondear.
     * @param trunc Contiene el valor del numero de decimales que se mostrara.
     * 
     * @return val Retorna el numero redondeado.
     * 
     * @throws FitException Excepcion FIT.
     */
    public static double redondearDecimal(double val, int trunc) {
        String str,
               dec,
               ent,
               aux1,
               aux2;

        int ent1,
            val1,
            val2,
            trunc2;

        try {
            str    = String.valueOf(val);
            dec    = Servicios.split(str, ".")[1];
            ent    = Servicios.split(str, ".")[0];
            ent1   = Integer.parseInt(ent, 10);
            aux1   = "";
            aux2   = "";
            val1   = 0;
            val2   = 0;
            trunc2 = trunc + 1;

            if (dec.length() >= trunc) {
                aux1 = dec.substring(0, trunc);
            }

            if (dec.length() >= trunc2) {
                aux2 = dec.substring(trunc, trunc2);
            }

            if (aux1 != "") {
                val1 = Integer.parseInt(aux1, 10);
            }

            if (aux2 != "") {
                val2 = Integer.parseInt(aux2, 10);
            }

            if (val2 >= 5) {
                val1 += 1;
            }

            if (val1 == 100) {
                ent1 += 1;
                val1 = 0;
                ent  = String.valueOf(ent1);
            }

            aux1 = String.valueOf(val1);

            if (aux1.length() == 1) {
                aux1 = "0" + aux1;
            }

            if (dec.length() > trunc) {
                str = ent + "." + aux1;
            } else {
                str = ent + "." + dec;
            }

            val = Double.parseDouble(str);

            return val;
        } catch (Exception e) {
            System.out.println("Servicios.redondearDecimal: " + e.toString());

            return 0;
        }
    }

    /**
     * Metodo que elimina las comas de un String.
     * 
     * @param valor String a ser modificado.
     * 
     * @return String sin comas.
     */
    public static String quitarComas(String valor) {
        String[] sep = Servicios.split(valor, ",");
        String aux = "";

        if (sep.length > 1) {
            for (String element : sep) {
                aux = aux + element;
            }

            return aux;
        }

        return valor;
    }

    /**
     * Metodo que redondea un double.
     * 
     * @param val Valor Numerico.
     * @param trunc Precision de decimales.
     * 
     * @return double.
     */
    public static double redondearDouble(double val, int trunc) {
        BigDecimal valor = new BigDecimal(val);

        return valor.setScale(trunc, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * Metodo que permite saber cual es el inicio y el fin de los registros que se van ha presentar en la paginacion.
     * 
     * @param parametros Paremtros con el numero de la pagina y los registros que se van a presentar.
     * 
     * @return Arreglo con el inicio y el fin de la paginacion.
     */
    public static int[] getQueryLimits(Hashtable parametros) {
        int   pagina;
        int   registros;
        int[] limits;

        try {
            limits    = new int[2];
            pagina    = Integer.parseInt(parametros.get("PAG").toString(), 10);
            registros = Integer.parseInt(parametros.get("REG").toString(), 10);

            if (registros == 1) {
                pagina = registros;
            }

            limits[0] = pagina * registros - registros;
            limits[1] = pagina * registros;

            return limits;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * Pone comas a un entero.
     * 
     * @param entero String con el entero
     * 
     * @return String del entero con comas
     */
    public static String comarEntero(String entero) {
        String enteroComado = "";

        for (int i = entero.replaceAll(",", "").length() - 1; i >= 0; i -= 3) {
            if (i > 2) {
                enteroComado = "," + entero.replaceAll(",", "").substring(i - 2, i + 1) + enteroComado;
            } else {
                enteroComado = entero.replaceAll(",", "").substring(0, i + 1) + enteroComado;
            }
        }

        return enteroComado.replaceAll("-,", "-");
    }

    /**
     * Metodo que permite calcular la longitud del area multiregistros de un x documento pdf.
     * 
     * @param unidad unidad de medida.
     * @param altPag alto de pagina segun unidad de medida.
     * @param marTop alto de margen superior de pagina segun unidad de medida.
     * @param marBot alto de margen inferior de pagina segun unidad de medida.
     * @param altCab alto de cabecera de pagina segun unidad de medida.
     * 
     * @return Valor entero correspondiente al alto en pixels del area que contendra a los multiregistros.
     */
    public static int calculaAreMulReg(String unidad, double altPag, double marTop, double marBot, double altCab) {
        double FAC_CM = 38,
               FAC_IN = 96.52,
               FAC_MM = 3.8,
               areaPx = 750; // valor por defecto

        if (unidad.equalsIgnoreCase("cm")) {
            areaPx = altPag * FAC_CM - marTop * FAC_CM - marBot * FAC_CM - altCab * FAC_CM;
        }

        if (unidad.equalsIgnoreCase("mm")) {
            areaPx = altPag * FAC_MM - marTop * FAC_MM - marBot * FAC_MM - altCab * FAC_MM;
        }

        if (unidad.equalsIgnoreCase("in")) {
            areaPx = altPag * FAC_IN - marTop * FAC_IN - marBot * FAC_IN - altCab * FAC_IN;
        }

        return new Double(areaPx).intValue();
    }

    /**
     * Metodo que permite convertir un valor x, a pixeles.
     * 
     * @param unidad Unidad de medida.
     * @param valor Valor a ser transformado.
     * 
     * @return valor entero transformado en pixeles.
     */
    public static int returnPixByUnit(String unidad, double valor) {
        double FAC_CM = 38,
               FAC_IN = 96.52,
               FAC_MM = 3.8,
               valPx = 0;

        if (unidad.equalsIgnoreCase("cm")) {
            valPx = valor * FAC_CM;
        }

        if (unidad.equalsIgnoreCase("mm")) {
            valPx = valor * FAC_MM;
        }

        if (unidad.equalsIgnoreCase("in")) {
            valPx = valor * FAC_IN;
        }

        return new Double(valPx).intValue();
    }

    /**
     * Metodo que permite calcular empiricamente el valor del numero de filas que puede contener
     * una longitud de alto de una pagina preestablecida en el documento PDF.
     * 
     * @param areaPx Longitud en pixeles del largo de un documento PDF
     * 
     * @return valor entero correspondiente al numero de filas que un area x puede contener
     */
    public static int returnNumRowByArea(double areaPx) {
        double CONS_HOJA = 750,
               CONS_ROWS = 35,
               numRows   = 0;

        numRows = areaPx * CONS_ROWS / CONS_HOJA;

        return new Double(numRows).intValue();
    }

    /**
     * Metodo que permite calcular empiricamente la diferencia en pixels existente entre dos posiciones conocidas
     * al aplicar quiebres de pagina en funcion del numero de filas que puede contener una x longitud de alto
     * de una pagina preestablecida en el documento PDF.
     * 
     * @param numRows Numero de registros que puede contener una x longitud
     * 
     * @return un valor entero correspondiente a la diferencia en pixels existentes entre dos posiciones.
     */
    public static int returnDifPixBetPos(double numRows) {
        double CONS_ROWS  = 35,
               CONS_DIFER = 665,
               difPix = numRows * CONS_DIFER / CONS_ROWS;

        return new Double(difPix).intValue();
    }

    /**
     * Metodo que coloca en un Vector nuevo los elementos de otro Vector solo hasta una posicion dada,
     * la misma que representa desde que elemento inclusive no se coloca en el nuevo Vector.
     * 
     * @param hasta Posicion hasta la que se copia (incluida).
     * @param original Vector original.
     * 
     * @return Vector con los elementos solicitados.
     */
    public static Vector deleteElementsVector(int hasta, Vector original) {
        try {
            Vector newVector = new Vector();

            for (int i = 0; i < hasta; i++) {
                newVector.add(original.get(i));
            }

            return newVector;
        } catch (Exception e) {
            Debug.imprimirError(e);

            return new Vector();
        }
    }

    /**
     * Metodo que permite obtener la fecha de expiracion de registros con valor 2999-12-31 00:00:00.0
     * y formato yyyy-mm-dd hh24.mi.ss.ff
     * 
     * @return Objeto Timestamp con valor 2999-12-31 00:00:00.0 y formato yyyy-mm-dd hh24.mi.ss.ff
     */
    public static Timestamp getExpirationDate() {
        // El valor 32503611600000L corrresponde al de 2999-12-31 00:00:00.0
        // decidi quemarlo ya que utilizando un Timestamp.valueOf("2999-12-31 00:00:00.0")
        // A PESAR de que ESTA SINTACTICAMENTE correcto, siempre tiene que declarar que
        // lanza una excepcion y por ende, cualquier lugar donde este metodo es llamado
        // se tiene que incluir en un try/catch
        // return new Timestamp(32503611600000L);
        return Timestamp.valueOf("2999-12-31 00:00:00.000");
    }

    /**
     * Metodo que permite obtener la fecha actual de la BDD del objeto SYSTIMESTAMP
     * con formato yyyy-mm-dd hh24.mi.ss.ff
     * 
     * @param connection Conexion en la que se trabaja.
     * 
     * @return fecha actual de la BDD con formato yyyy-mm-dd hh24.mi.ss.ff
     * 
     * @throws SQLException Cuando hay un error.
     */
    public static Timestamp getCurrentDate(Connection connection) throws SQLException {
        String sentencia;
        ResultSet resultSet = null;
        PreparedStatement preparedStatement = null;

        try {
            // sentencia = "SELECT SYSTIMESTAMP FECHASYS FROM DUAL";
            sentencia = "SELECT to_timestamp(to_char(SYSTIMESTAMP,'yyyy-mm-dd hh24.mi.ss.ff'),'yyyy-mm-dd hh24.mi.ss.ff') FECHASYS FROM DUAL";
            preparedStatement = connection.prepareStatement(sentencia);
            resultSet = preparedStatement.executeQuery();

            if (resultSet.next()) {
                return resultSet.getTimestamp("FECHASYS");
            }

            return null;
        } catch (SQLException exc) {
            throw exc;
        } finally {
            preparedStatement.close();
        }
    }

    /**
     * Le quita el formato a la fecha y le deja en el formato general.
     * 
     * @param formato Formato actual.
     * @param valorOriginal Valor original de la fecha.
     * 
     * @return String sin formato.
     */
    public static String getFechaSinFormato(String formato, String valorOriginal) {
        if (esFechaNormal(valorOriginal)) {
            return valorOriginal;
        }

        return formateadorFechaUniversal(formato, valorOriginal, FORMATO_FECHA_NORMAL);
    }

    /**
     * Obtiene un numero sin formato (sin comas).
     * 
     * @param valorOriginal Valor original.
     * 
     * @return String sin formato.
     */
    public static String getNumeroSinFormato(String valorOriginal) {
        return valorOriginal.replaceAll(",", "");
    }

    /**
     * Metodo que construye la cadena para realizar el seteo en los valores de fechas a formatearse.
     * 
     * @param formatoOriginal Objeto que trae la cadena del formato que se mostro en el browser
     *            			  para determinar donde se encuentran los valores de cada componente de la fecha.
     * @param cadenaOriginal Objeto que contiene la cadena a la que se extrae los
     *            			 componentes de la fecha para la cadena de seteo.
     * @param nuevoFormato Objeto que contiene el tipo de Formato que se desea entregar al valor de seteo.
     * 
     * @return Objeto que contiene la cadena cosntruida basada en el formato que
     *         se desea enviar en el mensaje a ser procesado.
     */
    protected static String formateadorFechaUniversal(String formatoOriginal, String cadenaOriginal, String nuevoFormato) {
        int initial;

        String nuevaCadena = "",
               anio        = "",
               mes         = "",
               dia         = "",
               hora        = "00",
               min         = "00",
               sec         = "00",
               mili        = "000000";

        try {
            initial = Servicios.findIndex(formatoOriginal, "yyyy");

            if (initial >= 0) {
                anio = Servicios.obtenerCadena(initial, initial + 4, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "mm");

            if (initial >= 0) {
                mes = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "dd");

            if (initial >= 0) {
                dia = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "YYYY");

            if (initial >= 0) {
                anio = Servicios.obtenerCadena(initial, initial + 4, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "MM");

            if (initial >= 0) {
                mes = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "DD");

            if (initial >= 0) {
                dia = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "hh");

            if (initial >= 0) {
                hora = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "mi");

            if (initial >= 0) {
                min = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            initial = Servicios.findIndex(formatoOriginal, "ss");

            if (initial >= 0) {
                sec = Servicios.obtenerCadena(initial, initial + 2, cadenaOriginal);
            }

            if (nuevoFormato.equals(FORMATO_FECHA_NORMAL)) {
                nuevaCadena = anio + "-" + mes + "-" + dia + " " + hora + "-" + min + "-" + sec;
            }

            if (nuevoFormato.equals(FORMATO_FECHA_TIMESTAMP)) {
                nuevaCadena = anio + "-" + mes + "-" + dia + " " + hora + "-" + min + "-" + sec + "." + mili;
            }
        } catch (Exception e) {
            // No hacer nada por el momento
            // Debug.imprimirError("\nFecha original=" + cadenaOriginal +
            // "\nFormato=" + formatoOriginal + "\nNueva fecha=" + nuevaCadena +
            // "\nNuevo formato=" + nuevoFormato, e);
        }

        return nuevaCadena;
    }

    /**
     * Metodo que permite sumar dos objetos Integer y devolver el resultado,
     * utilizando dentro de si, transformaciones a tipos de datos long.
     * 
     * @param sum1 Objeto que contiene el primer sumando de la suma.
     * @param sum2 Objeto que contiene el segundo sumando de la suma.
     * 
     * @return Objeto que contiene el resultado de la suma que se efectua.
     * 
     * @throws Exception Levantada si los objeto que vienen como parametro son null.
     */
    public static Integer sumIntegers(Integer sum1, Integer sum2) throws Exception {
        long dtSum1 = sum1.longValue();
        long dtSum2 = sum2.longValue();
        long result = dtSum1 + dtSum2;

        return longToInteger(result);
    }

    /**
     * Metodo que permite sumar un objeto Integer a un tipo de dato int,
     * obteniendo como resultado un objeto Integer con el resultado de la suma de los dos sumandos.
     * 
     * @param sum1 Objeto que contiene el sumando numero uno de la operacion.
     * @param sum2 Tipo de Dato que contiene el sumando numero dos de la operacion a efectuarse.
     * 
     * @return Objeto que contiene el resultado de la suma que se efectua.
     * 
     * @throws Exception Levantada si el sumando uno viene en null o el sumando dos no se encuentra inicializado.
     */
    public static Integer sumIntegers(Integer sum1, int sum2) throws Exception {
        long dtSum1 = sum1.longValue();
        long dtSum2 = Long.valueOf(String.valueOf(sum2)).longValue();
        long result = dtSum1 + dtSum2;

        return longToInteger(result);
    }

    /**
     * Metodo que permite transformar un tipo de dato long a un objeto Integer.
     * Recibe como parametro un tipo de dato long, y transforma su contenido textual a un objeto Integer.
     * 
     * @param dtLong Tipo de Dato que contiene el valor que se desea transformar a un objeto Integer.
     * 
     * @return Objeto que contiene el valor del tipo de dato long enviado como parametro para la transformacion.
     * 
     * @throws Exception Levantada cuando el long que entra como parametro no se encuentra inicializado.
     */
    public static Integer longToInteger(long dtLong) throws Exception {
        String tmp = String.valueOf(dtLong);

        return Integer.getInteger(tmp);
    }

    /**
     * Construye un String a partir de un ResultSet con los separadores proporcionados a la funcion.
     * 
     * @param rs ResultSet del cual se construye el String.
     * @param sepCamp String que indica el separador de campos.
     * @param sepReg String que indica el separador de registros.
     * 
     * @return String construido a partir del ResultSet.
     */
    public static String getResultSetString(ResultSet rs, String sepCamp, String sepReg) {
        StringBuffer rsString = new StringBuffer();

        try {
            ResultSetMetaData rsmd = rs.getMetaData();
            int colCount = rsmd.getColumnCount();

            System.out.println("En la función getResultSetString");

            while (rs.next()) {
                for (int i = 1; i <= colCount; i++) {
                    // TODO: indicar si es necesario comprobar el tipo de cada campo.
                    // Temporalmente todo lo obtiene a traves del getString.
                    rsString.append(rs.getString(i));

                    if (i < colCount) {
                        rsString.append(sepCamp);
                    }
                }

                rsString.append(sepReg);
            }
        } catch (SQLException ex) {
            rsString.append("");
            Debug.imprimirError(ex);
        }

        return rsString.toString();
    }

    /**
     * Metodo que devuelve una objeto tipo clase para invocaciones dinamicas de metodos.
     * 
     * @param nombreClase Nombre de la clase con el paquete completo.
     * 
     * @return Objeto tipo Class para poder instanciar objetos de esa clase.
     * 
     * @throws Exception Excepcion general de java.
     */
    public static Class getClase(String nombreClase) throws Exception {
        Class clase = null;
        clase = Class.forName(nombreClase);

        return clase;
    }

    /**
     * Metodo para instanciar un objeto de una clase en forma dinamica.
     * 
     * @param clase Clase de la cual se requiere una instancia, esta clase debe tener un constructor por defecto.
     * 
     * @return Objeto instanciado de la clase pasada como parametro.
     * 
     * @throws Exception Excepcion general de java.
     */
    public static Object getInstancia(Class clase) throws Exception {
        Object instancia = clase.newInstance();

        return instancia;
    }

    /**
     * Metodo que construye el arreglo correspondiente de tipos de objetos pasados a un metodo dinamicamente.
     * Si uno de los objetos de parametros es null, el tipo de class tambien se deja null y debera instanciarse
     * posteriormente en forma especifica en el indice correspondiente del arreglo retornado.
     * 
     * @param parametros Arreglo de objetos que deben pasarse al metodo.
     * 
     * @return Arreglo de clases a las que corresponden los objetos pasados como parametros.
     */
    public static Class[] getParametrosClases(Object[] parametros) {
        Class[] parametrosClases = new Class[parametros.length];

        for (int i = 0, len = parametros.length; i < len; i++) {
            if (parametros[i] != null) {
                parametrosClases[i] = parametros[i].getClass();
            } else {
                parametrosClases[i] = null;
            }
        }

        return parametrosClases;
    }

    /**
     * Metodo que invoca dinamicamente un metodo de una clase instanciada.
     * 
     * @param clase Clase a la que corresponde la invocacion a realizarse.
     * @param instancia Instancia de la clase que se utiliza para la invocacion.
     * @param nombreMetodo Nombre del metodo a invocar.
     * @param parametros Arreglo de parametros para el metodo a invocar.
     * @param parametrosClases Arreglo de clases a las que corresponden los parametros del metodo a invocar.
     * 
     * @return Objeto en general de java, que debe ser convertido al objeto adecuado en cada caso.
     * 
     * @throws Exception Excepcion general de java.
     */
    public static Object invocaMetodo(Class clase, Object instancia, String nombreMetodo,
    								  Object[] parametros, Class[] parametrosClases) throws Exception {
        try {
            Method metodo = null;
            metodo = clase.getMethod(nombreMetodo, parametrosClases);

            return metodo.invoke(instancia, parametros);
        } catch (InvocationTargetException e) {
            throw (Exception) e.getCause();
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * Funcion que rellena una cadena de caracteres, con el caracter indicado.
     * 
     * @param sCadena String a formatear.
     * @param sCaracter Caracter con el cual se rellenara la cadena.
     * @param iTipo Indica la posicion en la que se rellenara ("0"=izquierda, "?"=derecha).
     * @param iNumeroCaracteres Numero de caracteres a aniadir a la cadena.
     * 
     * @return La cadena formateada.
     */
    public static String rellenaCaracteres(String sCadena, String sCaracter, int iTipo, int iNumeroCaracteres) {
        String sTemp = "";

        if (sCaracter == null) {
            sCaracter = "";
        }

        if (sCadena == null) {
            sCadena = "";
        }

        if (sCaracter.length() == 0 || sCadena.length() > iNumeroCaracteres) {
            return "";
        }

        if (sCadena.length() == iNumeroCaracteres) {
            return sCadena;
        }

        if (sCaracter.length() > 1) {
            sTemp = sCaracter.substring(0, 1);
        } else {
            sTemp = sCaracter;
        }

        for (int i = 0; i <= iNumeroCaracteres; i++) {
            sTemp += sCaracter;
        }

        if (iTipo == 0) {
            // Rellena a la izquierda
            return sTemp.substring(0, iNumeroCaracteres - sCadena.length()) + sCadena;
        } else {
            // Derecha
            return sCadena + sTemp.substring(0, iNumeroCaracteres - sCadena.length());
        }
    } // RellenaCaracteres

    /**
     * Elimina todos los caracteres "0" de una cadena numerica y deja al menos uno.
     * Si viene "000032423" lo deja en "32423".
     * Si la cadena es "000000" devuelve "0".
     * 
     * @param sCadena String a formatear.
     * 
     * @return String formateado.
     */
    public static String eliminaCeros(String sCadena) {

    	return new Integer(sCadena).toString();
    }

}
