#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include "bmser_log.h"
#include "cJSON.h"
#include "bmser_cjson.h"


/**
 * @brief 根据给定的路径，在 cJSON 对象中找到对应的项。
 *
 * @param[in] root cJSON 根对象指针。
 * @param[in] path 路径字符串。
 * @return cJSON* 成功时返回找到的 cJSON 项, 否则返回NULL。
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-08           JHC        创建初始版本          \n
 */
cJSON* get_json_item_by_path(cJSON* root, const char* path) {
    if (!root || !path) return NULL;
#ifdef WIN32
    char* path_copy = _strdup(path); // 创建path的副本
#else
    char* path_copy = strdup(path); // 创建path的副本
#endif
    if (!path_copy) {
        // 处理_strdup失败的情况
        return NULL;
    }
#ifdef WIN32
    char* context = NULL; // strtok_s需要的额外指针，用于在后续调用中维持状态
    char* token = strtok_s(path_copy, ".[", &context); // 初始化标记
#else
    char* rest = path_copy;  // strtok_r的额外指针，用于保持上下文
    char* token = strtok_r(path_copy, ".[", &rest); // 初始化标记
#endif
    cJSON* current_element = root;

    while (token != NULL && current_element != NULL) {
        // 数组访问
        char* endptr = NULL;  // strtol将在这里指向遍历后的下一个字符
        long index = strtol(token, &endptr, 10);
        // 检查是否有数字被解析，并验证是不是遇到了中括号内的情况
        if (endptr != token && *endptr == ']') {
            current_element = cJSON_GetArrayItem(current_element, (int)index);
        }
        else {
            current_element = cJSON_GetObjectItemCaseSensitive(current_element, token);
        }
#ifdef WIN32
        token = strtok_s(NULL, ".[", &context);
#else
        // 为下一个迭代获得新token
        token = strtok_r(NULL, ".[", &rest);
#endif
    }

    free(path_copy);
    return current_element; // 返回找到的项或NULL
}

/**
 * @brief 解析 JSON 文本并获取指定路径上 JSON 数组的长度。
 *
 * @param[in] json_text JSON 文本字符串。
 * @param[in] path 要获取数组长度的 JSON 路径。
 * @return int 成功时返回数组的长度, 如果输入无效或者项不存在返回-1。
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-08           JHC        创建初始版本          \n
 */
int json_get_array_length(const char* json_text, const char* path) {
    if (json_text == NULL || path == NULL) {
        // 如果输入参数无效，返回错误。
        return -1;
    }

    cJSON* json = cJSON_Parse(json_text);
    if (json == NULL) {
        // 如果无法解析 JSON，返回错误。
        return -1;
    }

    cJSON* array_item = get_json_item_by_path(json, path);
    if (array_item == NULL || !cJSON_IsArray(array_item)) {
        // 如果找不到路径对应的项或该项不是数组，返回错误。
        cJSON_Delete(json);
        return -1;
    }

    int array_length = cJSON_GetArraySize(array_item);
    cJSON_Delete(json);
    return array_length;
}

/**
 * @brief 根据给定的 JSON 文本和路径获取数据，并填充到结果结构体中。
 *
 * @param[in] json_text JSON 文本字符串。
 * @param[in] path 路径字符串，指定要获取数据的路径。
 * @param[out] result 指向 JsonValue 结构体的指针，用于存放获取到的数据。
 * @return int 成功时返回0, 失败时返回-1。
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-08           JHC        创建初始版本          \n
 */
int json_value_get_by_json_path(const char* json_text, const char* path, JsonValue* result) {

    int ret = 0;
    // 参数有效性检查
    if (json_text == NULL || path == NULL || result == NULL) {
        return -1; // 失败
    }

    // 解析整个JSON文档
    cJSON* json = cJSON_Parse(json_text);
    if (json == NULL) {
        result->type = JSON_VALUE_NONE;
        return -1; // 失败
    }

    // 获取由点分隔的路径指定的项
    cJSON* item = get_json_item_by_path(json, path);

    // 根据项的类型设置结果结构体
    if (item != NULL) {
        if (cJSON_IsNumber(item)) {
            result->type = JSON_VALUE_NUMBER;
            result->value.doubleVal = item->valuedouble;
            result->value.int64Val = (long long)item->valuedouble;
        }
        else if (cJSON_IsString(item)) {
            result->type = JSON_VALUE_STRING;
            strncpy(result->value.stringVal, item->valuestring, MAX_JSON_STRING_SIZE - 1); // 安全的复制函数
            result->value.stringVal[MAX_JSON_STRING_SIZE - 1] = '\0'; // 确保字符串以 null 终止
        }
        else {
            result->type = JSON_VALUE_NONE;
        }
    }
    else {
        // 没有找到对应的项
        result->type = JSON_VALUE_NONE;
        ret = -1;
    }

    cJSON_Delete(json); // 清理 cJSON 对象
    return ret; // 成功
}


 /**
  * 读取文件内容并返回文件的全部文本内容。
  *
  * @param[i] fileName 需要读取的文件名。
  * @return 返回指向文件内容的指针。需要由调用者负责释放这段内存。若出错，则返回NULL。
  * @par         修改日志:
  * Date                Author     Description           \n
  * 2023-12-08           JHC        创建初始版本          \n
  */
char* jsonFileContent_read(const char* fileName) 
{
    if (fileName == NULL) {
        dy_syslog(LOG_ERR,"Input file name is NULL.\n");
        return NULL;
    }

    // 尝试打开文件
    FILE* f = fopen(fileName, "rb");
    if (f == NULL) {
        dy_syslog(LOG_ERR,"Failed to open %s\nPlease check if the file exists and the path is correct.\n", fileName);
        return NULL;
    }

    // 跳到文件末尾获取文件大小
    fseek(f, 0, SEEK_END);
    long len = ftell(f);
    // 返回文件的起始位置
    rewind(f);

    // 为文件内容分配内存
    char* fileContent = (char*)malloc(len + 1);
    if (fileContent == NULL) {
        dy_syslog(LOG_ERR,"Memory allocation failed for file content.\n");
        fclose(f); // 务必关闭文件
        return NULL;
    }

    // 从文件中读取内容
    size_t readLength = fread(fileContent, 1, len, f);
    if (readLength != len) {
        dy_syslog(LOG_ERR,"Could not read the full file content.\n");
        free(fileContent); // 释放内存
        fclose(f);  // 关闭文件
        return NULL;
    }

    // 确保字符串以 null 终止
    fileContent[len] = '\0';

    // 关闭文件
    fclose(f);

    return fileContent;
}
