<?php
namespace App\Custom;

use App\Custom\SQLConnection;

/**
 * Clase que manipula el 
 * archivo JSON del dashboard
 * */
class DashboardJSON 
{

    /**
     * id del cliente
     * @var string|int
     */
    private $cliente;
    
    /**
     * id del servicio contratado
     * @var string|int
     */
    private $servicio_contratado; 

    /**
     * id del usuario
     * @var string|int
     */
    private $user_id;

    /**
     * el path del archivo json
     * @var string 
     */
    private $json_path;

    /**
     * el nombre del archivo json
     * @var string 
     */
    private $json_name;

    /**
     * Lista de tipos
     * de graficos
     * @var array
     */
    private $lista_tipo_graficos;

    /**
     * si el servicio es
     * un servicio de json por
     * usuario
     * @var bool
     */
    private $json_por_usuario;

    /**
     * funcion constructora de la
     * clase
     * @param string|int id del cliente
     * @param string|int id del servicio contratado
     * @param string|int|null id del usuario
     */
    public function __construct($cli,$servicio,$user_id=NULL){
        $this->cliente = $cli;
        $this->servicio_contratado = $servicio;
        $this->user_id = ( is_numeric($user_id) ) ? $user_id : NULL;
        //
        $this->json_por_usuario = ($this->servicio_contratado == env('IV_PRODUCTO'));
        //
        $this->pathJSON();
        $this->nombreJSON();
    }

    /**
     * Funcion que se ejecuta
     * cuando se hace un var dump
     * del objeto
     * @access public
     * @return string
     */
    public function __debugInfo(){
        return 'Generando el JSON';
    }

    /**
     * Obtener los datos
     * del json
     * @access public
     * @param string el id del cliente
     * @param string el id del servicio contratado
     * @return null|array
     */
    public function obtenerJSON(){
        $this->validateUserId();
        if ( $this->tieneJSON() ){
            $data = $this->dataJSON();
            if ( json_last_error() == JSON_ERROR_NONE ){
                return $data;
            } else {
                return $this->generarJSON(true);    
            }
        } else {
            return $this->generarJSON(true);
        }
    }

    /**
     * Funcion que elimina el
     * archivo del json de los
     * datos del dashboard
     * devuelve true en caso de ser eliminado
     * y false si no se encontro
     * @access public
     * @return bool
     */
    public function eliminarJSON(){
        $this->validateUserId();
        if ( $this->tieneJSON() ){
            unlink($this->json_path.$this->json_name);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Funcion que verifica si el json es
     * creado o no
     * @access public
     * @return bool
     */
    public function tieneJSON(){
        $this->validateUserId();
        return file_exists($this->json_path.$this->json_name);
    }

    /**
     * Genera o regenera el archivo json
     * de los graficos de dashboard
     * @access public
     * @param bool si esta en true devuelve el contenido del json
     * @return void|array
     */
    public function generarJSON($conDatos=false){
        $this->validateUserId();
        //
        $indicadores_graficos = $this->indicadoresGraficos();
        //
        $data = [];
        //
        if ( count($indicadores_graficos) > 0 ){
            $data = $this->tratamientoDatos($indicadores_graficos);
            //
            if ( count($data) > 0 ){
                $this->respaldoJSON();
                $this->eliminarJSON();
                // importante para que esa funcion siempre devuelva resultado consistente
                // si no se codifica y descodifica puede devolver una mezcla de arrays asociativos y objetos
                // lo cuando se levanta del json no va a poder reproducir
                $data = $this->crearJSON($data,true);
            }
        }
        //
        if ( $conDatos ){
            // devuelve un array vacio
            return $data;
        }
    }

    /**
     * arma un respaldo del archivo json
     * lo copia no lo renombra
     * @access public
     * @return bool
     */
    public function respaldoJSON(){
        $this->validateUserId();
        //
        if ( file_exists($this->json_path.$this->json_name.'.bkp') ){
            unlink($this->json_path.$this->json_name.'.bkp');
        }
        //
        if ( file_exists($this->json_path.$this->json_name) ){
            return copy($this->json_path.$this->json_name,$this->json_path.$this->json_name.'.bkp');
        } else {
            return false;
        }
    }

    /**
     * Regenerar los json existentes
     * de los usuarios de un servicio
     * del cliente
     * @access public
     * @return bool devuelve true si se regeneraron archivos y false si no hay archivos
     */
    public function regenerarUsersJSON(){
        if ( $this->json_por_usuario ){
            // obtener los usuarios que tienen json generados del cliente
            $archivos = glob($this->json_path.'*.json');
            if ( !empty($archivos) ){
                $user = NULL;
                foreach( $archivos as $archivo ){
                    $user = basename($archivo,'.json');
                    $this->setUsuario($user);
                    $this->generarJSON();
                }
                //
                return true;
            }
        }
        //
        return false;
    }

    /**
     * Funcion que indica si el servicio
     * tiene JSON por usuario o por cliente
     * @access public
     * @return bool devuelve true si es JSON por usuario y false si es JSON por cliente
     */
    public function esJSONPorUsuario(){
        return $this->json_por_usuario;
    }

    /**
     * Funcion que devuelva la cantidad
     * de graficos y indicadores que tiene
     * el JSON del usuario
     * @access public
     * @return int
     */
    public function cantGraficosIndicadores(){
        $this->validateUserId();
        //
        return count($this->indicadoresGraficos());
    }

    ////////////// FUNCIONES SETTER //////////////////

    /**
     * Funcion que setea
     * el dato de cliente
     * @access public
     * @param string el id del cliente
     * @return void
     */
    public function setCliente($cliente){
        $this->cliente = $cliente;
        $this->pathJSON();
        $this->nombreJSON();
    }

    /**
     * Funcion que setea
     * el dato de servicio
     * @access public
     * @param string el id del servicio contratado
     * @return void
     */
    public function setServicio($servicio){
        $this->servicio_contratado = $servicio;
        $this->json_por_usuario = ($this->servicio_contratado == env('IV_PRODUCTO'));
        $this->pathJSON();
    }

    /**
     * Funcion que setea
     * el dato de usuario
     * @access public
     * @param string el id del usuario
     * @return void
     */
    public function setUsuario($usuario){
        $this->user_id = $usuario;
        $this->nombreJSON();
    }

    ///// Metodos privados ////

    /**
     * Funcion que valida que
     * la clase tiene un usuario
     * sino tira un error
     * @access private
     * @return void
     */
    private function validateUserId(){
        if ( $this->json_por_usuario && is_null($this->user_id) ){
            throw new \Exception('ID de usuario invalido.');
        }
    }

    /**
     * Funcion que arma la ruta
     * del json y lo asigna a una
     * propiedad de la clase
     * @access private
     * @return void
     */
    private function pathJSON(){
        $this->json_path = env('PATH_COMPARTIDO').DIRECTORY_SEPARATOR."Dashboard".DIRECTORY_SEPARATOR.$this->servicio_contratado.DIRECTORY_SEPARATOR.$this->cliente.DIRECTORY_SEPARATOR;
        /* if ( $this->json_por_usuario ){
            $this->json_path = env('PATH_COMPARTIDO').DIRECTORY_SEPARATOR."Dashboard".DIRECTORY_SEPARATOR.$this->servicio_contratado.DIRECTORY_SEPARATOR.$this->cliente.DIRECTORY_SEPARATOR;
        } else {
            $this->json_path = env('PATH_COMPARTIDO').DIRECTORY_SEPARATOR."Dashboard".DIRECTORY_SEPARATOR.$this->servicio_contratado.DIRECTORY_SEPARATOR;
        } */
    }

    /**
     * Funcion que arma el nombre
     * del archivo json y lo asigna
     * a una propiedad de la clase
     * @access private
     * @return void
     */
    private function nombreJSON(){
        if ( $this->json_por_usuario ){
            $this->json_name = $this->user_id.'.json';
        } else {
            $this->json_name = $this->cliente.'.json';
        }
    }

    /**
     * Funcion que hace el tratamiento a 
     * los datos del json , el tratamiento es
     * con array ascociativos
     * @access private
     * @param array los indicadores de los graficos del cliente
     * @return array
     */
    private function tratamientoDatos($indicadores){
        $data = [];
        $aux = NULL;
        $this->lista_tipo_graficos = []; // se inicializan el vector de tipos de graficos
        //
        foreach( $indicadores as $i => $indicador ){
            if ( isset($indicador->clave_indicador) ){
                $aux = ['clave_indicador' => $indicador->clave_indicador, 'datos' => $this->indicadoresGraficosData($indicador->clave_indicador)];
                //
                if ( $indicador->tipo_control == 'C' ){
                    // contadores
                    $data['contadores'][] = $aux;
                } elseif ( $indicador->tipo_control == 'G' ){
                    // graficos
                    $aux['datos'] = $this->graficoJSON($aux['datos']); // tratamiento especial para los graficos
                    $aux['titulo_grafico'] = $indicador->etiqueta_indicador ?? NULL;
                    $data['graficos'][] = $aux;
                }
            }
        }
        //
        $data['tipos_graficos'] = $this->lista_tipo_graficos;
        //
        return $data;
    }

    /**
     * Funcion que devuelve los
     * indicadores de graficos del cliente
     * @access private
     * @return array
     */
    private function indicadoresGraficos(){
        // SE BUSCAN LOS INDICADORES
        return SQLConnection::backendStoreProcedure('LN_dashboard_graficos_segun_servicio', array('GRAFICOS_INDICADORES',$this->cliente,$this->servicio_contratado), 'select');
    }

    /**
     * Funcion que devuelve los
     * datos del grafico en base
     * a su clave indicador
     * @access private
     * @param string la clave del indicador del grafico
     * @return array
     */
    private function indicadoresGraficosData($indicador){
        $datos = [];
        //
        $inds = [
            'GRAPH_VALORACION_IV' => 'GRAPH_VALORACION_IV2',
            'GRAPH_VALORACION_IV' =>'GRAPH_VALORACION_IV2',
            'GRAPH_PROFESIONAL' =>'GRAPH_PROFESIONAL2',
            'GRAPH_COMERCIAL_LEGAL' =>'GRAPH_COMERCIAL_LEGAL2',
            'GRAPH_ACADEMICO' =>'GRAPH_ACADEMICO2',
            'GRAPH_COMPLIANCE' =>'GRAPH_COMPLIANCE2',
            'GRAFICO_SCORE_FINAL' =>'GRAFICO_SCORE_FINAL2',
            'GRAFICO_SCORE_DOSSIER' =>'GRAFICO_SCORE_DOSSIER2',
            'GRAFICO_SCORE_DOCUMENTOS' =>'GRAFICO_SCORE_DOCUMENTOS2',
            'GRAFICO_SCORE_BALANCE' =>'GRAFICO_SCORE_BALANCE2',
            'GRAFICO_FIDECHECK' =>'GRAFICO_FIDECHECK2',
            'GRAFICO_INFORME_COMERCIAL' => 'GRAFICO_INFORME_COMERCIAL2',
            'GRAPH_CONTRAPARTES_PAISES' => 'GRAPH_CONTRAPARTES_PAISES2',
            'GRAPH_CONTRAPARTES_FAMILIAS' => 'GRAPH_CONTRAPARTES_FAMILIAS2',
            'GRAPH_CONTRAPARTES_CUMPLIMIENTO' => 'GRAPH_CONTRAPARTES_CUMPLIMIENTO2',
            'GRAFICO_DEPENDENCIA_ECONOMICA' => 'GRAFICO_DEPENDENCIA_ECONOMICA2',
            'GRAPH_KPI_1' => 'GRAPH_KPI_12',
            'GRAPH_KPI_2' => 'GRAPH_KPI_22',
            'GRAPH_KPI_3' => 'GRAPH_KPI_32',
            'GRAPH_KPI_4' => 'GRAPH_KPI_42',
            'GRAPH_KPI_5' => 'GRAPH_KPI_52',
            'GRAFICO_APOCRIFAS' => 'GRAFICO_APOCRIFAS2',
            'GRAFICO_ARCOR_AYC' => 'GRAFICO_ARCOR_AYC2',
            'GRAFICO_ARCOR_BCRA' => 'GRAFICO_ARCOR_BCRA2',
            'GRAPH_CONTRAPARTES_PAISES_ROJO' => 'GRAPH_CONTRAPARTES_PAISES_ROJO2',
            'GRAPH_CONTRAPARTES_FAMILIAS_ROJO' => 'GRAPH_CONTRAPARTES_FAMILIAS_ROJO2',
            'GRAFICO_ARCOR_FINAL' => 'GRAFICO_ARCOR_FINAL2'
        ];
        if ( isset($inds[$indicador]) ){
            $indicador = $inds[$indicador];    
        }
        /* if ( $indicador == 'GRAPH_VALORACION_IV' ){
            $indicador = 'GRAPH_VALORACION_IV2';
        } elseif ( $indicador == 'GRAPH_PROFESIONAL' ){
            $indicador = 'GRAPH_PROFESIONAL2';
        } elseif ( $indicador == 'GRAPH_COMERCIAL_LEGAL' ){
            $indicador = 'GRAPH_COMERCIAL_LEGAL2';
        } elseif ( $indicador == 'GRAPH_ACADEMICO' ){
            $indicador = 'GRAPH_ACADEMICO2';
        } elseif ( $indicador == 'GRAPH_COMPLIANCE' ){
            $indicador = 'GRAPH_COMPLIANCE2';
        } elseif ( $indicador == 'GRAFICO_SCORE_FINAL' ){
            $indicador = 'GRAFICO_SCORE_FINAL2';
        } elseif ( $indicador == 'GRAFICO_SCORE_DOSSIER' ){
            $indicador = 'GRAFICO_SCORE_DOSSIER2';
        } elseif ( $indicador == 'GRAFICO_SCORE_DOCUMENTOS'  ){
            $indicador = 'GRAFICO_SCORE_DOCUMENTOS2';
        } elseif ( $indicador == 'GRAFICO_SCORE_BALANCE' ){
            $indicador = 'GRAFICO_SCORE_BALANCE2';
        } elseif ( $indicador == 'GRAFICO_FIDECHECK' ){
            $indicador = 'GRAFICO_FIDECHECK2';
        } elseif ( $indicador == 'GRAFICO_INFORME_COMERCIAL' ){
            $indicador = 'GRAFICO_INFORME_COMERCIAL2';
        } */
        //
        if ( $indicador == 'GRAPH_CONTRAPARTES_CUMPLIMIENTO' || ( ($this->servicio_contratado == env('LED_PRODUCTO') || $this->servicio_contratado == env('IV_PRODUCTO') ) && $indicador !== 'ENRIESGO' && $indicador !== 'OPORTUNIDADES' )  ){
            $datos = SQLConnection::backendStoreProcedure('LN_dashboard_graficos_filtrado', array($indicador,$this->cliente,null,$this->servicio_contratado,$this->user_id), 'select');
        } else {
            $datos = SQLConnection::backendStoreProcedure('LN_dashboard_graficos_segun_servicio', array($indicador,$this->cliente,$this->servicio_contratado), 'select');
        
        }
        //
        return $datos;
    }

    /**
     * Funcion que crea
     * el archivo json
     * con los datos recibidos
     * @access private
     * @param array los datos a almacenar
     * @param bool si devuelve los datos o no despues de almacenarlos
     * @return void|array
     */
    private function crearJSON($data,$conDatos=false){
        $json = json_encode($data);
        if ( $json ){
            if ( !file_exists($this->json_path) ){
                mkdir($this->json_path);
            }
            //
            file_put_contents($this->json_path.$this->json_name,$json);
        } else {
            throw new \Exception('No se pudo codificar el JSON.');
        }
        //
        if ( $conDatos ){
            return json_decode($json);
        }
    }

    /**
     * Funcion que devuelve
     * los datos que tiene el
     * archivo json
     * @access private
     * @return null|array
     */
    private function dataJSON(){
        $data = file_get_contents($this->json_path.$this->json_name);
        if ( $data !== FALSE ){
            return json_decode($data); // el json devuelve una lista de objetos , porque no maneja array asociativos
        } else {
            return NULL;
        }
    }

    /**
     * Metodo que hace el 
     * tratamiento de los 
     * datos de los graficos
     * @access private
     * @param array los datos del grafico
     * @return array
     */
    private function graficoJSON($data){
        $item1 = ( isset($data[0]) ) ? $data[0] : NULL; // se toma el primer indice
        if ( $item1 && isset($item1->tipo_grafico) ){
            //
            switch($item1->tipo_grafico){
                case 'pie':
                case 'doughnut':
                case 'semi_doughnut':
                    $data = $this->graficoTorta($data);
                    break;
                case 'label_doughnut':
                    $data = $this->graficoDonutEtiqueta($data);
                    break;
                case 'bar':
                case 'column':
                    $data = $this->graficoBarra($data);
                    break;
                case 'sunburst':
                    $data = $this->graficoEstallidoSolar($data);
                    break;
                case 'sankey':
                    $data = $this->graficoSankey($data);
                    break;
                case 'pictorial':
                    $data = $this->graficoPictorial($data);
                    break;
                default:
                    break;
            }
            //
            $data['tipo_grafico'] = $item1->tipo_grafico; // el tipo del grafico
            //
            if ( !isset($this->lista_tipo_graficos[$item1->tipo_grafico]) ){
                $this->lista_tipo_graficos[$item1->tipo_grafico] = 0;
            }
            $this->lista_tipo_graficos[$item1->tipo_grafico] += 1; // se agrega a la variable de control de tipos de graficos
        }
        //
        return $data;
    }

    ///////// TIPOS DE GRAFICOS /////////////
    ////// Los datos son tratados para ser usados por la libreria highcharts ///////

    /**
     * Metodo que hace el
     * tratamiento especial
     * para los graficos de
     * barra y columna
     * @access private
     * @param array
     * @return array
     */
    private function graficoBarra($data){
        $datos = [];
        $datos['valores'] = [];
        // $datos['etiquetas'] = []; // usado antes para los nombres de categorias
        $datos['total'] = $data[0]->total ?? 0;
        $datos['indicador'] = $data[0]->clave_indicador ?? NULL;
        if ( isset($data[0]->titulo_indicador) ){
            $datos['indicador'] = $data[0]->titulo_indicador;
        }
        $obj = NULL;
        $val = NULL;
        // Se genera el formato de datos para el grafico
        foreach( $data as $fila ){
            if ( isset($fila->valor) ){
                $val = intval($fila->valor);
                if ( $val ){
                    $obj = (object) ['y' => $val, 'color' => ('#'.$fila->color), 'name' => $fila->n1_name];
                    $obj->custom = (object) ['lista' => $fila->lista];
                    $datos['valores'][] = $obj;
                }
            }
        }
        //
        return $datos;
    }

    /**
     * Metodo que hace el
     * tratamiento especial
     * para los graficos de
     * estallido solar
     * @access private
     * @param array
     * @return array
     */
    private function graficoEstallidoSolar($data){
        $depth = $this->obtenerCantN($data);
        //
        $datos = [];
        $datos['valores'] = [];
        $datos['total'] = $data[0]->total ?? 0;
        $datos['indicador'] = $data[0]->clave_indicador ?? NULL;
        if ( isset($data[0]->titulo_indicador) ){
            $datos['indicador'] = $data[0]->titulo_indicador;
        }
        //
        $datos['valores'][] = (object) ['id' => 'central', 'name' => 'Total', 'parent' => ''];
        // Se genera el formato de datos para el grafico
        for($i=1; $i <= $depth; $i++){
            $elem_ant = ($i-1); // si es 0 no tiene serie padre
            $agregados = [];
            $clave = 'n'.((string)$i);
            $clave_ant = 'n'.((string)($elem_ant));
            $clave_name = $clave.'_name';
            //
            foreach( $data as $fila ){
                //
                if ( $elem_ant ){
                    $unique = $fila->$clave.'_'.$fila->$clave_ant;
                } else {
                    $unique = $fila->$clave; // si no tiene serie padre
                }
                //
                if ( !in_array($unique,$agregados) ){
                    $obj = (object) ['id' => $fila->$clave, 'name' => $fila->$clave_name];
                    $obj->parent = ( $elem_ant ) ? $fila->$clave_ant : 'central'; // si no tiene serie padre es central
                    //
                    $obj->value = NULL;
                    if ( $i == $depth ){
                        $obj->value = intval($fila->valor);
                        $obj->custom = (object) ['lista' => $fila->lista];
                    }
                    //                    
                    $datos['valores'][] = $obj;
                    $agregados[] = $unique;
                }
            }
        }
        //
        return $datos;
    }

    /**
     * Metodo que hace el
     * tratamiento especial
     * para los graficos de
     * torta y donut
     * @access private
     * @param array
     * @return array
     */
    private function graficoTorta($data){
        $datos = [];
        $datos['total'] = $data[0]->total ?? 0;
        $datos['lista'] = $data[0]->lista ?? NULL;
        $datos['indicador'] = $data[0]->clave_indicador ?? NULL;
        if ( isset($data[0]->titulo_indicador) ){
            $datos['indicador'] = $data[0]->titulo_indicador;
        }
        $datos['valores'] = [];
        //
        $obj = NULL;
        $val = NULL;
        // Se genera el formato de datos para el grafico
        foreach( $data as $fila ){
            if ( !isset($fila->valor) ){
                continue;
            }
            $val = intval($fila->valor);
            if ( $val ){
                $obj = (object) ['y' => $val, 'name' => $fila->n1_name];
                if ( !is_null($fila->color) ){
                    $obj->color = '#'.$fila->color;
                }
                $obj->custom = (object) ['rango' => $fila->n1 , 'lista' => $fila->lista];
                $datos['valores'][] = $obj;
            }
        }
        //
        return $datos;
    }

    /**
     * Metodo que hace el
     * tratamiento especial
     * para los graficos de
     * donut con etiqueta
     * @access private
     * @param array
     * @return array
     */
    private function graficoDonutEtiqueta($data){
        $datos = [];
        $datos['total'] = $data[0]->total ?? 0;
        $datos['lista'] = $data[0]->lista ?? NULL;
        $datos['indicador'] = $data[0]->clave_indicador ?? NULL;
        if ( isset($data[0]->titulo_indicador) ){
            $datos['indicador'] = $data[0]->titulo_indicador;
        }
        $datos['valores'] = [];
        //
        $obj = NULL;
        $val = NULL;
        // Se genera el formato de datos para el grafico
        foreach( $data as $fila ){
            $val = intval($fila->valor);
            if ( $val ){
                $obj = (object) ['y' => $val, 'name' => $fila->n1_name];
                if ( !is_null($fila->color) ){
                    $obj->color = '#'.$fila->color;
                }
                $obj->custom = (object) ['rango' => $fila->n1 , 'lista' => $fila->lista];
                if ( $fila->mostrar_etiqueta == '1' ){
                   $obj->custom->etiqueta_mostrar = $fila->que_mostrar;
                }
                $datos['valores'][] = $obj;
            }
        }
        //
        return $datos;
    }

    /**
     * Metodo que hace el
     * tratamiento especial
     * para los graficos de
     * sankey
     * @access private
     * @param array
     * @return array
     */
    private function graficoSankey($data){
        $datos = [];
        $datos['valores'] = []; // vector de conexiones
        $datos['nodos'] = []; // vector de nodos
        $datos['total'] = $data[0]->total ?? 0;
        $datos['indicador'] = $data[0]->clave_indicador ?? NULL;
        if ( isset($data[0]->titulo_indicador) ){
            $datos['indicador'] = $data[0]->titulo_indicador;
        }
        //
        $nodos_agregados = [];
        $obj = null;
        foreach( $data as $fila ){
            // se almacenan las conexiones entre los nodos y su peso
            // el 'from' y 'to' deben ser los 'id' de los nodos conectados
            $obj = (object) ['from' => $fila->n1,'to' => $fila->n2,'weight' => intval($fila->valor)];
            $obj->id = ($fila->n1.'_'.$fila->n2);
            $obj->name = ($fila->n1_name.' -> '.$fila->n2_name);
            $obj->custom = (object) ['lista' => $fila->lista];
            $datos['valores'][] = $obj;
            // se almacenan los nodos
            if ( !in_array($fila->n1,$nodos_agregados) ){
                $datos['nodos'][] = (object) ['id' => $fila->n1,'name' => $fila->n1_name];
                $nodos_agregados[] = $fila->n1;
            }
            //
            if ( !in_array($fila->n2,$nodos_agregados) ){
                $datos['nodos'][] = (object) ['id' => $fila->n2,'name' => $fila->n2_name];
                $nodos_agregados[] = $fila->n2;
            }
        }
        //
        return $datos;
    }

    /**
     * Metodo que hace el
     * tratamiento especial
     * para los graficos de
     * pictorial
     * @access private
     * @param array
     * @return array
     */
    private function graficoPictorial($data){
        $datos = [];
        $datos['valores'] = []; // vector de conexiones
        $datos['total'] = $data[0]->total ?? 0;
        $datos['indicador'] = $data[0]->clave_indicador ?? NULL;
        if ( isset($data[0]->titulo_indicador) ){
            $datos['indicador'] = $data[0]->titulo_indicador;
        }
        //
        $val = null;
        $obj = null;
        $custom = null;
        foreach( $data as $fila ){
            $val = intval($fila->valor); // el entero de la cadena
            if ( $val ){
                $obj = (object) ['name' => $fila->n1_name,'color' => '#'.$fila->color]; // datos de la serie
                $custom = (object) ['valor' => $fila->n1,'lista' => $fila->lista]; // datos adicionales (filtro)
                $obj->data[] = (object) ['x' => 0,'y' => $val,'custom' => $custom];
                $datos['valores'][] = $obj;
            }
        }
        //
        return $datos;
    }

    /**
     * Obtener las series o
     * la profundidad o la cantidad de
     * indicadores con letra 'n' que 
     * se devuelve para los datos de
     * los graficos
     * @access private
     * @param array
     * @return int
     */
    private function obtenerCantN($data){
        $indicador = 0;
        if ( !empty($data) ){
            $claves = get_object_vars($data[0]);
            $claves = array_keys($claves);
            $patron = "/^n\d$/"; // patron de series
            //
            $indicador = count(preg_grep($patron,$claves));
        }
        //    
        return $indicador;
    }
}