/** @file dc_signal_query.cpp — 信号查询 */
#include "dc_internal.h"

/** @brief 通用信号信息查询内部函数 */
static int dc_query_info(dc_signal_map_t *pmap, const char *saddr,
    char *desc, int desc_len, uint8_t *data_type, void **p_data)
{
    if (!g_initialized || !saddr)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, *pmap);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (desc && desc_len > 0)
    {
        strncpy(desc, ps->desc, desc_len - 1);
        desc[desc_len - 1] = '\0';
    }

    if (data_type)
    {
        *data_type = ps->data_type;
    }

    if (p_data && ps->vec_p_data && ps->vec_p_data_count > 0)
    {
        *p_data = ps->vec_p_data[0];
    }

    return DC_OK;
}

/** @brief 查询 out 信号信息 */
int dc_get_out_signal_info(const char *saddr, char *desc, int desc_len,
    uint8_t *data_type, void **p_data)
{
    return dc_query_info(&g_dc_out, saddr, desc, desc_len, data_type, p_data);
}

/** @brief 查询 AO 信号信息（含参数元数据和控型） */
int dc_get_ao_signal_info(const char *saddr, char *desc, int desc_len,
    uint8_t *data_type, dc_param_meta_t *p_meta, uint8_t *ctrl_type,
    void **p_data)
{
    if (!g_initialized || !saddr)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_ao);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (desc && desc_len > 0)
    {
        strncpy(desc, ps->desc, desc_len - 1);
        desc[desc_len - 1] = '\0';
    }

    if (data_type)
    {
        *data_type = ps->data_type;
    }

    if (p_meta)
    {
        *p_meta = ps->param;
    }

    if (ctrl_type)
    {
        *ctrl_type = ps->ctrl_type;
    }

    if (p_data && ps->vec_p_data && ps->vec_p_data_count > 0)
    {
        *p_data = ps->vec_p_data[0];
    }

    return DC_OK;
}

/** @brief 查询定值信号信息（含多定值区数据指针数组） */
int dc_get_param_signal_info(const char *saddr, char *desc, int desc_len,
    uint8_t *data_type, dc_param_meta_t *p_meta, uint8_t *ctrl_type,
    void **p_data_array, int *p_count)
{
    if (!g_initialized || !saddr)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_param);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (desc && desc_len > 0)
    {
        strncpy(desc, ps->desc, desc_len - 1);
        desc[desc_len - 1] = '\0';
    }

    if (data_type)
    {
        *data_type = ps->data_type;
    }

    if (p_meta)
    {
        *p_meta = ps->param;
    }

    if (ctrl_type)
    {
        *ctrl_type = ps->ctrl_type;
    }

    if (p_data_array && p_count)
    {
        *p_count = ps->vec_p_data_count;

        for (int i = 0; i < ps->vec_p_data_count; i++)
        {
            p_data_array[i] = ps->vec_p_data[i];
        }
    }

    return DC_OK;
}

/** @brief 查询遥控信号信息 */
int dc_get_yk_signal_info(const char *saddr, char *desc, int desc_len,
    uint8_t *data_type, uint8_t *ctrl_type, void **p_data)
{
    if (!g_initialized || !saddr)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_yk);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (desc && desc_len > 0)
    {
        strncpy(desc, ps->desc, desc_len - 1);
        desc[desc_len - 1] = '\0';
    }

    if (data_type)
    {
        *data_type = ps->data_type;
    }

    if (ctrl_type)
    {
        *ctrl_type = ps->ctrl_type;
    }

    if (p_data && ps->vec_p_data && ps->vec_p_data_count > 0)
    {
        *p_data = ps->vec_p_data[0];
    }

    return DC_OK;
}

/** @brief 将信号值按类型转为字符串写入 buf */
int dc_get_signal_val(const void *p_data, uint8_t data_type,
    char *buf, int buf_len)
{
    if (!p_data || !buf || buf_len <= 0)
    {
        return DC_ERR_PARAM;
    }

    std::string s = dc_util_val_to_string(p_data, data_type);

    if (s.empty())
    {
        return DC_ERR_TYPE;
    }

    strncpy(buf, s.c_str(), buf_len - 1);
    buf[buf_len - 1] = '\0';

    return DC_OK;
}

/** @brief 按信号类型字符串获取已注册信号数量 */
int dc_get_signal_count(const char *type_str)
{
    dc_signal_map_t *pmap = NULL;

    if (type_str)
    {
        if (0 == strcmp(type_str, "out"))
        {
            pmap = &g_dc_out;
        }
        else if (0 == strcmp(type_str, "yk"))
        {
            pmap = &g_dc_yk;
        }
        else if (0 == strcmp(type_str, "ao"))
        {
            pmap = &g_dc_ao;
        }
        else if (0 == strcmp(type_str, "param"))
        {
            pmap = &g_dc_param;
        }
    }

    if (!pmap)
    {
        return 0;
    }

    return (int)pmap->signal_id;
}

/** @brief 按信号类型和 ID 获取信号详细信息 */
int dc_get_signal_info_by_id(const char *type_str, uint32_t id,
    char *saddr, int saddr_len, char *desc, int desc_len,
    char *data_type_str, int type_str_len, uint8_t *ctrl_type,
    char *link_str, int link_len)
{
    if (!type_str)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_map_t *pmap = NULL;

    if (0 == strcmp(type_str, "out"))
    {
        pmap = &g_dc_out;
    }
    else if (0 == strcmp(type_str, "yk"))
    {
        pmap = &g_dc_yk;
    }
    else if (0 == strcmp(type_str, "ao"))
    {
        pmap = &g_dc_ao;
    }
    else if (0 == strcmp(type_str, "param"))
    {
        pmap = &g_dc_param;
    }

    if (!pmap)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find_by_id(id, *pmap);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (saddr && saddr_len > 0)
    {
        strncpy(saddr, ps->saddr, saddr_len - 1);
        saddr[saddr_len - 1] = '\0';
    }

    if (desc && desc_len > 0)
    {
        strncpy(desc, ps->desc, desc_len - 1);
        desc[desc_len - 1] = '\0';
    }

    if (data_type_str && type_str_len > 0)
    {
        std::string n = dc_util_type_name(ps->data_type);

        strncpy(data_type_str, n.c_str(), type_str_len - 1);
        data_type_str[type_str_len - 1] = '\0';
    }

    if (ctrl_type)
    {
        *ctrl_type = ps->ctrl_type;
    }

    if (link_str && link_len > 0)
    {
        link_str[0] = '\0';

        for (int i = 0; i < ps->link_count; i++)
        {
            if (i > 0)
            {
                strncat(link_str, ",", link_len - strlen(link_str) - 1);
            }
            strncat(link_str, ps->link_saddrs[i],
                link_len - strlen(link_str) - 1);
        }
    }

    return DC_OK;
}
