/** @file dc_signal_util.cpp — 类型工具函数 */
#include "dc_internal.h"

struct { uint8_t id; const char *name; uint8_t len; } static const kTypeTab[] = {
    {DATA_TYPE_B,   "bool",    1},
    {DATA_TYPE_S8,  "int8_t",  1},
    {DATA_TYPE_U8,  "uint8_t", 1},
    {DATA_TYPE_S16, "int16_t", 2},
    {DATA_TYPE_U16, "uint16_t", 2},
    {DATA_TYPE_S32, "int32_t", 4},
    {DATA_TYPE_U32, "uint32_t", 4},
    {DATA_TYPE_L64, "int64_t", 8},
    {DATA_TYPE_UL64,"uint64_t", 8},
    {DATA_TYPE_F32, "float",   4},
    {DATA_TYPE_D64, "double",  8},
    {DATA_TYPE_IP,  "ip",      4},
    {DATA_TYPE_MAC, "mac",     8},
    {DATA_TYPE_C8,  "char8",   8},
    {DATA_TYPE_C32, "char32",  32},
    {DATA_TYPE_C64, "char64",  64},
    {DATA_TYPE_C128,"char128", 128},
    {DATA_TYPE_C1,  "char1",   1},
    {DATA_TYPE_STR, "str",     128},
};

static const int kTypeCount = sizeof(kTypeTab) / sizeof(kTypeTab[0]);

/** @brief 获取数据类型名称字符串 */
std::string dc_util_type_name(uint8_t dt)
{
    for (int i = 0; i < kTypeCount; i++)
    {
        if (kTypeTab[i].id == dt)
        {
            return kTypeTab[i].name;
        }
    }

    return "unknown";
}

/** @brief 获取数据类型名称到缓冲区 (线程安全, 无堆分配) */
void dc_internal_type_name(uint8_t dt, char *buf, int buf_len)
{
	const char *name = "unknown";

	for (int i = 0; i < kTypeCount; i++)
	{
		if (kTypeTab[i].id == dt)
		{
			name = kTypeTab[i].name;
			break;
		}
	}

	if (NULL != buf && buf_len > 0)
	{
		strncpy(buf, name, buf_len - 1);
		buf[buf_len - 1] = '\0';
	}
}

/** @brief 通过名称字符串获取数据类型 ID */
uint8_t dc_util_type_id_by_name(const std::string &n)
{
    for (int i = 0; i < kTypeCount; i++)
    {
        if (n == kTypeTab[i].name)
        {
            return kTypeTab[i].id;
        }
    }

    return 0;
}

/** @brief 获取数据类型的字节长度 */
uint8_t dc_util_type_len(uint8_t dt)
{
    for (int i = 0; i < kTypeCount; i++)
    {
        if (kTypeTab[i].id == dt)
        {
            return kTypeTab[i].len;
        }
    }

    return 0;
}

/** @brief 根据数据类型创建零初始化内存块 */
void *dc_util_create_data(uint8_t dt)
{
    uint8_t len = dc_util_type_len(dt);

    if (!len)
    {
        return NULL;
    }

    return calloc(1, len);
}

/** @brief 释放由 dc_util_create_data 分配的内存 */
void dc_util_destroy_data(void *p, uint8_t dt)
{
    (void)dt;
    free(p);
}

/** @brief 将源数据按类型拷贝到目标 */
void dc_util_val_copy(void *dst, const void *src, uint8_t dt)
{
    uint8_t len = dc_util_type_len(dt);

    if (len && dst && src)
    {
        memcpy(dst, src, len);
    }
}

/** @brief 按类型比较两个值是否相等，返回 0 相等，-1 不等或错误 */
int dc_util_val_compare(uint8_t dt, const void *p1, const void *p2)
{
    uint8_t len = dc_util_type_len(dt);

    if (!len || !p1 || !p2)
    {
        return -1;
    }

    return memcmp(p1, p2, len) == 0 ? 0 : -1;
}

/** @brief 将值按类型转换为字符串表示 */
std::string dc_util_val_to_string(const void *p, uint8_t dt)
{
    if (!p)
    {
        return "";
    }

    char buf[256] = {0};

    switch (dt)
    {
    case DATA_TYPE_B:
        snprintf(buf, sizeof(buf), "%s", *(uint8_t *)p ? "true" : "false");
        break;
    case DATA_TYPE_S8:
        snprintf(buf, sizeof(buf), "%d", *(int8_t *)p);
        break;
    case DATA_TYPE_U8:
        snprintf(buf, sizeof(buf), "%u", *(uint8_t *)p);
        break;
    case DATA_TYPE_S16:
        snprintf(buf, sizeof(buf), "%d", *(int16_t *)p);
        break;
    case DATA_TYPE_U16:
        snprintf(buf, sizeof(buf), "%u", *(uint16_t *)p);
        break;
    case DATA_TYPE_S32:
        snprintf(buf, sizeof(buf), "%d", *(int32_t *)p);
        break;
    case DATA_TYPE_U32:
        snprintf(buf, sizeof(buf), "%u", *(uint32_t *)p);
        break;
    case DATA_TYPE_L64:
        snprintf(buf, sizeof(buf), "%lld", (long long)*(int64_t *)p);
        break;
    case DATA_TYPE_UL64:
        snprintf(buf, sizeof(buf), "%llu", (unsigned long long)*(uint64_t *)p);
        break;
    case DATA_TYPE_F32:
        snprintf(buf, sizeof(buf), "%.6g", (double)*(float *)p);
        break;
    case DATA_TYPE_D64:
        snprintf(buf, sizeof(buf), "%.12g", *(double *)p);
        break;
    case DATA_TYPE_IP:
        snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
            ((uint8_t *)p)[0], ((uint8_t *)p)[1],
            ((uint8_t *)p)[2], ((uint8_t *)p)[3]);
        break;
    case DATA_TYPE_MAC:
        snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X",
            ((uint8_t *)p)[0], ((uint8_t *)p)[1],
            ((uint8_t *)p)[2], ((uint8_t *)p)[3],
            ((uint8_t *)p)[4], ((uint8_t *)p)[5]);
        break;
    case DATA_TYPE_C8:
    case DATA_TYPE_C32:
    case DATA_TYPE_C64:
    case DATA_TYPE_C128:
    case DATA_TYPE_STR:
        snprintf(buf, sizeof(buf), "%s", (char *)p);
        break;
    case DATA_TYPE_C1:
        snprintf(buf, sizeof(buf), "%c", *(char *)p);
        break;
    default:
        return "";
    }

    return std::string(buf);
}

/** @brief 从字符串解析值并按类型写入内存 */
int dc_util_val_from_string(void *p, uint8_t dt, const std::string &s)
{
    if (!p || s.empty())
    {
        return -1;
    }

    switch (dt)
    {
    case DATA_TYPE_B:
        *(uint8_t *)p = (s == "true" || s == "1") ? 1 : 0;
        break;
    case DATA_TYPE_S8:
        *(int8_t *)p = (int8_t)atoi(s.c_str());
        break;
    case DATA_TYPE_U8:
        *(uint8_t *)p = (uint8_t)atoi(s.c_str());
        break;
    case DATA_TYPE_S16:
        *(int16_t *)p = (int16_t)atoi(s.c_str());
        break;
    case DATA_TYPE_U16:
        *(uint16_t *)p = (uint16_t)atoi(s.c_str());
        break;
    case DATA_TYPE_S32:
        *(int32_t *)p = (int32_t)atoi(s.c_str());
        break;
    case DATA_TYPE_U32:
        *(uint32_t *)p = (uint32_t)strtoul(s.c_str(), NULL, 10);
        break;
    case DATA_TYPE_L64:
        *(int64_t *)p = (int64_t)strtoll(s.c_str(), NULL, 10);
        break;
    case DATA_TYPE_UL64:
        *(uint64_t *)p = (uint64_t)strtoull(s.c_str(), NULL, 10);
        break;
    case DATA_TYPE_F32:
        *(float *)p = (float)atof(s.c_str());
        break;
    case DATA_TYPE_D64:
        *(double *)p = atof(s.c_str());
        break;
    case DATA_TYPE_IP:
    {
        int a, b, c, d;

        if (4 == sscanf(s.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d))
        {
            ((uint8_t *)p)[0] = (uint8_t)a;
            ((uint8_t *)p)[1] = (uint8_t)b;
            ((uint8_t *)p)[2] = (uint8_t)c;
            ((uint8_t *)p)[3] = (uint8_t)d;
        }
        break;
    }
    case DATA_TYPE_MAC:
    {
        int m[6];

        if (6 == sscanf(s.c_str(), "%02X:%02X:%02X:%02X:%02X:%02X",
            &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]))
        {
            for (int i = 0; i < 6; i++)
            {
                ((uint8_t *)p)[i] = (uint8_t)m[i];
            }
        }
        break;
    }
    case DATA_TYPE_C8:
    case DATA_TYPE_C32:
    case DATA_TYPE_C64:
    case DATA_TYPE_C128:
    case DATA_TYPE_STR:
        strncpy((char *)p, s.c_str(), dc_util_type_len(dt) - 1);
        break;
    case DATA_TYPE_C1:
        *(char *)p = s[0];
        break;
    default:
        return -1;
    }

    return 0;
}
