<?php

define('INI_CHAR', '{'); // Caracter de inicio
define('END_CHAR', '}'); // Caracter de fin

/**
 * CN_TABLE engulfs most of the services required for data mainuplation by other
 * classes
 *
 * @author narange
 */
class CN_TABLE {

    /**
     * Gets all records of a table
     *
     * @param Doctrine_Table $table_name The name of the table to query
     * @return Doctrine_Collection|array
     */
    public static function getAll($table_name) {
        //Obtener todas las filas de una tabla/vista
        $table = Doctrine_Core::getTable($table_name);
        return $table->findAll();
    }

    /**
     * Gets all records of a table
     *
     * @param Doctrine_Table $table_name The name of the table to query
     * @param boolean $limit_results
     * @param array $criteria
     * @return Doctrine_Collection|array
     */
    public static function getAllWithCriteria($table_name, $limit_results, $criteria) {
        //Obtener todas las filas de una tabla/vista
        $table = Doctrine_Core::getTable($table_name);
    }

    /**
     * crea el sql de consulta para los parametros de entrada
     * devuelve las filas de la base de datos
     *
     * @param array $table_names
     * @param array $table_join_ids
     * @param array $fields
     * @param int $tot_num_records
     * @param array $field_conditions
     * @param array $field_or_conditions
     * @param string $query_qualifier
     * @param array $fields_orderBy
     * @param string $sortBy
     * @return array
     */
    public static function getAllWithFriendFields($table_names, $table_join_ids, $fields, &$tot_num_records, $field_conditions = null, $field_or_conditions = null, $query_qualifier = null, $summatory = null, $sum_res = null, $fields_orderBy = null, $sortBy = null) {

        //se instancia la clase del manejo del log
        $logger = sfContext::getInstance()->getLogger();
        $logger->info("Obtener consulta");


        //valida si viene los datos de ordenamiento
        if (!is_null($fields_orderBy) && is_null($sortBy)) {

            $has_coma = false;
            foreach ($fields_orderBy as $value) {
                if ($has_coma) {
                    $sortBy .= ' , ';
                }
//                if (!is_null($sortBy)) {
//                    $sortBy.=' , ';
//                }
                $sortBy .= $value;
                $has_coma = true;
            }
        }

        //variable para el sql
        $sql = "";
        //array de alias (tab) para las tablas
        $tids = array();
        for ($i = 0; $i < count($table_names); $i++) {
            $tids[$table_names[$i]] = 'tab' . $i;
        }

        //se anexa  total de columnas
        $sql_count = 'SELECT COUNT(*) AS num_filas';
        $qq = $query_qualifier != null ? $query_qualifier : '';
        $logger->info("*** Cualificador: " . $query_qualifier);
        $sql .= "SELECT *
            FROM (SELECT row_.*, ROWNUM rownum_
            FROM ( ";

        $sql_body = "SELECT /*+ First_rows*/ $qq ";

        //recorre cada alias y anexa las variables de las tablas al sql
        foreach ($tids as $tab_name => $alias) {
            if (array_key_exists($tab_name, $fields)) {
                foreach ($fields[$tab_name] as $fname => $falias) {
                    $fexpres = ''; // The expression that will hold the fields
//                    $logger->info("[CN_TABLE] Nombres de campos de tabla. " . $fname);
                    $concats = explode(',', $fname);
                    $i = 0;
                    foreach ($concats as $concat) {

                        //si posee letras el valor
                        if (preg_match('/[A-z_]/', $concat)) {
                            //si es una fecha
                            if (strpos($concat, 'fecha') === false) {
                                $fexpres .= "$alias.$concat";
                            } else {

                                /*
                                 * Si es fecha_log
                                 */
                                if ($concat == 'fecha_log' || $concat == 'fecha_facturacion' || $concat == 'fecha_estado' || $concat == 'fecha_hora_ini' || $concat == 'fecha_hora_fin') {
                                    //cambiar el formato a la fecha
                                    $fexpres .= "to_char($alias.$concat, 'YYYY-MM-DD HH:MI AM')";
                                } else {
                                    //cambiar el formato a la fecha
                                    $fexpres .= "to_char($alias.$concat, 'YYYY-MM-DD')";
                                }
                            }
                        } else {
                            //si posee espacios colocar entre comillas
                            if (preg_match("/ /", $concat)) {

                                $fexpres .= "'$concat'";
                            } else {

                                $fexpres .= "$concat";
                            }
                        }
//                        if ($i < count($concats) - 1) {
//                            $fexpres.= '||';
//                            $i++;
//                        }
                    }

                    $sql_body .= " $fexpres as $falias,";
                }
            }
        }
        $sql_body = substr($sql_body, 0, -1);

        $sql .= $sql_body;

        if (!is_null($query_qualifier)) {
            $sql_count .= " FROM ( " . $sql_body . " ";
        }

        //anexar tabla principal al sql
        $main_tab_name = $table_names[0];
        $sql_from = " FROM $main_tab_name $tids[$main_tab_name]";

        //recorre cada alias y anexa los join de las tablas al sql
        foreach ($table_join_ids as $tab_name => $join_ids) {

            $rel_val = explode(',', $tab_name);
            $tab = $rel_val[0];
            if (count($join_ids) == 0) {
                $sql_from .= ", $tab $tids[$tab]";
            } else {
                $jtype = count($rel_val) > 1 ? $rel_val[1] : '';

                $sql_from .= " $jtype JOIN $tab $tids[$tab] ON";
                $j = 0;
                //join de tablas con sus alias
                foreach ($join_ids as $id_name => $rel_name) {

                    //validar si los alias son diferentes en las tablas
                    if (!preg_match("/-/", $id_name)) {//valida si esta la coma
                        $sql_from .= " $tids[$rel_name].$id_name = $tids[$tab].$id_name";
                    } else {
                        $id_name_alias = explode('-', $id_name); //divide el string en un array
                        $sql_from .= " $tids[$rel_name].$id_name_alias[0] = $tids[$tab].$id_name_alias[1]";
                    }

                    //si hay mas parametros de join
                    if ($j < count($join_ids) - 1) {
                        $sql_from .= ' AND';
                        $j++;
                    }
                }
            }
        }

        $sql .= $sql_from;
        $sql_count .= $sql_from;

        //filtros para la consulta
        $where = '';
        if (!is_null($field_or_conditions) || !is_null($field_conditions)) {
            $where .= ' WHERE ';
        }

        $appendAnd = '';
        $condNorm = '';
        $condCount = '';

        //filtros de condicion or
        if (!is_null($field_or_conditions)) {
            $condOr = CN_TABLE::extractSQLConditions($field_or_conditions, 'OR', $tids, false);
            if (trim($condOr) != '') {
                $condNorm .= ' (' . $condOr . ')';
                $condCount .= ' (' . $condOr . ')';
                $appendAnd .= ' AND ';
            }
        }

        //filtros de condicion and
        if (!is_null($field_conditions)) {

            //validar si hubo parametros de filtro
            $filtro = CN_TABLE::extractSQLConditions($field_conditions, 'AND', $tids, true, $sortBy);
            $logger->info("+-------------------------" . $filtro);

            //debe ser diferente de null, vacio
            //tab indica que hay mas filtros 
            if (preg_match("/tab/", $filtro)) {
                $condNorm .= $appendAnd . $filtro;
            } else {
                $condNorm .= $filtro;
            }

            //validar si hubo parametros de filtro
            $filtro = CN_TABLE::extractSQLConditions($field_conditions, 'AND', $tids, false);
            //debe ser diferente de null, vacio
            //tab indica que hay mas filtros 
            if (preg_match("/tab/", $filtro)) {
                $condCount .= $appendAnd . $filtro;
            } else {
                $condCount .= $filtro;
            }
        }

        if ($condNorm != '') {

//            $sql.= $where == '' ? ') row_ )' : $where . $condNorm;

            if ($where == '') {
                //$fields_orderBy= null, $sortBy=null
                //agregar ordenamiento
                if (!is_null($sortBy)) {
                    $sql .= ' ORDER BY ' . $sortBy;
                }
                $sql .= ' ) row_ )';
            } else {

                $sql .= $where . $condNorm;
            }
        } else {
            //$fields_orderBy= null, $sortBy=null
            //agregar ordenamiento
            if (!is_null($sortBy)) {
                $sql .= ' ORDER BY ' . $sortBy;
            }
            $sql .= ' )  row_ )';
        }

        if ($condCount != '') {
            $sql_count .= $where . $condCount;
        }

        if (!is_null($query_qualifier)) {
            $sql_count .= " ) ";
        }

        //ejecutar el sql
        $count_records = CN_TABLE::executeSQL($sql_count);
        //validar si hay registros
        if (!is_null($count_records)) {
            //contar numero de registros
            $tot_num_records = $count_records[0]['num_filas'];
        }

        return CN_TABLE::executeSQL($sql);
    }

    /**
     * extraer el sql con las condiciones de la consulta
     *
     * @param array $field_conditions
     * @param string $connector
     * @param array $tids the table ids
     * @return string the resulting sql
     */
    public static function extractSQLConditions($field_conditions, $connector, $tids, $with_rows, $sortBy = null) {

        $sql = '';
        $append_row_start = '';

//      $append_row_end = $with_rows ? ' ) row_ )' : '';
        if ($with_rows) {
            //$fields_orderBy= null, $sortBy=null
            //validar campos de ordenamiento
            if (!is_null($sortBy)) {
                $order = ' ORDER BY ' . $sortBy;
            } else {
                $order = '';
            }
            $append_row_end = $order . ' ) row_ )';
        } else {

            $append_row_end = '';
        }

        $i = 0;

        //seleccionar el tipo de filtro en sql
        foreach ($field_conditions as $tab_name => $conditions) {
            $j = 0;
            foreach ($conditions as $id_name => $expres) {
                $id_names = explode(',', $id_name);
                $id_name = $id_names[0];
                $row_type = count($id_names) > 1 ? $id_names[1] : null;
                $k = 0;
                foreach ($expres as $type => $params) {
                    if ($id_name == 'rownum' && !$with_rows) {
                        $sql = substr($sql, 0, -4);
                        $k++;
                    } else if ($id_name == 'rownum') {
                        if ($row_type == 'start')
                            $append_row_start = " WHERE rownum_ $type $params[0] ";
                        if ($row_type == 'end') {

                            if (!is_null($sortBy)) {
                                $order = ' ORDER BY ' . $sortBy;
                            } else {
                                $order = '';
                            }

                            $append_row_end = $order . " ) row_ WHERE ROWNUM $type $params[0]) ";
                        }

                        $sql = substr($sql, 0, -4);
                        $k++;
                    } else {
                        $poner_comillas = false;
                        if ($id_name == 'condition') {
                            $field_names = array();
                            for ($i = 1; $i < count($id_names); $i++) {
                                $field_names[] = $id_names[$i];
                            }
                            // primer parámetro
                            $param1 = explode(',', $params[0]);
                            $full_field_name = "$tids[$tab_name].$param1[1]";
                            //segundo parámetro
                            $param2 = explode(',', $params[1]);
                            $params[0] = "$tids[$tab_name].$param2[1]";
                        } else {
                            /*
                             * si biene un dato que puede tener varios tipos de filtros
                             * extraer el numero 2 que representa dos posibilidades
                             * solo funciona para 2 tipos de filtro y si no se van agregar los dos
                             */
                            if (substr($id_name, -1, 1) == '2') {
                                $id_name = substr($id_name, 0, -1);
                            }


                            $poner_comillas = true;
                            $full_field_name = "$tids[$tab_name].$id_name";
                        }
                        /*
                         * manejo de identificador de filtro sql
                         */
                        switch ($type) {
                            //si es likeall colocar % al inicio y al final
                            case 'LIKEALLPLUS':
                                $full_express = implode('', $params);
                                $full_express = strtolower($full_express);
                                $sql .= " ( LOWER($full_field_name) LIKE '%$full_express' ";

                                //si posee espacios el parametro
                                //se busca por cada uno
                                if (preg_match("/ /", $params[0])) {

                                    //parte el parametro por espacios
                                    $caracteres = preg_split('/ /', $params[0], -1, PREG_SPLIT_NO_EMPTY);

                                    //valida que hay particion por espacios
                                    if (!is_null($caracteres)) {

                                        $sql .= " or ( ";

                                        //para imprimir el parametro de conexion and
                                        $varias = false;
                                        //recorre el parametro dividido en espacios
                                        foreach ($caracteres as $value) {
                                            if ($varias) {
                                                $sql .= " and ";
                                            }

                                            //crea sql para cada valor
                                            $sql .= " LOWER($full_field_name) LIKE '%$value%' ";


                                            $varias = true;
                                        }


                                        $sql .= " ) ";
                                    }
                                }

                                $sql .= " ) ";
                                break;
                            //si es likeall colocar % al inicio y al final
                            case 'LIKEALL':
                                $full_express = implode('', $params);
                                $full_express = strtolower($full_express);
                                $sql .= " ( LOWER($full_field_name) LIKE '%$full_express' ) ";
                                break;
                            //si es like colocar % al final
                            case 'LIKE':
                                $full_express = implode('', $params);
                                $full_express = strtolower($full_express);
                                $sql .= " LOWER($full_field_name) $type '$full_express'";
                                break;
                            //si es: IS NOT NULL o IS NULL
                            case 'IS':
                                $sql .= " $full_field_name $type $params ";
                                break;
                            //si es: IN
                            case 'IN':
                                /* la lista debe venir eg 1,2,3 para numerico o '1','2','3' para string */
                                if(strpos($params[0], 'n')===false){
                                    $sql .= " $full_field_name $type ($params[0])";
                                }else{
                                    $sql .=" 1=1 ";
                                }
                                break;
                            //si es: NOTIN
                            case 'NOTIN':
                                /* la lista debe venir eg 1,2,3 para numerico o '1','2','3' para string */
                                $sql .= " $full_field_name NOT IN ($params[0])";
                                break;
                            //si es: NULL
                            case 'NULL':
                                $sql .= " $full_field_name IS $params[0] ";
                                break;
                            //si es between variables entre and
                            case 'BETWEEN':
                                if ($poner_comillas) {
                                    $params[0] = "'$params[0]'";
                                    $params[1] = "'$params[1]'";
                                }
                                $sql .= " $full_field_name $type $params[0] AND $params[1]";
                                break;
                            /*
                             * si es between variables entre and
                             * prueba para fecha
                             * colocar la conversion de  formato fecha
                             * para no tener en cuenta la hora
                             */
                            case 'BETWEENFECHA':
                                if ($poner_comillas) {
                                    $params[0] = "'$params[0]'";
                                    $params[1] = "'$params[1]'";
                                }
//                                $sql.="  to_char($full_field_name, 'YYYY-MM-DD') BETWEEN $params[0] AND $params[1]";
                                $sql .= "  $full_field_name BETWEEN to_date($params[0], 'YYYY-MM-DD') AND to_date($params[1], 'YYYY-MM-DD') ";
                                //$sql .= "  to_date(to_char($full_field_name,'YYYY-MM-DD'),'YYYY-MM-DD') BETWEEN to_date($params[0], 'YYYY-MM-DD') AND to_date($params[1], 'YYYY-MM-DD') ";
                                break;
                            default:
                                if ($poner_comillas) {
                                    $params[0] = "'$params[0]'";
                                }
                                $sql .= " $full_field_name $type $params[0]";
                                break;
                        }

                        if ($k < count($expres) - 1) {
                            $sql .= " $connector";
                            $k++;
                        }
                    }
                }
                if ($j < count($conditions) - 1) {
                    $sql .= " $connector";
                    $j++;
                }
            }
            if ($i < count($field_conditions) - 1) {
                $sql .= trim($sql) != '' ? " $connector" : '';
                $i++;
            }
        }
        $sql .= $append_row_end . $append_row_start;
        return $sql;
    }

    /**
     * obtener la sumatoria de una consulta
     *
     * @param array $table_names
     * @param array $table_join_ids
     * @param array $summatory_data
     * @return array
     */
    public static function getSum($table_names, $table_join_ids, $fields, $summatory_data, $field_conditions = null, $field_or_conditions = null, $query_qualifier = null) {
        $tids = array();
        for ($i = 0; $i < count($table_names); $i++) {
            $tids[$table_names[$i]] = 'tab' . $i;
        }
        // sum supper clause
        //sql de sum
        $sql = " SELECT ";
        //variables a realizar la sumatorio
        foreach ($tids as $tab_name => $alias) {
            if (array_key_exists($tab_name, $summatory_data)) {
                if (array_key_exists('count', $summatory_data[$tab_name])) {
                    $sql .= " count(*) as " . $summatory_data[$tab_name]['count'] . ", ";
                }
                foreach ($summatory_data[$tab_name]['fields'] as $fname) {
                    /*
                     * Validar que no posea case o demas operaciones - Modifico 20120514
                     */
                    if (!preg_match("/#/", $fname)) {//valida si esta la coma
                        $sql .= " SUM($fname) AS $fname,";
                    } else {
                        $fname_array = explode('#', $fname); //divide el string en un array

                        $sql .= " SUM($fname_array[0]) AS $fname_array[1],";
                    }
                }
                if (array_key_exists('labels', $summatory_data[$tab_name])) {
                    foreach ($summatory_data[$tab_name]['labels'] as $label) {
                        $labelValues = explode(',', $label);
                        $labelField = $labelValues[0];
                        $labelDisplay = count($labelValues) > 1 ? $labelValues[1] : '';
                        $sql .= " '$labelDisplay' AS $labelField,";
                    }
                }
            }
        }

        $sql = substr($sql, 0, -1);

        // Include query qualifier in an inner clause
        $qq = $query_qualifier != null ? $query_qualifier : '';
        //adjuntar sql pra la sumatoria
        $sql .= " FROM ( SELECT $qq  ";
        foreach ($tids as $tab_name => $alias) {
            if (array_key_exists($tab_name, $fields)) {
                foreach ($fields[$tab_name] as $fname => $falias) {
                    $fexpres = ''; // The expression that will hold the fields
                    $concats = explode(',', $fname);
                    $i = 0;
                    foreach ($concats as $concat) {
                        if (preg_match('/[A-z_]/', $concat)) {
                            //validar si es fecha
                            if (strpos($concat, 'fecha') === false)
                                $fexpres .= "$alias.$concat";
                            else
                            //cambiar el formato de fecha
                                $fexpres .= "to_char($alias.$concat, 'YYYY-MM-DD')";
                        }
                        else {
                            //si posee un espacio
                            if (preg_match("/ /", $concat)) {

                                $fexpres .= "'$concat'";
                            } else {

                                $fexpres .= "$concat";
                            }
                        }
//                        if ($i < count($concats) - 1) {
//                            $fexpres.= '||';
//                            $i++;
//                        }
                    }

                    $sql .= " $fexpres as $falias,";
                }
            }
        }

        $sql = substr($sql, 0, -1);

        // From clause
        $main_tab_name = $table_names[0];
        //tabla principal
        $sql_from = " FROM $main_tab_name $tids[$main_tab_name]";

        //tablas de join
        //recorre cada alias y anexa los join de las tablas al sql
        foreach ($table_join_ids as $tab_name => $join_ids) {

            $rel_val = explode(',', $tab_name);
            $tab = $rel_val[0];
            if (count($join_ids) == 0) {
                $sql_from .= ", $tab $tids[$tab]";
            } else {
                $jtype = count($rel_val) > 1 ? $rel_val[1] : '';

                $sql_from .= " $jtype JOIN $tab $tids[$tab] ON";
                $j = 0;
                //join de tablas con sus alias
                foreach ($join_ids as $id_name => $rel_name) {

                    //validar si los alias son diferentes en las tablas
                    if (!preg_match("/-/", $id_name)) {//valida si esta la coma
                        $sql_from .= " $tids[$rel_name].$id_name = $tids[$tab].$id_name";
                    } else {
                        $id_name_alias = explode('-', $id_name); //divide el string en un array

                        /*
                         * Si las variables son por request - Modifico 20120514
                         */
                        if ($id_name_alias[1] == 'request') {

                            $valor = $request[$rel_name];

                            $sql_from .= " $tids[$tab].$id_name_alias[0] = '$valor'";
                        } else {

                            $sql_from .= " $tids[$rel_name].$id_name_alias[0] = $tids[$tab].$id_name_alias[1]";
                        }
                    }

                    //si hay mas parametros de join
                    if ($j < count($join_ids) - 1) {
                        $sql_from .= ' AND';
                        $j++;
                    }
                }
            }
        }

        //antes 20111122
//        foreach ($table_join_ids as $tab_name => $join_ids) {
//
//            //divide la variable por coma (,)
//            $rel_val = explode(',', $tab_name);
//            $tab = $rel_val[0];
//            $jtype = count($rel_val) > 1 ? $rel_val[1] : '';
//
//            $sql_from.=" $jtype JOIN $tab $tids[$tab] ON";
//            $j = 0;
//            foreach ($join_ids as $id_name => $rel_name) {
//                $sql_from.=" $tids[$rel_name].$id_name = $tids[$tab].$id_name";
//                if ($j < count($join_ids) - 1) {
//                    $sql_from.= ' AND';
//                    $j++;
//                }
//            }
//        }

        $sql .= $sql_from;

        //filtros para la consulta
        $where = '';
        if (!is_null($field_or_conditions) || !is_null($field_conditions)) {
            $where .= ' WHERE ';
        }

        $appendAnd = '';
        //filtros de condicion or
        if (!is_null($field_or_conditions)) {
            $where .= '(' . CN_TABLE::extractSQLConditions($field_or_conditions, 'OR', $tids, false) . ')';
            $appendAnd .= ' AND ';
        }
        //filtros de condicion and
        if (!is_null($field_conditions)) {
            $where .= $appendAnd . CN_TABLE::extractSQLConditions($field_conditions, 'AND', $tids, false);
        }

        $sql .= $where;

        //recorre los valores y construye parte del sql
        foreach ($tids as $tab_name => $alias) {
            if (array_key_exists($tab_name, $summatory_data)) {
                foreach ($summatory_data[$tab_name] as $data_id => $data_val) {
                    $id = explode(',', $data_id);
                    $name = $id[0];
                    if ($name == 'condition') {
                        $sql .= $where != '' ? ' AND ' : ' WHERE ';
                        $where = $where != '' ? $where : ' WHERE ';
                        foreach ($data_val as $cond_val) {
                            if ($cond_val != 'field') {
                                $sql .= $cond_val;
                            } else {
                                $sql .= "$alias.$id[1]";
                            }
                        }
                    }
                }
            }
        }
        $sql .= ' ) ';

        //ejecutar el sql
        return CN_TABLE::executeSQL($sql);
    }

    /**
     * ejecuta un sql en la base de datos
     * @param string $sql
     * @param boolean $noRevisar enviar true en caso de que se quiera que la conexion no cambie las variables de numeros a booleanas, no enviar ningun parametro en caso contrario
     * @return array
     */
    public static function executeSQL($sql, $noRevisar = null) {

        //realiza la conexion a la base de datos
        $conn = Doctrine_Manager::connection();
        //ejecuta el sql y obtiene todos los resultados
        $results = $conn->execute($sql)->fetchAll();

        //inicializa variable de retorno
        $records = array();

        //recorre los resultados de la consulta 
        foreach ($results as $result) {
            $record = array();
            foreach ($result as $key => $value) {
                $key = strtolower($key);
                //cambia los datos para los campos boolean
                if ($noRevisar == null) {
                    if (       $key == 'estado' 
                            || $key == 'operador' 
                            || $key == 'festivo' 
                            || $key == 'actual' 
                            || $key == 'activo' 
                            || $key == 'liquida'
                            || $key == 'aplica_iva'
                            || $key == 'radicado'
                            || $key == 'medio_dia'
                            || $key == 'cumplido'
                            || $key == 'cierre'
                            || $key == 'pago'
                            || $key == 'comision'
                            || $key == 'viatico'
                            || $key == 'viaje'
                            || $key == 'aplica_ica'
                            || $key == 'zona_roja'
                            || $key == 'func_inv'
                            || $key == 'interrupcion'
                            || $key == 'firmado'
                            || $key == 'aprobado'
                            || $key == 'autorizado'
                            || $key == 'aplica_tarifa_taxis'
                            || $key == 'sgr'
                            || $key == 'marca_automatico'
                            || $key == 'aplica_dias_ini_mes_regis_planea'
                            || $key == 'aplica_hora_regis_planea'
                            || $key == 'aplica_tiquete'
                            || $key == 'aplica_solicitud'
                            || $key == 'lider'
                            || $key == 'aplica_dias_tarifa'
                            || $key == 'servicio_ini_aero'
                            || $key == 'aplica_solicitud_aerea'
                            || $key == 'aplica_solicitud_terrestre'
                            || $key == 'traslada_equipos'
                            || $key == 'pernocta'
                    )
                        $value = $value == 1 ? true : false;
                }
                $record[strtolower($key)] = $value;

//                echo $key . " - " . $value . " * ";
            }
            $records[] = $record;
        }
        //retorna el resultado con los cambios pertinentes
        return $records;
    }

    /**
     * To get the memory usage in KB or MB
     * @param type $size
     * @return type
     */
    public static function convert($size) {
        $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
        return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i];
    }

    /**
     * Ejecuta un sql en la base de datos con variables bind - 20130801
     * @param string $sql Consulta SQL de tipo bind Ejemplo: "SELECT * FROM PEOPLE WHERE NAME=:name AND AGE=:age"
     * @param type $noRevisar Enviar true en caso de que se quiera que la conexion no cambie las variables de numeros a booleanas, no enviar ningun parametro en caso contrario
     * @param type $record_bind Record de las variables a reemplazar de tipo bind
     * @return type
     */
    public static function executeBindSQL($sql, $noRevisar = null, $record_var_bind = array(), $record_bind = array()) {

//        $logger = sfContext::getInstance()->getLogger();
//        $logger->info("[CN_TABLE] Sql Bind: " . $sql);

        $logPath = sfConfig::get('sf_log_dir') . '/liquidacion.log';
        $custom_logger = new sfFileLogger(new sfEventDispatcher(), array('file' => $logPath));

        $custom_logger->info("[CN_TABLE] memory_get_usage ini executeBindSQL: " . memory_get_usage() . "\n");

        gc_enable(); // Activar recolector de basuras
        $custom_logger->info("[CN_TABLE] " . gc_enabled()); // true
        gc_collect_cycles();
        try {

            /*
             * Inicializa variable de retorno
             */
            unset($records);
            $records = null;
            $records = array();
            $records_table = $record_bind;
            $record_bind = array();

            $custom_logger->info("[CN_TABLE] memory_get_usage 00 executeBindSQL: " . memory_get_usage() . "\n");
            /*
             * CONNECT TO SERVER.-----------------------------------------------
             */
            //realiza la conexion a la base de datos
            $conn = Doctrine_Manager::connection();

            $custom_logger->info("[CN_TABLE] memory_get_usage 0100 executeBindSQL: " . memory_get_usage() . "\n");
            //echo("Connected to database.\n"); 

            /*
             * PREPARE STATEMENT.-----------------------------------------------------
             */
//            $logger->info("[CN_TABLE] -------------------------------------------------------    1   ");
            $stmt = $conn->prepare($sql);

            /*
             * BIND VARIABLES.--------------------------------------------------------   
             */
//            $stmt->bindValue("name", 'John');
//            $stmt->bindValue("age", 99);
//            foreach ($record_var_bind as $key => $value) {
//                $stmt->bindValue($key, $value);
//            $logger->info("[CN_TABLE] -------------------------------------------------------    2    ");
//            $stmt->bindValue("periodo", 103);
//            $stmt->bindValue("num_doc", '10011338');
//                $stmt->bindValue("id_concep_nomina", 151);
//            $stmt->bindValue("id_tipo_doc", 1);
//            $stmt->bindValue("tag", 1);
//            $stmt->bindValue("id_periodo_ajuste", 103);
//            $stmt->bindValue("id_concep_nomina", $record_bind['id_concep_nomina']);
//                $stmt->bindValue($value, $record_bind[$value]);
//            $stmt->bindValue(1, 151);
//            }
            $custom_logger->info("[CN_TABLE] memory_get_usage 0101 executeBindSQL: " . memory_get_usage() . "\n");
            unset($conn, $sql);
            $custom_logger->info("[CN_TABLE] memory_get_usage 01 executeBindSQL: " . memory_get_usage() . "\n");
            foreach ($record_var_bind as $key => $value) {
                if (isset($records_table[$value])) {
                    $record_bind[$value] = $records_table[$value];
                } else {
                    $record_bind[$value] = '';
                }
            }
            $custom_logger->info("[CN_TABLE] memory_get_usage 021 executeBindSQL: " . memory_get_usage() . "\n");
            unset($records_table, $key, $value, $record_var_bind);
            $custom_logger->info("[CN_TABLE] memory_get_usage 022 executeBindSQL: " . memory_get_usage() . "\n");

            /*
             * Cambiar variable texto null por vacio
             */
            foreach ($record_bind as $key => $value) {
                if ($value == 'null') {
                    $record_bind[$key] = '';
                }
            }

            /*
             * EXECUTE STATEMENT.-----------------------------------------------------   
             */
//            $logger->info("[CN_TABLE] -------------------------------------------------------    3    ");
            $stmt->execute($record_bind);
            unset($record_bind);
            $custom_logger->info("[CN_TABLE] memory_get_usage 023 executeBindSQL: " . memory_get_usage() . "\n");
            /*
             * DISPLAY RESULTS.-------------------------------------------------------       
             */
//            $logger->info("[CN_TABLE] -------------------------------------------------------    4   ");
            $results = $stmt->fetchAll();
//            $results = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
//            $logger->info("[CN_TABLE] Cantidad Record: " . count($results) . "\n");
//            foreach ($results as $row) {
//                foreach ($row as $key => $value) {
//                    $logger->info("[CN_TABLE] Datos Record: " . $key . " - " . $value . "\n");
//                }
//            }

            /*
             * Recorre los resultados de la consulta  para cambiar valores booleanos
             */
            foreach ($results as $result) {
                $record = array();
                foreach ($result as $key => $value) {
                    $key = strtolower($key);
                    //cambia los datos para los campos boolean
                    if ($noRevisar == null) {
                        if ($key == 'estado'
                            || $key == 'operador'
                            || $key == 'festivo'
                            || $key == 'actual'
                            || $key == 'activo'
                            || $key == 'liquida'
                            || $key == 'aplica_iva'
                            || $key == 'radicado'
                            || $key == 'medio_dia'
                            || $key == 'cumplido'
                            || $key == 'cierre'
                            || $key == 'pago'
                            || $key == 'comision'
                            || $key == 'viatico'
                            || $key == 'viaje'
                            || $key == 'aplica_ica'
                            || $key == 'zona_roja'
                            || $key == 'func_inv'
                            || $key == 'interrupcion'
                            || $key == 'firmado'
                            || $key == 'aprobado'
                            || $key == 'autorizado'
                            || $key == 'aplica_tarifa_taxis'
                            || $key == 'sgr'
                            || $key == 'lider'
                            || $key == 'servicio_ini_aero'
                            || $key == 'aplica_solicitud_aerea'
                            || $key == 'aplica_solicitud_terrestre'  
                            || $key == 'traslada_equipos'
                            || $key == 'pernocta'
                        )
                            $value = $value == 1 ? true : false;
                    }
                    $record[strtolower($key)] = $value;

//                echo $key . " - " . $value . " * ";
                }
                $records[] = $record;
            }

            $stmt->closeCursor();
        } catch (Exception $e) {
//            $logger->info("[CN_TABLE] -------------------------------------------------------    Error Bind   ");
//            $logger->info($e->getMessage());
            $stmt->closeCursor();
        }

        /*
         * Retorna el resultado con los cambios pertinentes
         */
        //Destruye una variable especificada
        $custom_logger->info("[CN_TABLE] memory_get_usage pre executeBindSQL: " . memory_get_usage() . "\n");
//        unset($records_table, $record_bind, $conn, $stmt, $results, $record, $record_var_bind, $sql);
        $records_table = null;
        $record_bind = null;
        $conn = null;
        $stmt = null;
        $results = null;
        $record = null;
        $record_var_bind = null;
//        $custom_logger->info("[CN_TABLE] " . gc_collect_cycles()); // # de elementos limpiados
//        gc_collect_cycles(); // Función de recolección de ciclos forzosa
//        $custom_logger->info("[CN_TABLE] " . gc_collect_cycles()); // # de elementos limpiados
//        gc_disable(); // Desactivar el recolector
        $custom_logger->info("[CN_TABLE] memory_get_usage post executeBindSQL: " . memory_get_usage() . "\n");

        return $records;
    }

    /**
     * adjunta una fila en la base
     *
     * @param <type> $table_name
     * @param array $values
     * @param <type> $id_name
     * @param <type> $id_names
     * @param <type> $field_names
     * @param <type> $has_id_cia
     * @param <type> $has_activo
     * @param string $check_exists
     * @param <type> $has_vigencia
     * @param <type> $other_tab_uq_fields
     * @return Doctrine_Record
     */
    public static function addRow($table_name, array $values, $id_name, $id_names, $field_names, $has_id_cia, $has_activo, $check_exists, $has_vigencia, $other_tab_uq_fields, $has_secuencia = true) {



        /*
         * Variables globales del proyecto
         */
        $tabla_seg = sfConfig::get('app_tablaSeg');
        $tabla_vig_seg = sfConfig::get('app_tablaVigSeg');



        //se instancia la clase del manejo del log
        $logger = sfContext::getInstance()->getLogger();
        $other_tab_vals = array();

        /*
         * recorrer los campos y colocar null(vacio)
         */
        if (!is_null($field_names)) {
            foreach ($field_names as $field_names_value) {
                //si no esta el valor
                if (isset($values[$field_names_value])) {
//                $values[$field_names_value] = null;
                    $logger->info("--+--" . $field_names_value);
                } else {
                    $values[$field_names_value] = null;
                    $logger->info("--*--" . $field_names_value);
                }
            }
        }


        // Populate values with dependent data
        if (!is_null($other_tab_uq_fields)) {

            //recorre las variables para la consulta en otras tablas
            foreach ($other_tab_uq_fields as $fname => $tab_props) {

                //divide la variable
                $fnames = explode(",", $fname);

//                if ($fnames || $fnames < 1) {
//                    $fnameArray = $fnames;
//                } else {
//                    $fnameArray = array($fname);
//                }

                $logger->info("*********************************************1-" . $fname);
                //recorre los campos para la combinacion de ids de otros campos, tabla y
                foreach ($tab_props as $tab_name => $fields) {
                    $key_found = true;
                    //recorre todos los campos para verificar si biene datos y no son nulos
                    foreach ($fnames as $fname) {
                        $logger->info($values[$fname] . "*********************************************2-" . $fname);
                        $key_found = $key_found &&
                                array_key_exists($fname, $values) &&
                                $values[$fname] != null &&
                                $values[$fname] != 'null';

                        if ($values[$fname] != 'null') {

                            $logger->info("*********************************************entro" . $fname);
                        } else {
                            $logger->info("*********************************************no entro" . $fname);
                        }

                        $logger->info("*********************************************variables-" . $values[$fname]);
                        $logger->info("*********************************************3-" . $key_found);
                    }
//                    $key_found = true; //corregir por que no entra la parte de arriba
                    //valida para la busqueda del id
                    if ($key_found) {



                        $logger->info("*********************************************4-");
                        $record = CN_TABLE::getByIdNames($tab_name, $fnames, $values); //obtiene el id para la tabla y campos requeridos diferentes
                        //valida si hay resultado
                        if (!is_null($record)) {
                            //recorre los campos y anexa el valor del record
                            foreach ($fields as $field) {

                                $values[$field] = $record[$field];
                                $logger->info("*********************************************5-" . $values[$field]);

                                $other_tab_vals[$field] = $record[$field];
                                $logger->info("*********************************************6-" . $other_tab_vals[$field]);
                            }
                        } else {


                            /*
                             * recorre los campos y anexa el valor del record - 20111014
                             * Si los datos no se encuentras de cambian por null(vacio)
                             */
                            foreach ($fields as $field) {

                                $values[$field] = null;
//                                unset($values[$field]);
                            }
                        }
                    } else {

                        /*
                         * recorre los campos y anexa el valor del record - 20111014
                         * Si los datos no se encuentras de cambian por null(vacio)
                         */
                        foreach ($fields as $field) {

                            $values[$field] = null;
//                            unset($values[$field]);
                        }
                    }
                }
            }
        }
//        die(); 

        $existing_record = null;

        // Check if the existing one should return
        if (!is_null($check_exists)) {

            //si posee id_cia
            if ($has_id_cia) {
                $check_exists[] = 'id_cia';
            }

            //valida si hay la combinacion con las variables de los campos especificados en check_exist esta ya en la base de datos
            $existing_record = CN_TABLE::getByIdNames($table_name, $check_exists, $values);
        }

        // Create the record
        $table = Doctrine_Core::getTable($table_name); // Fetch the table type
        $record = $table->create();

        //valida si hay la combinacion con las variables de los campos especificados en check_exist
        if ($existing_record != null) {
            $logger->info("[CN_TABLE] Record exists.");
            $record = $existing_record;
        }

        //si exite y hay valores
        if ($existing_record != null && count($values) > 0) {
            $record = $existing_record; // if it existed, then apply it
            $logger->info("[CN_TABLE] Updating record.");
            foreach ($values as $key => $value) {
                if (!in_array($key, $id_names) && $key != 'id_cia' && in_array($key, $field_names)) {
                    $record[$key] = $value;
                    $logger->info("[CN_TABLE] Changing record[$key] = $value");
                }
            }
            $logger->info("[CN_TABLE] Fin Changing record.");

            $logger->info("[CN_TABLE] *** " . $id_name);
            // -- Forced update
            $values[$id_name] = $existing_record[$id_name];
            $tab_id = 'tab';
            $set_segment = '';
            $where_segment = '';
            $q = Doctrine_Query::create()->update("$table_name $tab_id");
            foreach ($values as $key => $value) {
                if (!in_array($key, $id_names) && $key != 'id_cia' && in_array($key, $field_names)) {
                    $q = $q->set("$tab_id.$key", "'$value'");
                } else if (in_array($key, $id_names)) {
                    $where_segment .= " $tab_id.$key = '$value' AND";
                }
            }
            $set_segment = substr($set_segment, 0, -1); //eliminar la ultima posicion
            $where_segment = substr($where_segment, 0, -3); //eliminar el ultimo and

            $q = $q->where($where_segment);

            //actualiza la secuencia para la tabla
            if ($has_secuencia) {
                $logger->info("[CN_TABLE] Actualiza la secuencia para la tabla NEXTVAL.");
                CN_TABLE::executeSQL("SELECT " . $table_name . "_SEQ.NEXTVAL FROM DUAL"); // Invoke this or it won't work
            }

            //ejecuta el sql de adicion
//            $logger->info("[CN_TABLE] SQL ".$q);
            CN_TABLE::executeSQL($q->getSqlQuery());
            $logger->info("[CN_TABLE] Fin updating record.");
        }

        // Check if the id_name comes in
        $seqId = null;
        if ($existing_record == null && !is_null($id_name) && $has_secuencia) {
            $logger->info("[CN_TABLE] Check seq the $tabla_seg and $tabla_vig_seg.");
            if ($has_id_cia && !$has_vigencia) {// is it a company id?
                // Get the sequence for that company and table
                $seq = CN_TABLE::getByIds($tabla_seg, array(
                            'id_cia' => $values['id_cia'],
                            'nom_entidad' => $table_name)
                );
                // if it doesn't exist, create it
                if (is_null($seq)) {
                    $seq = CN_TABLE::addRow($tabla_seg, array(
                                'id_cia' => $values['id_cia'],
                                'nom_entidad' => $table_name,
                                'seq' => 0), null, null, null, false, false, null, false, null);
                }

                $seq->seq++; // increment the sequence
                $seq->save(); // persist it
                $seqId = $seq->seq; // assign it to the id
            } else if ($has_id_cia && $has_vigencia) { // if not, is it a vigencia sequence??
                //verificar si es con id o no
                if (!isset($values['id_vigencia'])) {
                    $values['id_vigencia'] = $values['vigencia'];
                }

                // Get the sequence for that company and table
                $seq = CN_TABLE::getByIds($tabla_vig_seg, array(
                            'id_cia' => $values['id_cia'],
                            'nom_entidad' => $table_name, 'id_vigencia' => $values['id_vigencia'])
                );

                if (is_null($seq)) { // if it doesn't exist, create it
                    $seq = CN_TABLE::addRow($tabla_vig_seg, array(
                                'id_cia' => $values['id_cia'],
                                'id_vigencia' => $values['id_vigencia'],
                                'nom_entidad' => $table_name,
                                'seq' => 0), null, null, null, false, false, null, false, null);
                }
                $seq->seq++; // increment the sequence
                $seq->save(); // persist it
                $seqId = $seq->seq; // assign it to the id
            } else if (!$has_id_cia && $has_vigencia) {// Sino tiene id_cia, pero si vigencia
                //verificar si es con id o no
                if (!isset($values['id_vigencia'])) {
                    $values['id_vigencia'] = $values['vigencia'];
                }

                // Get the sequence for that company and table
                $seq = CN_TABLE::getByIds($tabla_vig_seg, array(
                            'nom_entidad' => $table_name, 'id_vigencia' => $values['id_vigencia'])
                );

                // if it doesn't exist, create it
                if (is_null($seq)) {
                    $seq = CN_TABLE::addRow($tabla_vig_seg, array(
                                'id_vigencia' => $values['id_vigencia'],
                                'nom_entidad' => $table_name,
                                'seq' => 0), null, null, null, false, false, null, false, null);
                }

                $seq->seq++; // increment the sequence
                $seq->save(); // persist it
                $seqId = $seq->seq; // assign it to the id
            }
        }

        /*
         * prueba para ts_im
         * funciona para no seguir la secuencia, pero aun implica que se lleve el consecutivo en la tabla de CN_TABLE_SEQ
         * se cambia valor por el que ingrese el usuario
         */
//        if ($id_name == 'id_ts_im') {
//            $seqId = $values[$id_name];
//            $logger->info("*** Cambio de id de secuencia: " . $seqId . "-" . $id_name);
//        }

        $logger->info("[CN_TABLE] Listo para guardar.");

        if (!is_null($seqId) && $existing_record == null) { // If the seqId is set
            $logger->info("[CN_TABLE] Saving! with secuence in table");
            $values[$id_name] = $seqId; // Assign it to the new record
            $record->fromArray($values); // Assign the values from the array
            $record->save(); // Save the record
        } else if ($existing_record == null) {
            $logger->info("[CN_TABLE] Saving! with secuence in db");
            $record->fromArray($values); // Assign the values from the array
            $record->save(); // Save the record
            if (is_null($seqId) && !is_null($id_name) && $has_secuencia && !($has_id_cia && $has_vigencia)) {
                $logger->info("[CN_TABLE] SI Actualizar secuencia.");
                $conn = Doctrine_Manager::connection();
                $record[$id_name] = $conn->lastInsertId($table_name);
            } elseif (is_null($seqId) && !is_null($id_name) && !$has_secuencia) {

                $logger->info("[CN_TABLE] SI/NO Actualizar secuencia.");
                $conn = Doctrine_Manager::connection();
                $record[$id_name] = $conn->lastInsertId($table_name);
            } else {

                $logger->info("[CN_TABLE] NO Actualizar secuencia.");
            }
        }

//    if ($existing_record != null) {
//      foreach ($values as $key => $value) {
//        if (!in_array($key, $id_names) && $key != 'id_cia') {
//          $record[$key] = $value;
//          $logger->info("[CN_TABLE] Changing record[$key] = $value");
//        }
//      }
//      $logger->info('[CN_TABLE] Writing form existing');
//    }

        if (is_null($seqId) && !is_null($id_name) && is_null($existing_record)) {
            // if it has a name for its id
            // and no id assigned, ask for
            // it from an apparent
            // existing sequence
        }

        // poner los valores que se esperaban de la otra tabla
        if (count($other_tab_vals) > 0) {
            foreach ($other_tab_vals as $key => $value) {
                $record[$key] = $value;
            }
        }

        return $record;
    }

    /**
     * actualizar fila
     *
     * @param <type> $record
     * @param array $values
     * @return <type>
     */
    public static function updateRow($record, array $values) {
        $record->synchronizeWithArray($values);
        $record->save();
        return $record;
    }

    /**
     *
     * @param <type> $record
     * @param array $values
     * @return <type>
     */
    public static function updateRowFromContainer(Doctrine_Record $record, array $value_names, $container, $fecha_sistema) {

        //crea un array de record para la actualizacion
        foreach ($value_names as $name) {

            $record[$name] = sfAPIActions::extractIfBoolean($container[$name]);
        }

        //anexa variables de fecha sistema que lo requieran
        if ($fecha_sistema && isset($fecha_sistema)) {//agregada, arrojaba un warning - 20111118
            foreach ($fecha_sistema as $key => $value) {

                $record[$key] = $value;
            }
        }

        //guarda el record
        $record->save();
        return $record;
    }

    /**
     * obtener los nombres de los id de una tabla por los campos requeridos
     *
     * @param <type> $table_name
     * @param array $id_names
     * @param array $ids
     * @return <type>
     */
    public static function getByIdNames($table_name, array $id_names, array $ids) {
        $table = Doctrine_Core::getTable($table_name);

        $where = '';
        for ($i = 0; $i < count($id_names); $i++) {

            /*
             * Para el num_doc debe manejarse como texto - 20120309
             */
            if ($id_names[$i] == 'num_doc') {
                $id_val = '\'' . $ids[$id_names[$i]] . '\'';
            } else {
                $id_val = is_numeric($ids[$id_names[$i]]) ? $ids[$id_names[$i]] : '\'' . $ids[$id_names[$i]] . '\'';
            }

            $where .= "$id_names[$i] = $id_val";
            if ($i < count($id_names) - 1)
                $where .= ' AND ';
        }
        $res = null;
        $records = $table->findByDql($where);
        //Se cambia para que no valide solo con un registro, sino mas de uno - 20160620
        if (sizeof($records) >= 1) {
            $res = $records->getFirst();
        }
        return $res;
    }

    /**
     * obtener el id para los campos de una tabla
     *
     * @param <type> $table_name
     * @param array $ids
     * @return <type>
     */
    public static function getByIds($table_name, array $ids) {
        $table = Doctrine_Core::getTable($table_name);
        $where = '';
        $i = 0;
        foreach ($ids as $key => $value) {
            $where .= "$key = ";
            if (is_numeric($value)) {
                $where .= "$value";
            } else {
                $where .= "'$value'";
            }

            if ($i < count($ids) - 1) {
                $where .= ' AND ';
                $i++;
            }
        }
        $res = null;
        $records = $table->findByDql($where);
        //Se cambia para que no valide solo con un registro, sino mas de uno - 20160620
        if (sizeof($records) >= 1) {
            $res = $records->getFirst();
        }
        return $res;
    }

    /**
     *
     * @param <type> $table_name
     * @param array $id_names
     * @param array $ids
     * @return <type>
     */
    public static function getByIdFromContainer($table_name, array $id_names, $id_cont, $has_name_texto = false) {

        //se instancia la clase del manejo del log
        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] Metodo obtener id.");


        $table = Doctrine_Core::getTable($table_name);

        $where = '';
        $ids = array();
        for ($i = 0; $i < count($id_names); $i++) {

            //si el id_name es texto
            if ($has_name_texto) {
                $where .= "$id_names[$i] = " . "'" . $id_cont[$id_names[$i]] . "'";
            } else {
                $where .= "$id_names[$i] = " . $id_cont[$id_names[$i]];
            }

            if ($i < count($id_names) - 1)
                $where .= ' AND ';
        }
        $res = null;
        $logger->info("[CN_TABLE] Where: " . $where);
        $records = $table->findByDql($where);
        if (sizeof($records) == 1) {
            $res = $records->getFirst();
        }


        foreach ($records as $value) {

            $logger->info("******recorrer respuesta where: " . $value);
        }
        $logger->info("******recorrer respuesta where: " . $records->__toString());
//            $logger->info("******recorrer respuesta where: " . $res->toArray());

        return $res;
    }

    /**
     * eliminar el id para la tabla
     *
     * @param <type> $table_name
     * @param array $id_names
     * @param array $ids
     * @return <type>
     */
    public static function deleteById($table_name, array $id_names, array $ids) {
        $record = CN_TABLE::getById($table_name, $id_names, $ids);
        $success = $record->delete();

        return $success;
    }

    /**
     * eliminar una fila de la base de datos
     *
     * @param <type> $record
     * @return <type>
     */
    public static function delete($record) {
        $success = $record->delete();

        return $success;
    }

    /**
     * Metodo que registra en la tabla_log una fila para el control de logs
     *
     * @param <type> $id_tabla
     * @param <type> $id_vigencia
     * @param <type> $cen_op
     * @param <type> $id_cia
     * @param <type> $id_mae_bd
     * @param <type> $id_ope_bd
     * @param <type> $id_mae_ter
     * @param <type> $usuario
     * @param <type> $fecha_log
     * @param <type> $comando
     * @param <type> $observacion
     * @param <type> $ip_address
     * @return <type>
     */
    public static function registroTableLog($id_tabla, $id_ope_bd, $id_mae_bd, $usuario, $username, $comando, $observacion, $ip_address = null) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] Entro registro tabla log.");

        /*
         * Variables globales del proyecto
         */
        $modulo = sfConfig::get('app_modulo');
        $usuarioERP = sfConfig::get('app_usuarioERP');
        $claveERP = sfConfig::get('app_claveERP');
        $tabla_log = sfConfig::get('app_tablaLog');

        //Ip del servidor o equipode ingreso - 20210617
        if (is_null($ip_address)) {
            $ip_address = $_SERVER['REMOTE_ADDR'];
        }

        try {
            //sentencia sql para registro log
            $sql = <<<EOD
INSERT INTO $tabla_log (ID_TABLA,ID_ANHO,ID_MAE_BD,ID_OPE_DB,ID_MAE_TER,USUARIO,FECHA_LOG,COMANDO,OBSERVACION,IP_ADDRESS) 
VALUES ($id_tabla, extract(year from sysdate), $id_mae_bd ,$id_ope_bd, $usuario, '$username', sysdate, '$comando', $observacion, '$ip_address')
EOD;


            //ejecuta y obtiene el resultado del sql
            CN_TABLE::executeSQL($sql);

            //  $logger->info("[CN_TABLE] sql: " . $sql);
        } catch (Excepcion $e) {
            $logger->info("[CN_TABLE]Error al insertar el log");
        }
//        $results = CN_TABLE::executeOCI_SQL_Add($sql, $usuarioERP, $claveERP);

        /*
         * IMPRESION SQL EN EL ARCHIVO DE LOG
         */


        return $sql;
    }

    /**
     * Metodo que registra en la tabla_log una fila para el control de logs
     *
     * @param <type> $request
     * @param <type> $id_ope_bd 
      //1 - indica operacion de consultar
      //2 - indica operacion de actualizar
      //3 - indica operacion de adicionar
      //4 - indica operacion de eliminar
      //5 - indica operacion de anular
     * @param <type> $observacion
     * @return <type>
     */
    public static function registrarLog(sfWebRequest $request, $id_ope_bd, $id_mae_bd, $observacion = null) {
        $logger = sfContext::getInstance()->getLogger();
        $sql = "";
        try {



            //TODO 
            $id_tabla = 'null';
            //id del usuario
            $id_usuario = '0';
            if (isset($request['id_usuario_log'])) {
                $id_usuario = $request['id_usuario_log'];
            }
            //id del tercero del usuario
            $id_tercero = 'null';
            if (isset($request['id_tercero_log'])) {
                $id_tercero = $request['id_tercero_log'];
            }
            //comando de funcionalidad
            $cod_func = 'sin comando';
            if (isset($request['comando'])) {
                $cod_func = $request['comando'];
            }

            //id de companhia
            $id_cia = 'null';
            if (isset($request['id_cia'])) {
                $id_cia = $request['id_cia'];
            }


            //id del tercero del usuario
            $id_tercero = 'null';
            if (isset($request['id_tercero_log'])) {
                $id_tercero = $request['id_tercero_log'];
            }
            //comando de funcionalidad
            $cod_func = 'sin comando';
            if (isset($request['comando'])) {
                $cod_func = $request['comando'];
            }

            switch ($id_ope_bd) {
                case 1:
                    $operacion = "consulto";
                    break;
                case 2:
                    $operacion = "actualizo";
                    break;
                case 3:
                    $operacion = "adiciono";
                    break;
                case 4:
                    $operacion = "elimino";
                    break;
                case 5:
                    $operacion = "anulo";
                    break;
            }

            $nombreTabla = CN_TABLE::consultarNombreTablaBD($id_mae_bd);
            if (is_null($observacion)) {
                $observacion = "'Se $operacion sobre la tabla $nombreTabla desde la funcionalidad: $cod_func.'";
            } else {
                $observacion = "'Se $operacion sobre la tabla $nombreTabla desde la funcionalidad: $cod_func, $observacion'";
            }

            //Ip del servidor o equipode ingreso - 20210617
            $ip_address = $_SERVER['REMOTE_ADDR'];
            if (isset($request['ip_address'])) {
                $ip_address = $request['ip_address'];
            }


            /*
             * registro de consulta en tabla de log $id_tabla, $id_ope_bd, $id_mae_bd, $usuario, $comando, $observacion
             */
            $sql = CN_TABLE::registroTableLog($id_tabla, $id_ope_bd, $id_mae_bd, $id_usuario, $cod_func, $observacion, $ip_address);
        } catch (Exception $exp) {
            $logger->info("[CN_TABLE] Error de Log " . $exp);
        }
        return $sql;
    }

    /**
     * Metodo para obtener el id de la tabla en la base de datos
     *
     * @param <type> $tabla
     * @return <type>
     */
    public static function consultarIdTablaBD($tabla) {

        $id_mae_bd = 0;

        /*
         * Variables globales del proyecto
         */
        $tabla_mae = sfConfig::get('app_tablaMae');

        //sentencia sql para registro log
        $sql = <<<EOD
select * from $tabla_mae
where DES_MAE_BD = '$tabla'
EOD;

        //ejecuta y obtiene el resultado del sql
        $record = CN_TABLE::executeSQL($sql);

        //validar que existe registro de la tabla
        if (count($record) > 0) {

            $id_mae_bd = $record[0]['id_mae_bd'];
        } else {

            //llamar al metodo para crear nuevo registro en la tabla CN_MAE_TER
            $id_mae_bd = CN_TABLE::crearTabla_MAE_BD($tabla);
        }

        return $id_mae_bd;
    }

    /**
     * Metodo para obtener el id de la tabla en la base de datos
     *
     * @param <type> $tabla
     * @return <type>
     */
    public static function consultarNombreTablaBD($tabla) {

        $id_mae_bd = 0;

        /*
         * Variables globales del proyecto
         */
        $tabla_mae = sfConfig::get('app_tablaMae');

        //sentencia sql para registro log
        $sql = <<<EOD
select * from $tabla_mae
where ID_MAE_BD = '$tabla'
EOD;

        //ejecuta y obtiene el resultado del sql
        $record = CN_TABLE::executeSQL($sql);

        //validar que existe registro de la tabla
        if (count($record) > 0) {

            $nombre = $record[0]['des_mae_bd'];
        } else {

            $nombre = "";
        }

        return $nombre;
    }

    /*
     * Crear registro de tabla en XX_MAE_BD - maestro de bade de datos
     */

    public static function crearTabla_MAE_BD($tabla) {


        $id_mae_bd = 0;

        /*
         * Variables globales del proyecto
         */
        $tabla_mae = sfConfig::get('app_tablaMae');

        //obtener id mayor +1 de la tabla
        //sentencia sql para registro log
        $sql = <<<EOD
select nvl(count(ID_MAE_BD)+1,0) as id_seq from $tabla_mae
EOD;

        //ejecuta y obtiene el resultado del sql
        $record = CN_TABLE::executeSQL($sql);

        if (count($record) > 0) {

            $id_mae_bd = $record[0]['id_seq'];
        } else {
            return $id_mae_bd;
        }

        //crear registro en la tabla
        //sentencia sql para registro log
        $sql = <<<EOD
INSERT INTO $tabla_mae VALUES ( $id_mae_bd , '$tabla' )
EOD;

        //ejecuta y obtiene el resultado del sql
        CN_TABLE::executeSQL($sql);

        return $id_mae_bd;
    }

    /**
     * Metodo que ejecuta un insert de la sentencia sql
     * conexion con la base de datos websafiERP
     *
     * @param <type> $sql
     * @param <type> $user
     * @param <type> $pass
     * @return <type>
     */
    public static function executeOCI_SQL_Add($sql, $user, $pass) {

        $logger = sfContext::getInstance()->getLogger();
//    $logger->info("Sql de insert: " . $sql);

        $exito = true;

        /*
         * Variables globales del proyecto
         */
        $modulo = sfConfig::get('app_modulo');
        $ip = sfConfig::get('app_ip');

        /*
         * Conexion a la base de datos
         */
        //base de datos websafiERP
        $conn = oci_connect($user, $pass, $ip);

        //validacion conexion
        if (!$conn) {
            $exito = false;
            $e = oci_error();
//        print htmlentities($e['message']);
            $logger->info("error conn:" . $e['message']);
//            exit;
        }

        $stid = oci_parse($conn, $sql);
        //validar errores
        if (!$stid) {
            $exito = false;
            $e = oci_error($conn);
            $logger->info("error stid:" . $e['message']);
//            exit;
        }

        $exec = oci_execute($stid);
        //validar errores
        if (!$exec) {
            $exito = false;
            $e = oci_error($stid);

            $logger->info("error exec:" . $e['message']);

//        echo htmlentities($e['message']);
//        echo "<pre>";
//        echo htmlentities($e['sqltext']);
//        printf("\n%" . ($e['offset'] + 1) . "s", "^");
//        echo "</pre>";
//            exit;
        } else {
//        echo "Registro insertado correctamente: " . $sql . "<br>";
            $logger->info("Informacion: " . "Registro insertado correctamente: " . $sql);
        }


        //cerrar la conexion en la base de datos
        oci_close($conn);

        //returna array de consulta
        return $exito;
    }

    /**
     * Metodo que ejecuta una sentencia sql y retorna la consulta en un array
     * conexion con la base de datos websafiERP
     *
     * @param <type> $sql
     * @param <type> $user
     * @param <type> $pass
     * @return <type>
     */
    public static function executeOCI_SQL_List($sql, $user, $pass) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("Sql de insert: " . $sql);

        /*
         * Variables globales del proyecto
         */
        $modulo = sfConfig::get('app_modulo');
        $ip = sfConfig::get('app_ip');

        /*
         * Conexion a la base de datos
         */
        //base de datos  websafiERP
        $conn = oci_connect($user, $pass, $ip); //se debe verificar cambio de ip para uso fuera de la red interna
        //validacion conexion
        if (!$conn) {
            $e = oci_error();
            $logger->info($e['message']);
//            print htmlentities($e['message']);
//            exit;
        }

        $stid = oci_parse($conn, $sql);
        $logger->info("stid: " . $stid);


        $exec = oci_execute($stid);

//    echo var_dump($stid);
//    print_r($stid);
//    die();

        $records = array();

        //validar ejecucion
        if ($exec && $stid) {
            while ($row = oci_fetch_array($stid, OCI_ASSOC + OCI_RETURN_NULLS)) {
//        print_r($row);
//            echo "\n" . var_dump($row) . "\n";
                $records[] = $row;
            }
        } else {
            //mensajes de error
            $logger->info("Se produjo un error");
            $e = oci_error($conconexion);
            $logger->info($e['message']);
//            exit;
        }

        //cerrar la conexion en la base de datos
        oci_close($conn);

        //returna array de consulta
        return $records;
    }

    /**
     * Metodo para retornar string de fecha sistema
     *
     * @return string 
     */
    public static function fechaSistema() {

        //fecha del sistema
        $anho_completo = date('Y'); //anho completo cuatro digitos
        $mes = date('m'); //mes con dos digitos
        $dia = date('d'); //dia con dos digitos
        $fecha_sistema = $anho_completo . '-' . $mes . '-' . $dia;

        return $fecha_sistema;
    }

    /**
     * Metodo para retornar el anho - mes anterior
     *
     * @return string
     */
    public static function fechaAnterior($anho, $mes) {

        //inicializar variables
        $fechaAnterior = array();
        $anho_ant = 0;
        $mes_ant = 0;

        /*
         * obtener fecha siguiente anho - mes
         */

        //valida primer periodo
        if ($mes == 1) {

            $anho_ant = $anho - 1;
            $mes_ant = 12;
        } else {

            $anho_ant = $anho;
            $mes_ant = $mes - 1;
        }

        $fechaAnterior = array(
            'id_anhos' => $anho_ant,
            'id_meses' => $mes_ant
        );


        return $fechaAnterior;
    }

    /**
     * Metodo para retornar el anho - mes siguiente
     *
     * @return string
     */
    public static function fechaSiguiente($anho, $mes) {

        //inicializar variables
        $fechaSiguinte = array();
        $anho_sig = 0;
        $mes_sig = 0;

        /*
         * obtener fecha siguiente anho - mes
         */

        //valida ultimo periodo
        if ($mes == 12) {

            $anho_sig = $anho + 1;
            $mes_sig = 1;
        } else {

            $anho_sig = $anho;
            $mes_sig = $mes + 1;
        }

        $fechaSiguinte = array(
            'id_anhos' => $anho_sig,
            'id_meses' => $mes_sig
        );


        return $fechaSiguinte;
    }

    /**
     * Metodos de aplicacion formula
     * Ejemplo: ( 2+2 > 5*8 ? 5*10 : 5 == 54 ? 1 :  +1000+1 )
     */
    public static function aplicarEval($formula) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] Formula: " . $formula);

        if (!is_null($formula)) {
            // Ejemplo de Eval
            $eval = eval('return (' . $formula . ');');
            if ($eval === false) {
//                $eval = false;
                $logger->info("[CN_TABLE] Formula Error Eval: " . $formula);
            }
        } else {

            $eval = false;
        }

        /*
         * Retornar resultado
         */
        return $eval;
    }

    /**
     * Reemplaza en la consulta los filtros y valores del SQL, que vienen en el record
     * Ejemplo: select raz_soc from id_cia where id_cia = $id_cia
     * $id_cia - > variable de reemplazo
     * Reemplaza $id_cia por el valor en el record
     * @param type $consulta
     * @param type $record
     */
    public static function reemplazoConsulta($consulta, $record) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] Consulta: " . $consulta);

        foreach ($record as $key => $value) {

            //Fecha
            if ($key == 'fecha_desde' || $key == 'fecha_hasta') {

                $consulta = str_replace('$' . $key, " to_date('" . $value . "', 'yyyy-mm-dd') ", $consulta);
            } else
            //Texto
            if ($key == 'num_doc') {

                $consulta = str_replace('$' . $key, " '" . $value . "' ", $consulta);
            }
            //Numero
            else {

                $consulta = str_replace('$' . $key, $value, $consulta);
            }

//            if ($key == 'porcentaje') {
//                $logger->info("[CN_TABLE] Consulta: " . $consulta);
//            }
        }

        return $consulta;
    }

    /**
     * Get the variables within the formula
     * Ejemplo: 'C1'
     * @param array $vars
     * @param string $formula
     */
    public static function getVarsInFormula(&$vars, $formula) {
        if ($formula != '') {
            $pos_ini = strpos($formula, INI_CHAR);
            $pos_end = strpos($formula, END_CHAR);

            if ($pos_ini !== false && $pos_end !== false) {
                $var = substr($formula, $pos_ini + 1, $pos_end - $pos_ini - 1);
                if (array_search($var, $vars) === false)
                    $vars[] = $var;

                CN_TABLE::getVarsInFormula($vars, substr($formula, $pos_end + 1));
            }
        }
    }

    /**
     * Get the variables within the consulta
     * Ejemplo: '$tag '
     * @param array $vars
     * @param string $consulta
     */
    public static function getVarsInConsulta(&$vars, $consulta) {

//        $logger = sfContext::getInstance()->getLogger();
//        $logger->info("[CN_TABLE] getVarsInConsulta Consulta: " . $consulta);

        if ($consulta != '') {
            $pos_ini = strpos($consulta, ':');
            $pos_end = $pos_ini + strpos(substr($consulta, $pos_ini), ' ');

            if ($pos_ini !== false && $pos_end !== false) {
                $var = substr($consulta, $pos_ini + 1, $pos_end - $pos_ini);
                if (array_search($var, $vars) === false) {
                    $var = trim($var);
                    $vars[] = str_replace("'", null, $var);
                }
                CN_TABLE::getVarsInConsulta($vars, substr($consulta, $pos_end + 1));
            }
        }
    }

    /**
     * Obtener dias entre dos fechas 
     * formato yyyy-mm-dd
     * @param type $fecha_ini
     * @param type $fecha_fin
     * @param type $calendario
     * @return int
     */
    public static function diasEntreFechas($fecha_ini, $fecha_fin, $calendario = true) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] diasEntreFechas: " . $fecha_ini . " - " . $fecha_fin);

        $dias = 0;

        /*
         * Validar forma de calculo
         */
        if ($calendario) {

            $dias = ((strtotime($fecha_fin) - strtotime($fecha_ini)) / 86400);
        }
        //Todos los meses de 30 dias
        else {

            /*
             * Dividir fecha formato yyyy-mm-dd
             * Posicion 0 anho
             * Posicion 1 mes
             * Posicion 2 dia
             */
            $fecha_ini = explode('-', $fecha_ini);
            $fecha_fin = explode('-', $fecha_fin);

            //Para cuando el anho y mes es el mismo
            if ($fecha_ini[0] == $fecha_fin[0] && $fecha_ini[1] == $fecha_fin[1]) {

                //$logger->info($fecha_fin[2]." - " . $fecha_ini[2]);

                if ($fecha_fin[2] > 30) {
                    $fecha_fin[2] = 30;
                } elseif ($fecha_fin[1] == 2) {
                    if ($fecha_fin[2] >= 28) {
                        $fecha_fin[2] = 30;
                    }
                }

                $dias = $fecha_fin[2] - $fecha_ini[2] + 1;
            } else {

                $dias = 30 - $fecha_ini[2] + 1;

                $fecha_ini = CN_TABLE::fechaSiguiente($fecha_ini[0], $fecha_ini[1]);
//                $logger->info("[CN_TABLE] fechasCiclo: " .$fecha_ini['id_anhos'] . "-" . $fecha_ini['id_meses']);


                if ($fecha_ini['id_anhos'] > 2200) {
                    $logger->info("[CN_TABLE] Supero fecha 2200.");
                    return 0;
                    die();
                }

                //Unir fecha formato yyyy-mm-dd
                $fecha_ini = $fecha_ini['id_anhos'] . "-" . str_pad($fecha_ini['id_meses'], 2, "0", STR_PAD_LEFT) . "-0" . 1;
                $fecha_fin = $fecha_fin[0] . "-" . $fecha_fin[1] . "-" . $fecha_fin[2];

                $dias += CN_TABLE::diasEntreFechas($fecha_ini, $fecha_fin, false);
            }
        }

        $logger->info("[CN_TABLE] dias: " . $dias);
        return $dias;
    }

    /**
     * Obtener meses entre dos fechas 
     * formato yyyy-mm-dd
     * @param type $fecha_ini
     * @param type $fecha_fin
     * @param type $calendario
     * @return int
     */
    public static function mesesEntreFechas($fecha_ini, $fecha_fin, $calendario = true) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] mesesEntreFechas: " . $fecha_ini . " - " . $fecha_fin);

        $meses = 0;

        /*
         * Validar forma de calculo - meses de 30 dias
         */
        if ($calendario) {
            //round(($a=(($e-$s)/86400)/30),0);
            $dias = ((strtotime($fecha_fin) - strtotime($fecha_ini)) / 86400);
            $meses = round(($dias / 30), 0);
        }
        //Todos los meses de 30 dias - trabajados completos
        else {

            //Dividir fecha formato yyyy-mm-dd
            $fecha_ini = explode('-', $fecha_ini);
            $fecha_fin = explode('-', $fecha_fin);

            $anho_mes_ini = $fecha_ini[0] . str_pad($fecha_ini[1], 2, '0', STR_PAD_LEFT);
            $anho_mes_fin = $fecha_fin[0] . str_pad($fecha_fin[1], 2, '0', STR_PAD_LEFT);

            $anho_mes_ini = $anho_mes_ini * 1;
            $anho_mes_fin = $anho_mes_fin * 1;
            $logger->info("[CN_TABLE] anho_mes_ini: " . $anho_mes_ini . ' - anho_mes_fin: ' . $anho_mes_fin);

            $dia_ini = $fecha_ini[2];
            $dia_fin = $fecha_fin[2];
            $mes_fin = $fecha_fin[1];

            do {

                /*
                 * Validar mes completo
                 */
                if ($anho_mes_ini < $anho_mes_fin && $dia_ini == 1) {
                    $meses = $meses + 1;
                } elseif ($anho_mes_ini == $anho_mes_fin && $dia_ini == 1 && $dia_fin >= 30) {
                    $meses = $meses + 1;
                } elseif ($anho_mes_ini == $anho_mes_fin && $mes_fin == 2 && $dia_ini == 1 && $dia_fin >= 28) {
                    $meses = $meses + 1;
                }

                if ($anho_mes_ini > 220001) {
                    $logger->info("[CN_TABLE] Supero mes 220001.");
                    return 0;
                    die();
                }

                $fecha_ini = CN_TABLE::fechaSiguiente(substr($anho_mes_ini, 0, 4), substr($anho_mes_ini, 4, 2));
                $anho_mes_ini = $fecha_ini['id_anhos'] . str_pad($fecha_ini['id_meses'], 2, '0', STR_PAD_LEFT);
                $anho_mes_ini = $anho_mes_ini * 1;
                $dia_ini = 1;

                $logger->info("[CN_TABLE] anho_mes_ini: " . $anho_mes_ini);
            } while ($anho_mes_ini <= $anho_mes_fin);
        }

//        $logger->info("[CN_TABLE] meses: " . $meses);
        return $meses;
    }

    /**
     * Metodo para redondear hacia abajo los terminados en 5...
     * @param type $valor_calculo
     * @param type $redondeo
     * @return int
     */
    public static function redondeoValor($valor_calculo, $redondeo) {

        $logger = sfContext::getInstance()->getLogger();
        $logger->info("[CN_TABLE] Valor_calculo: " . $valor_calculo . " - Redondeo " . $redondeo);

        $valor = 0;
        $redondeo_calc = $redondeo * -1;

//        $logger->info( "-> " . str_pad(1, $redondeo, 0, STR_PAD_RIGHT) );
//        die();
        //obtener el valor a redondear
        if ($redondeo_calc >= 0) {
            $valor_redondeo = 5 * str_pad(1, $redondeo_calc, 0, STR_PAD_RIGHT);
        } else {
            $redondeo_calc = $redondeo_calc * -1;
            $valor_redondeo = 5 / str_pad(1, $redondeo_calc, 0, STR_PAD_RIGHT);
        }

        //obtener valor redondeado hacia abajo
        if (($valor_calculo + $valor_redondeo) == round($valor_calculo, $redondeo)) {
            $valor_calculo = $valor_calculo - $valor_redondeo;
        } else {
            $valor_calculo = round($valor_calculo, $redondeo);
        }

        $valor = $valor_calculo;

        return $valor;
    }

    /**
     * Metodo de envio de correos - 20180419
     * 
     * @param type $report_params
     * @param type $datos_usuario
     * @param type $subject
     * @param type $currentUri
     * @param type $ruta
     * @param type $adjunto
     * @param type $progress_key
     * @param type $array_adjuntos
     * @param type $entidad_cliente
     * @param type $entidad_nombre
     * @param type $addAddress
     */
    public static function envioCorreo($report_params, $datos_usuario, $subject, $currentUri, $ruta, $adjunto, $progress_key, $array_adjuntos, $entidad_cliente, $entidad_nombre, $addAddress = false,$useCc = false) {

        /**
         * Clase de log
         */
        $logger = sfContext::getInstance()->getLogger();
        $logger->info('********** Metodo Envio de Correo. **********');
        $adresses = '';

        //Codigo para determinar log registrado - 20200414::LAVILA
        $contador = rand ( 1 , 999 );
        $adjuntolog = '';
        $codigolog = date('YmdHis') . str_pad($contador, 3, "0", STR_PAD_LEFT);
        

        /**
         * Variables configuración
         */
        $logger->info('*** Variables configuración ***');
        $i = 1;
        $ipServidorCorreo = sfConfig::get('app_ipServidorCorreo');
        $SMTPSecure = sfConfig::get('app_SMTPSecure');
        $SMTPAuth = sfConfig::get('app_SMTPAuth');
        $port = sfConfig::get('app_port');
        $username = sfConfig::get('app_username');
        $password = sfConfig::get('app_password');
        $mail_envio = sfConfig::get('app_mail');

        /*
          $logger->info('*** Variables: ' . $ipServidorCorreo . ' ***');
          $logger->info('*** Variables: ' . $SMTPSecure . ' ***');
          $logger->info('*** Variables: ' . $SMTPAuth . ' ***');
          $logger->info('*** Variables: ' . $port . ' ***');
          $logger->info('*** Variables: ' . $username . ' ***');
          $logger->info('*** Variables: ' . $password . ' ***');
         */

        /**
         * Reemplazo de caracteres tilde
         */
        $logger->info('*** Reemplazo de caracteres tilde ***');
        $subject = str_replace("á", "&aacute;", $subject);
        $subject = str_replace("é", "&eacute;", $subject);
        $subject = str_replace("í", "&iacute;", $subject);
        $subject = str_replace("ó", "&oacute;", $subject);
        $subject = str_replace("ú", "&uacute;", $subject);

        /**
         * PHPMailer
         */
        $logger->info('*** PHPMailer ***');
        // Instanciar PHPMailer una primera Vez
        $mail = new PHPMailer(); // defaults to using php "mail()"

        /*
         * WERP
         */
        $mail->IsSMTP(); // telling the class to use SMTP
        $mail->SMTPSecure = $SMTPSecure;
        $mail->Host = $ipServidorCorreo;      // SMTP server
        //$mail->SMTPDebug  = 2;                     // enables SMTP debug information (for testing)
        // 1 = errors and messages
        // 2 = messages only
        $mail->SMTPAuth = $SMTPAuth;                  // enable SMTP authentication
        $mail->Port = $port;                    // set the SMTP port for the GMAIL server
        $mail->Username = $username;              // SMTP account username
        $mail->Password = $password;           // SMTP account password
        $mail->SetFrom($mail_envio);
        //$mail->SetFrom($report_params["email_envio"], utf8_decode($entidad_nombre));
        $mail->SMTPOptions = array(
                               'ssl' => array(
                               'verify_peer' => false,
                               'verify_peer_name' => false,
                               'allow_self_signed' => true
                               )
                       );

        $mail->Subject = $subject;
        $logger->info('Enviando ' . count($datos_usuario) . ' - ' . $subject);

        /**
         * Recorre usuarios para envio de correo
         */
        $i_porcentaje = 1;
        $cantidad_array = count($datos_usuario);

        // Antes de inicar el proceso largo
        $brecha = 1;
        if ($cantidad_array > 100)
            $brecha = $cantidad_array - (0.99 * $cantidad_array);
        $logger->info("Valor de progress_key: " . $progress_key . " - Cantidad " . $cantidad_array);
        if($useCc==false){//Generamos un correo por cada destinatario
            /*
             * For datos_usuario
             */
            $logger->info('*** For datos_usuario ***');
            foreach ($datos_usuario as $value) {

                // Guardar un valor en el proceso largo
                if ($i_porcentaje % $brecha == 0) {
                    MemcacheHandler::getInstance()->set($progress_key, round(($i_porcentaje / $cantidad_array) * 100, 0));
                }


                $logger->info("Funcionario: " . $value);
                $datos = explode(';', $value);

                /**
                 * Datos del funcionario para el envio del correo
                 * Ejemplo: 
                 * 123;1;pepito perez;correo@gmal.com
                 * 123;1;pepito perez;correo@gmal.com;mensaje extra;referencia;nombre_reporte_adjunto
                 * 
                 * Datos de reemplazo mensajes
                 * $0->num_doc 
                 * $1->tipo_doc
                 * $2->correo
                 * $3->nombre_completo
                 * $4->mensaje_extra usuario
                 * $5->referencia en el mensaje/adjunto
                 * $6->nombre_reporte adjunto
                 */
                $report_params["num_doc"] = $datos[0];
                $report_params["id_tipo_doc"] = $datos[1];
                $report_params["nombre_completo"] = $datos[2];
                $report_params["email"] = $datos[3];
                //$report_params["email"] = "lavila@sofhouse.net"; //Para pruebas
                //$report_params["email"] = "a.net"; //Para pruebas

                /**
                 * mensaje_extra y mensaje_extra_gwt - 20170606
                 */
                if (isset($report_params["mensaje_extra"])) {
                    $report_params["mensaje_extra"] = "<br/><br/>" . $datos[4];
                    $report_params["mensaje_extra"] = str_replace("ó", "&oacute;", $report_params["mensaje_extra"]);
                    $report_params["mensaje_extra"] = str_replace(",,,", "<br/>", $report_params["mensaje_extra"]);
                    $report_params["mensaje_extra"] = str_replace("null", " ", $report_params["mensaje_extra"]);
                } elseif (isset($report_params["mensaje_extra_gwt"])) {
                    $report_params["mensaje_extra"] = "<br/><br/>" . $report_params["mensaje_extra_gwt"];
                } else {
                    $report_params["mensaje_extra"] = "";
                }
                //$5->referencia en el mensaje/adjunto
                if (isset($datos[5])) {
                    $report_params["referencia"] = $datos[5];
                    $logger->info("$5->referencia en el mensaje/adjunto:" . $report_params["referencia"]);
                    $subject = str_replace("$0", $report_params["num_doc"], $subject);
                    $mail->Subject = str_replace("$5", $report_params["referencia"], $subject);
                } else {
                    $report_params["referencia"] = '';
                }
                //$6->nombre_reporte adjunto
                if (isset($datos[6])) {
                    $nombre_archivo = $datos[6];
                    $logger->info("$6->nombre_reporte adjunto:" . $nombre_archivo);
                }

                //arrayadjuntos
                if (isset($report_params["arrayadjuntos"])) {
                    $array_adjuntos = array();
                    $cant_adjuntos = $report_params["arrayadjuntos"];
                    for ($i = 1; $i <= $cant_adjuntos; $i++) {
                        $datos_adj = explode('+', $datos[3 + $i]);
                        $key_datos = $datos_adj[1];
                        $array_adjuntos[$key_datos] = str_replace("+", "/", $datos[3 + $i]);
                    }
                }

                /*
                 * Envio de correo             * 
                 */

                if ($addAddress) {
                    $mail->AddAddress($mail_envio, utf8_decode($entidad_nombre));
                }

                // Agregar El correo
                // Agregar el Attachment
                // Cambiar el body
                $destinatario = $address = $report_params["email"];
                $mail->AddAddress($address, $report_params["num_doc"]);

                /**
                 * Reemplazo de caracteres
                 */
                $mensaje_extra = str_replace("ó", "&oacute;", $report_params["mensaje_extra"]);
                $mensaje_extra = str_replace(",,,", "<br/>", $mensaje_extra);
                $mensaje_extra = str_replace("null", " ", $mensaje_extra);

                $mensaje_firma = "";
                if (isset($report_params["mensaje_firma"])) {
                    $mensaje_firma = str_replace("ó", "&oacute;", $report_params["mensaje_firma"]);
                    $mensaje_firma = str_replace(",,,", "<br/>", $mensaje_firma);
                    $mensaje_firma = str_replace("null", " ", $mensaje_firma);
                }

                $body = "<html><body> </body></html>";
                //Body
                if (isset($report_params["mensaje"])) {
                    $body_mensaje = $report_params["mensaje"];
                    $body_mensaje = str_replace("á", "&aacute;", $body_mensaje);
                    $body_mensaje = str_replace("é", "&eacute;", $body_mensaje);
                    $body_mensaje = str_replace("í", "&iacute;", $body_mensaje);
                    $body_mensaje = str_replace("ó", "&oacute;", $body_mensaje);
                    $body_mensaje = str_replace("ú", "&uacute;", $body_mensaje);
                    $body_mensaje = str_replace("Á", "&Aacute;", $body_mensaje);
                    $body_mensaje = str_replace("É", "&Eacute;", $body_mensaje);
                    $body_mensaje = str_replace("Í", "&Iacute;", $body_mensaje);
                    $body_mensaje = str_replace("Ó", "&Oacute;", $body_mensaje);
                    $body_mensaje = str_replace("Ú", "&Uacute;", $body_mensaje);

                    /**
                     * Reemplazo num_doc y nombre
                     */
                    $body_mensaje = str_replace("$0", $report_params["num_doc"], $body_mensaje);
                    $body_mensaje = str_replace("$3", $report_params["nombre_completo"], $body_mensaje);
                    $body_mensaje = str_replace("$5", $report_params["referencia"], $body_mensaje);


                    //$body = "<html><body> " . $body_mensaje . $mensaje_extra . "</body></html>";
                    $body = <<<EOD
<html><body> 
<br/>
$body_mensaje
<br/>
$mensaje_extra
<br/> 
$mensaje_firma                            
<br/> 
</body></html>
EOD;
                } else {
                    if ($adjunto) {
                        $mensaje = "Archivo adjunto.";
                    } else {
                        $mensaje = "Envio de correo sin mensaje.";
                    }
                    $username = $report_params["username"];
                    $nombre_completo = $report_params["nombre_completo"];
                    $email = $report_params["email"];
                    //$body = "<html><body> $subject.<br/><br/>" . "Enviado por el usuario: " . $username .
                    ' al funcionario ' . $nombre_completo . ' al correo ' . $email .
                            "<br/><br/>Mensaje: " . $mensaje . $mensaje_extra . "</body></html>";
                    $body = <<<EOD
<html><body> 
<br/>
$subject
<br/><br/>
Enviado por el usuario: $username al funcionario $nombre_completo al correo $email
<br/><br/>
Mensaje: $mensaje $mensaje_extra                            
<br/> 
$mensaje_firma                            
<br/> 
</body></html>
EOD;
                }
                //$mail->AltBody = "This is the body in plain text for non-HTML mail clients"; // optional, comment out and test

                $body = str_replace("á", "&aacute;", $body);
                $body = str_replace("é", "&eacute;", $body);
                $body = str_replace("í", "&iacute;", $body);
                $body = str_replace("ó", "&oacute;", $body);
                $body = str_replace("ú", "&uacute;", $body);
                $body = str_replace("ñ", "&ntilde;", $body);
                $body = str_replace("Á", "&Aacute;", $body);
                $body = str_replace("É", "&Eacute;", $body);
                $body = str_replace("Í", "&Iacute;", $body);
                $body = str_replace("Ó", "&Oacute;", $body);
                $body = str_replace("Ú", "&Uacute;", $body);
                $body = str_replace("Ñ", "&Ntilde;", $body);
                $mail->MsgHTML($body);

                /**
                 * Si el envio es con adjunto de jasper
                 */
                if ($adjunto) {
                    $logger->info("Si el envio con otro adjunto");
    //                    $mail->AddAttachment("$ruta/nivel/2- Competencias comunes.docx", "ManualNomina.pdf");      // attachment
    //                    $mail->AddAttachment("images/phpmailer_mini.gif"); // attachment
                    foreach ($array_adjuntos as $key => $value) {
                        $adjuntolog = $value;
                        $mail->AddAttachment("$ruta/$value", $key);      // attachment                        
                    }
                }

                /**
                 * Log de envio correo - 20200428::LAVILA
                 */
                $cuerpo = $body;
                if($destinatario) {
                    $sql = "Insert into LOG_ENVIO_CORREO (ID_LOG_ENVIO_CORREO,ID_MODULO,FECHA_LOG,USUARIO,
                            CORREO_DESTINO,CORREO_COPIA,ASUNTO,MENSAJE,ADJUNTO,CODIGOLOG,ESTADO_CORREO,FECHA_CORREO) 
                                    values (null,'20',sysdate,'admin',
                            '".$destinatario."','".$report_params["email_envio"]."','".$mail->Subject."','".$cuerpo."','".$adjuntolog."','".$codigolog."','0',null)";
                    //Ejecutar SQL
                    $records = CN_TABLE::executeSQL($sql);
                }

                /*
                 *  Enviar el correo
                 */
                $logger->info(">>> Enviar el correo");
                if (!$mail->Send()) {
                    //echo "Mailer Error: " . $mail->ErrorInfo;
                    $logger->info("Mailer Error: " . $mail->ErrorInfo . "- Correos: ".$adresses." - Asunto:".$subject."<br/>");
                    if($destinatario) {
                        $sql = "update log_envio_correo set estado_correo = 0, fecha_correo = sysdate where id_modulo = 20 and codigolog = " . $codigolog;
                        //Ejecutar SQL
                        $records = CN_TABLE::executeSQL($sql);
                    }
                } else {
                    //echo "Message sent!";
                    $logger->info("Correo enviado!!! a ".$address." - Asunto:".$subject."<br/>");
                    $logger->info("Correo enviado");
                    if($destinatario) {
                        $sql = "update log_envio_correo set estado_correo = 1, fecha_correo = sysdate where id_modulo = 20 and codigolog = " . $codigolog;
                        //Ejecutar SQL
                        $records = CN_TABLE::executeSQL($sql);
                    }
                }

                /*
                 * Limpiar datos del correo
                 */
                $mail->ClearAllRecipients();
                $mail->ClearAttachments();

                //Contadores
                $i = $i + 1;
                $i_porcentaje = $i_porcentaje + 1;
    //                echo 'Correo enviado por el usuario ' . $report_params["username"] . ' al funcionario ' .
    //                $report_params["nombre_completo"] . ' al correo ' . $report_params["email"];
    //                echo '<br/>';
            }
        }else{//Generamos un solo correo con copia a todos los destinatarios
            $adresses = "";
            foreach ($datos_usuario as $value) {
                $logger->info("Funcionario: " . $value);
                $datos = explode(';', $value);
                $report_params["num_doc"] = $datos[0];
                $report_params["id_tipo_doc"] = $datos[1];
                $report_params["nombre_completo"] = $datos[2];
                $report_params["email"] = $datos[3];
                //Agrgamos el correo
                $destinatario = $address = $report_params["email"];
                $mail->AddAddress($address, $report_params["num_doc"]);
                $adresses .= $report_params["email"].";";
            }
            /**
            * mensaje_extra y mensaje_extra_gwt - 20170606
            */
           if (isset($report_params["mensaje_extra"])) {
               $report_params["mensaje_extra"] = "<br/><br/>" . $datos[4];
               $report_params["mensaje_extra"] = str_replace("ó", "&oacute;", $report_params["mensaje_extra"]);
               $report_params["mensaje_extra"] = str_replace(",", "<br/>", $report_params["mensaje_extra"]);
               $report_params["mensaje_extra"] = str_replace("null", " ", $report_params["mensaje_extra"]);
           } elseif (isset($report_params["mensaje_extra_gwt"])) {
               $report_params["mensaje_extra"] = "<br/><br/>" . $report_params["mensaje_extra_gwt"];
           } else {
               $report_params["mensaje_extra"] = "";
           }
           //$5->referencia en el mensaje/adjunto
           if (isset($datos[5])) {
               $report_params["referencia"] = $datos[5];
               $logger->info("$5->referencia en el mensaje/adjunto:" . $report_params["referencia"]);
               $subject = str_replace("$0", $report_params["num_doc"], $subject);
               $mail->Subject = str_replace("$5", $report_params["referencia"], $subject);
           } else {
               $report_params["referencia"] = '';
           }
           //$6->nombre_reporte adjunto
           if (isset($datos[6])) {
               $nombre_archivo = $datos[6];
               $logger->info("$6->nombre_reporte adjunto:" . $nombre_archivo);
           }

           //arrayadjuntos
           if (isset($report_params["arrayadjuntos"])) {
               $array_adjuntos = array();
               $cant_adjuntos = $report_params["arrayadjuntos"];
               for ($i = 1; $i <= $cant_adjuntos; $i++) {
                   $datos_adj = explode('+', $datos[3 + $i]);
                   $key_datos = $datos_adj[1];
                   $array_adjuntos[$key_datos] = str_replace("+", "/", $datos[3 + $i]);
               }
           }
            $mensaje_extra = str_replace("ó", "&oacute;", $report_params["mensaje_extra"]);
            $mensaje_extra = str_replace(",,,", "<br/>", $mensaje_extra);
            $mensaje_extra = str_replace("null", " ", $mensaje_extra);

            $mensaje_firma = "";
            if (isset($report_params["mensaje_firma"])) {
                $mensaje_firma = str_replace("ó", "&oacute;", $report_params["mensaje_firma"]);
                $mensaje_firma = str_replace(",,,", "<br/>", $mensaje_firma);
                $mensaje_firma = str_replace("null", " ", $mensaje_firma);
            }

            $body = "<html><body> </body></html>";
            //Body
            if (isset($report_params["mensaje"])) {
                $body_mensaje = $report_params["mensaje"];

                /**
                 * Reemplazo num_doc y nombre
                 */
                $body_mensaje = str_replace("$0", $report_params["num_doc"], $body_mensaje);
                $body_mensaje = str_replace("$3", $report_params["nombre_completo"], $body_mensaje);
                $body_mensaje = str_replace("$5", $report_params["referencia"], $body_mensaje);


                //$body = "<html><body> " . $body_mensaje . $mensaje_extra . "</body></html>";
                $body = <<<EOD
<html><body> 
<br/>
$body_mensaje
<br/>
$mensaje_extra
<br/> 
$mensaje_firma                            
<br/> 
</body></html>
EOD;
                } else {
                    if ($adjunto) {
                        $mensaje = "Archivo adjunto.";
                    } else {
                        $mensaje = "Envio de correo sin mensaje.";
                    }
                    $username = $report_params["username"];
                    $nombre_completo = $report_params["nombre_completo"];
                    $email = $report_params["email"];
                    //$body = "<html><body> $subject.<br/><br/>" . "Enviado por el usuario: " . $username .
                    ' al funcionario ' . $nombre_completo . ' al correo ' . $email .
                            "<br/><br/>Mensaje: " . $mensaje . $mensaje_extra . "</body></html>";
                    $body = <<<EOD
<html><body> 
<br/>
$subject
<br/><br/>
Enviado por el usuario: $username al funcionario $nombre_completo al correo $email
<br/><br/>
Mensaje: $mensaje $mensaje_extra                            
<br/> 
$mensaje_firma                            
<br/> 
</body></html>
EOD;
                }
                //$mail->AltBody = "This is the body in plain text for non-HTML mail clients"; // optional, comment out and test

                $body = str_replace("á", "&aacute;", $body);
                $body = str_replace("é", "&eacute;", $body);
                $body = str_replace("í", "&iacute;", $body);
                $body = str_replace("ó", "&oacute;", $body);
                $body = str_replace("ú", "&uacute;", $body);
                $body = str_replace("ñ", "&ntilde;", $body);
                $mail->MsgHTML($body);

                /**
                 * Si el envio es con adjunto de jasper
                 */
                if ($adjunto) {
                    $logger->info("Si el envio con otro adjunto");
    //                    $mail->AddAttachment("$ruta/nivel/2- Competencias comunes.docx", "ManualNomina.pdf");      // attachment
    //                    $mail->AddAttachment("images/phpmailer_mini.gif"); // attachment
                    foreach ($array_adjuntos as $key => $value) {
                        $adjuntolog = $value;
                        $mail->AddAttachment("$ruta/$value", $key);      // attachment                        
                    }
                }

                /**
                 * Log de envio correo - 20200428::LAVILA
                 */
                $cuerpo = $body;
                if($destinatario) {
                    $sql = "Insert into LOG_ENVIO_CORREO (ID_LOG_ENVIO_CORREO,ID_MODULO,FECHA_LOG,USUARIO,
                            CORREO_DESTINO,CORREO_COPIA,ASUNTO,MENSAJE,ADJUNTO,CODIGOLOG,ESTADO_CORREO,FECHA_CORREO) 
                                    values (null,'20',sysdate,'admin',
                            '".$destinatario."','".$report_params["email_envio"]."','".$mail->Subject."','".$cuerpo."','".$adjuntolog."','".$codigolog."','0',null)";
                    //Ejecutar SQL
                    $records = CN_TABLE::executeSQL($sql);
                }

                /*
                 *  Enviar el correo
                 */
                $logger->info(">>> Enviar el correo");
                if (!$mail->Send()) {
                    //echo "Mailer Error: " . $mail->ErrorInfo;
                    
                        $logger->info("Mailer Error:" . $mail->ErrorInfo . " - Correos: ".$adresses." - Asunto:".$subject."<br/>");
                    if($destinatario) {
                        $sql = "update log_envio_correo set estado_correo = 0, fecha_correo = sysdate where id_modulo = 20 and codigolog = " . $codigolog;
                        //Ejecutar SQL
                        $records = CN_TABLE::executeSQL($sql);
                    }
                } else {
                    //echo "Message sent!";
                    $logger->info("Correo enviado!!! a ".$adresses." - Asunto:".$subject."<br/>");
                    $logger->info("Correo enviado");
                    if($destinatario) {
                        $sql = "update log_envio_correo set estado_correo = 1, fecha_correo = sysdate where id_modulo = 20 and codigolog = " . $codigolog;
                        //Ejecutar SQL
                        $records = CN_TABLE::executeSQL($sql);
                    }
                }

                /*
                 * Limpiar datos del correo
                 */
                $mail->ClearAllRecipients();
                $mail->ClearAttachments();
                
            
        }

        $logger->info("Fin de envio de correos");

        //Actualizar el Memcache
        MemcacheHandler::getInstance()->set($progress_key, 99);
    }

    /**
     * Validar correo formato
     * 
     * @param type $correo
     */
    public static function validarCorreo($correo) {

        //valida si esta vacio
        if ($correo == null || $correo == '' || $correo == 'null') {

            return false;
        }

        $findme = '@';
        $pos = strpos($correo, $findme);

        //valida si tiene el @
        if ($pos === false) {

            return false;
        }

        return true;
    }

    /**
     * Funcion de redondeo hacia arriba - 20170222
     * @param type $number - numero a redondear
     * @param type $significance - valor en cifras de 10 segun redondeo
     * @return type
     */
    public static function ceiling($number, $significance = 1) {

        /**
         * Clase de log
         */
        $logger = sfContext::getInstance()->getLogger();
        $logger->info('Funcion de redondeo hacia arriba, numero: ' . $number . ' - Redondear: ' . $significance);

        return ( is_numeric($number) && is_numeric($significance) ) ? (ceil($number / $significance) * $significance) : $number;
    }

    /**
     * Para convertir a utf-8 un array - 20171204
     * 
     * @param type $array
     * @return type
     */
    public static function utf8_converter($array) {
        array_walk_recursive($array, function(&$item, $key) {
//            if (!mb_detect_encoding($item, 'utf-8', true)) {
            $item = utf8_encode($item);
//            }
        });

        return $array;
    }

}

?>
