/* Chrysalide - Outil d'analyse de fichiers binaires
 * json.c - manipulations génériques de données au format JSON
 *
 * Copyright (C) 2024 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Chrysalide is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "json.h"


#include <assert.h>



/******************************************************************************
*                                                                             *
*  Paramètres  : root  = racine d'une arborescence JSON chargée.              *
*                query = chemin XPath d'une requête à mener.                  *
*                error = description d'une éventuelle erreur rencontrée. [OUT]*
*                                                                             *
*  Description : Détermine la présence d'un élément avec une valeur textuelle.*
*                                                                             *
*  Retour      : true si le noeud existe et porte une chaîne comme valeur.    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool has_json_string_value(JsonNode *root, const char *xpath, GError **error)
{
    bool result;                            /* Bilan à retourner           */
    JsonNode *found;                        /* Accès direct aux trouvailles*/
    JsonArray *array;                       /* Liste des résultats         */
    guint count;                            /* Taille de la liste          */
    JsonNode *node;                         /* Noeud portant la cible      */
    GValue value;                           /* Valeur correspondante       */

    result = false;

    *error = NULL;
    found = json_path_query(xpath, root, error);

    if (found != NULL)
    {
        assert(*error == NULL);

        array = json_node_get_array(found);

        count = json_array_get_length(array);

        if (count == 1)
        {
            node = json_array_get_element(array, 0);

            memset(&value, 0, sizeof(GValue));
            json_node_get_value(node, &value);

            if (G_VALUE_HOLDS(&value, G_TYPE_STRING))
                result = true;

        }

        json_node_unref(found);

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : root  = racine d'une arborescence JSON chargée.              *
*                query = chemin XPath d'une requête à mener.                  *
*                error = description d'une éventuelle erreur rencontrée. [OUT]*
*                                                                             *
*  Description : Fournit le contenu d'un élément avec une valeur textuelle.   *
*                                                                             *
*  Retour      : Valeur trouvée ou NULL en cas d'échec.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

char *get_json_string_value(JsonNode *root, const char *xpath, GError **error)
{
    char *result;                           /* Valeur à retourner          */
    JsonNode *found;                        /* Accès direct aux trouvailles*/
    JsonArray *array;                       /* Liste des résultats         */
    guint count;                            /* Taille de la liste          */
    JsonNode *node;                         /* Noeud portant la cible      */
    GValue value;                           /* Valeur correspondante       */
    const gchar *raw;                       /* Valeur brute présente       */

    result = NULL;

    *error = NULL;
    found = json_path_query(xpath, root, error);

    if (found != NULL)
    {
        assert(*error == NULL);

        array = json_node_get_array(found);

        count = json_array_get_length(array);

        if (count == 1)
        {
            node = json_array_get_element(array, 0);

            memset(&value, 0, sizeof(GValue));
            json_node_get_value(node, &value);

            if (G_VALUE_HOLDS(&value, G_TYPE_STRING))
            {
                raw = json_array_get_string_element(array, 0);
                result = strdup(raw);
            }

        }

        json_node_unref(found);

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : root  = racine d'une arborescence JSON chargée.              *
*                query = chemin XPath d'une requête à mener.                  *
*                error = description d'une éventuelle erreur rencontrée. [OUT]*
*                                                                             *
*  Description : Fournit le contenu d'un élément avec une valeur entière.     *
*                                                                             *
*  Retour      : Valeur trouvée ou NULL en cas d'échec.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

long long get_json_integer_value(JsonNode *root, const char *xpath, GError **error)
{
    long long result;                       /* Valeur à retourner          */
    JsonNode *found;                        /* Accès direct aux trouvailles*/
    JsonArray *array;                       /* Liste des résultats         */
    guint count;                            /* Taille de la liste          */
    JsonNode *node;                         /* Noeud portant la cible      */
    GValue value;                           /* Valeur correspondante       */

    result = 0xffffffffffffffffll;

    *error = NULL;
    found = json_path_query(xpath, root, error);

    if (found != NULL)
    {
        assert(*error == NULL);

        array = json_node_get_array(found);

        count = json_array_get_length(array);

        if (count == 1)
        {
            node = json_array_get_element(array, 0);

            memset(&value, 0, sizeof(GValue));
            json_node_get_value(node, &value);

            if (G_VALUE_HOLDS(&value, G_TYPE_INT64))
                result = json_array_get_int_element(array, 0);

        }

        json_node_unref(found);

    }

    return result;

}