/** @file dc_signal_show.cpp — 信号展示/导出（tinyxml2 C++ API + libcmd C 接口） */
#include "dc_internal.h"
#include "myCmd.h"
#include "tinyxml2.h"
#include <cstdio>
#include <iostream>

extern "C" {

/**
 * @brief 格式化打印一张信号表的所有信号
 * @param smap 信号表引用
 */
static void dc_show_signals(dc_signal_map_t &smap)
{
    const int COL_ID = 8;
    const int COL_SADDR = 36;
    const int COL_DESC = 48;
    const int COL_TYPE = 10;
    const int COL_VAL = 24;
    const int COL_LINK = 48;

    auto pad_right = [](const std::string &s, int w) -> std::string
    {
        int pad = w - (int)s.length();

        if (pad > 0)
        {
            return s + std::string((size_t)pad, ' ');
        }

        return s + ' ';
    };

    std::cout << "\t"
              << pad_right("id", COL_ID)
              << pad_right("saddr", COL_SADDR)
              << pad_right("desc", COL_DESC)
              << pad_right("type", COL_TYPE)
              << pad_right("val", COL_VAL)
              << pad_right("link_saddrs", COL_LINK)
              << std::endl;

    int total = COL_ID + COL_SADDR + COL_DESC + COL_TYPE + COL_VAL + COL_LINK;

    std::cout << "\t" << std::string((size_t)total, '-') << std::endl;

    for (uint32_t i = 0; i < smap.signal_id; i++)
    {
        dc_signal_t *ps = dc_core_find_by_id(i, smap);

        if (!ps)
        {
            continue;
        }

        std::string link_str;

        for (int j = 0; j < ps->link_count; j++)
        {
            if (j > 0)
            {
                link_str += ", ";
            }

            link_str += ps->link_saddrs[j];
        }

        std::string val_str = dc_util_val_to_string(ps->vec_p_data[0],
                                                     ps->data_type);

        std::cout << "\t"
                  << pad_right(std::to_string(ps->id), COL_ID)
                  << pad_right(ps->saddr, COL_SADDR)
                  << pad_right(ps->desc, COL_DESC)
                  << pad_right(dc_util_type_name(ps->data_type), COL_TYPE)
                  << pad_right(val_str, COL_VAL)
                  << pad_right(link_str, COL_LINK)
                  << std::endl;
    }
}

/**
 * @brief datacenter 命令处理：out/in/yk/ao/param/all 子命令
 */
static void cmd_dc_func(int argc, char *argv[])
{
    const char *help = "datacenter out|in|yk|ao|param|all\n";

    if (argc < 2)
    {
        printf("%s", help);

        return;
    }

    if (0 == strcmp(argv[1], "out"))
    {
        printf("out signals:\n");
        dc_show_signals(g_dc_out);
    }
    else if (0 == strcmp(argv[1], "yk"))
    {
        printf("yk signals:\n");
        dc_show_signals(g_dc_yk);
    }
    else if (0 == strcmp(argv[1], "ao"))
    {
        printf("ao signals:\n");
        dc_show_signals(g_dc_ao);
    }
    else if (0 == strcmp(argv[1], "param"))
    {
        printf("param signals:\n");
        dc_show_signals(g_dc_param);
    }
    else if (0 == strcmp(argv[1], "all"))
    {
        printf("out signals:\n");
        dc_show_signals(g_dc_out);
        printf("yk signals:\n");
        dc_show_signals(g_dc_yk);
        printf("ao signals:\n");
        dc_show_signals(g_dc_ao);
        printf("param signals:\n");
        dc_show_signals(g_dc_param);
    }
}

/**
 * @brief datacenter 命令的 Tab 补全回调
 */
static void cmd_dc_complete_func(const char *buf, char ***completions, int *ncomp)
{
    static const char *subs[] = {"out", "in", "yk", "ao", "param", "all"};

    cmd_sub_complete(buf, completions, ncomp, subs,
                     (int)(sizeof(subs) / sizeof(subs[0])));
}

CMD_REGISTER_C("datacenter", cmd_dc_func, "datacenter信号查看", cmd_dc_complete_func);

/**
 * @brief 保存所有已注册 out 信号到 XML（PLC 配置导出）
 * @param path 目标文件路径
 * @return DC_OK 成功，<0 失败
 */
int dc_save_out_signals_xml(const char *path)
{
    if (!g_initialized || !path)
    {
        return DC_ERR_PARAM;
    }

    tinyxml2::XMLDocument doc;

    doc.InsertEndChild(doc.NewDeclaration());

    tinyxml2::XMLElement *root = doc.NewElement("Root");

    doc.InsertEndChild(root);

    tinyxml2::XMLElement *out_elem = doc.NewElement("Out");

    out_elem->SetAttribute("count", (int)g_dc_out.signal_id);

    for (uint32_t i = 0; i < g_dc_out.signal_id; i++)
    {
        dc_signal_t *ps = dc_core_find_by_id(i, g_dc_out);

        if (!ps)
        {
            continue;
        }

        tinyxml2::XMLElement *sig = doc.NewElement("Signal");

        sig->SetAttribute("no", (int)i);
        sig->SetAttribute("saddr", ps->saddr);
        sig->SetAttribute("desc", ps->desc);
        out_elem->InsertEndChild(sig);
    }

    root->InsertEndChild(out_elem);

    if (doc.SaveFile(path) != tinyxml2::XML_SUCCESS)
    {
        LOG_E("failed to save out signals to %s\n", path);

        return DC_ERR_PARAM;
    }

    LOG_I("out signals saved to %s, count=%u\n", path, g_dc_out.signal_id);

    return DC_OK;
}

} /* extern "C" */
