//
// Created by xajhu on 2021/7/6 0006.
//
#include <string.h>
#include <uv.h>

#include "s2j/s2j.h"
#include "hardware.h"
#include "user_errno.h"
#include "config.h"
#include "misc.h"

static HARDWARE_INFO g_hardwareInfo;

_Noreturn void hardwareRefreshCb(void *UNUSED(pArg)) {
    do {
        unsigned int period = cfg_get_hardware_refresh_period();

        if (cfg_get_watch_sensor()) {
            get_sensor_info(&g_hardwareInfo.sensorInfo);
        }

        if (cfg_get_watch_disk()) {
            get_disk_info(&g_hardwareInfo.diskInfo);
        }

        if (cfg_get_watch_cpu()) {
            get_cpu_info(&g_hardwareInfo.cpuInfo);
        }

        if (cfg_get_watch_memory()) {
            get_memory_info(&g_hardwareInfo.memInfo);
        }

        if (period < REFRESH_MAX_PERIOD && period >= 1) {
            uv_sleep(1000 * period);
        } else {
            uv_sleep(1000);
        }

        uv_sleep(1000);
    } while (TRUE);
}

int init_hardware() {
    static uv_thread_t uvThread;

    memset(&g_hardwareInfo, 0, sizeof(HARDWARE_INFO));

    uv_thread_create(&uvThread, hardwareRefreshCb, NULL);

    cpu_watch_init();
    memory_watch_init();
    disk_watch_info();
    sensor_watch_init();

    return ERR_SUCCESS;
}

/***************************************************************
*  CPU_INFO json 格式化相关函数
***************************************************************/
static cJSON *struct_to_json_CPU_DESC(void *pObj) {
    PCPU_DESC pCpuDesc = (PCPU_DESC)pObj;    //&((PCPU_INFO)pObj)->cpuCoreDesc;
    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pCpuDesc, int, cpuSpeed);
    s2j_json_set_basic_element(pJsonObj, pCpuDesc, string, cpuName);

    return pJsonObj;
}

static cJSON *struct_to_json_CPU_INFO(void *pObj) {
    PCPU_INFO pCpuInfo = (PCPU_INFO)pObj;    //&((PHARDWARE_INFO)pObj)->cpuInfo;
    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pCpuInfo, int, nCores);
    s2j_json_set_basic_element(pJsonObj, pCpuInfo, int, nLogicCores);
    s2j_json_set_basic_element(pJsonObj, pCpuInfo, int, nCpus);
    s2j_json_set_basic_element(pJsonObj, pCpuInfo, double, cpuUsed);
    s2j_json_set_basic_element(pJsonObj, pCpuInfo, int, timestamp);
    s2j_json_set_struct_element_by_func(pJsonObj, pCpuInfo, CPU_DESC, cpuCoreDesc);

    return pJsonObj;
}

/***************************************************************
*  MEMORY_INFO json 格式化相关函数
***************************************************************/
static cJSON *struct_to_json_MEMORY_INFO(void *pObj) {
    PMEMORY_INFO pMemInfo = (PMEMORY_INFO)pObj;
    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pMemInfo, string, cachedMemSize);
    s2j_json_set_basic_element(pJsonObj, pMemInfo, string, bufferMemSize);
    s2j_json_set_basic_element(pJsonObj, pMemInfo, string, availMemSize);
    s2j_json_set_basic_element(pJsonObj, pMemInfo, string, freeMemSize);
    s2j_json_set_basic_element(pJsonObj, pMemInfo, string, totalMemSize);
    s2j_json_set_basic_element(pJsonObj, pMemInfo, int, timestamp);

    return pJsonObj;
}

/***************************************************************
*  DISK_INFO json 格式化相关函数
***************************************************************/
static cJSON *struct_to_json_DISK_PART_USED(void *pObj) {
    PDISK_PART_USED pDisk = (PDISK_PART_USED)pObj;

    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pDisk, string, deviceName);
    s2j_json_set_basic_element(pJsonObj, pDisk, string, diskSize);
    s2j_json_set_basic_element(pJsonObj, pDisk, string, diskUsed);
    s2j_json_set_basic_element(pJsonObj, pDisk, string, usedPercent);

    return pJsonObj;
}

static cJSON *struct_to_json_DISK_INFO(void *pObj) {
    PDISK_INFO pDiskInfo = (PDISK_INFO)pObj;
    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pDiskInfo, int, nItems);
    s2j_json_set_basic_element(pJsonObj, pDiskInfo, int, timestamp);
    s2j_json_set_struct_array_element_by_func(pJsonObj, pDiskInfo, DISK_PART_USED, diskPartInfo, pDiskInfo->nItems);

    return pJsonObj;
}

/***************************************************************
*  SENSOR_INFO json 格式化相关函数
***************************************************************/
static cJSON *struct_to_json_SENSOR_ITEM(void *pObj) {
    PSENSOR_ITEM pSensor = (PSENSOR_ITEM)pObj;

    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pSensor, string, sensorName);
    s2j_json_set_basic_element(pJsonObj, pSensor, string, value);
    s2j_json_set_basic_element(pJsonObj, pSensor, string, unit);
    s2j_json_set_basic_element(pJsonObj, pSensor, string, status);

    return pJsonObj;
}

static cJSON *struct_to_json_SENSOR_INFO(void *pObj) {
    PSENSOR_INFO pSensorInfo = (PSENSOR_INFO)pObj;
    s2j_create_json_obj(pJsonObj);

    s2j_json_set_basic_element(pJsonObj, pSensorInfo, int, nItems);
    s2j_json_set_basic_element(pJsonObj, pSensorInfo, int, timestamp);
    s2j_json_set_struct_array_element_by_func(pJsonObj, pSensorInfo, SENSOR_ITEM, sensorInfo, pSensorInfo->nItems);

    return pJsonObj;
}

const char *get_hardware_json() {
    const char *pJsonStr;
    s2j_create_json_obj(pJsonObj);

    s2j_json_set_struct_element_by_func(pJsonObj, &g_hardwareInfo, CPU_INFO, cpuInfo);
    s2j_json_set_struct_element_by_func(pJsonObj, &g_hardwareInfo, MEMORY_INFO, memInfo);
    s2j_json_set_struct_element_by_func(pJsonObj, &g_hardwareInfo, DISK_INFO, diskInfo);
    s2j_json_set_struct_element_by_func(pJsonObj, &g_hardwareInfo, SENSOR_INFO, sensorInfo);

    pJsonStr = cJSON_Print(pJsonObj);
    cJSON_Delete(pJsonObj);

    return pJsonStr;
}