#include "make_out_cfg.h"

#include <sstream>
#include <iomanip>

LOCAL const char *type_id_to_str(uint8_t type_id)
{
    switch (type_id)
    {
    case DATA_TYPE_B:    return "B";
    case DATA_TYPE_S8:   return "s8";
    case DATA_TYPE_U8:   return "u8";
    case DATA_TYPE_S16:  return "s16";
    case DATA_TYPE_U16:  return "u16";
    case DATA_TYPE_S32:  return "s32";
    case DATA_TYPE_U32:  return "u32";
    case DATA_TYPE_F32:  return "f32";
    case DATA_TYPE_IP:   return "ip";
    case DATA_TYPE_MAC:  return "mac";
    case DATA_TYPE_C8:   return "c8";
    case DATA_TYPE_C32:  return "c32";
    case DATA_TYPE_C64:  return "c64";
    case DATA_TYPE_C1:   return "c1";
    default:             return "unknown";
    }
}


LOCAL tinyxml2::XMLElement *add_info_element(tinyxml2::XMLDocument &doc, tinyxml2::XMLElement *parent, const stru_st_mx_co_dd_info &info)
{
    // 创建 Item 节点
    tinyxml2::XMLElement *item = doc.NewElement("Item");

    // 设置 saddr 属性
    item->SetAttribute("saddr", info.saddr.c_str());

    // 设置desc属性
    item->SetAttribute("desc", info.desc.c_str());
    // 设置inf属性
    std::ostringstream oss;
    oss << "0x" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << info.inf;
    item->SetAttribute("inf_hex", oss.str().c_str());

    item->SetAttribute("inf", (int)info.inf);

    parent->InsertEndChild(item);
    return item;
}

LOCAL void add_param_element(tinyxml2::XMLDocument &doc, tinyxml2::XMLElement *parent, const stru_param_cfg_data &param)
{
    // tinyxml2::XMLElement *item = doc.NewElement("Param");

    // tinyxml2::XMLElement *saddr = doc.NewElement("saddr");
    // saddr->SetText(param.saddr.c_str());
    // item->InsertEndChild(saddr);

    // tinyxml2::XMLElement *desc = doc.NewElement("desc");
    // desc->SetText(param.desc.c_str());
    // item->InsertEndChild(desc);

    // tinyxml2::XMLElement *type_str = doc.NewElement("type_str");
    // type_str->SetText(param.type_str.c_str());
    // item->InsertEndChild(type_str);

    // tinyxml2::XMLElement *default_value = doc.NewElement("default_value");
    // default_value->SetText(param.default_value.c_str());
    // item->InsertEndChild(default_value);

    // tinyxml2::XMLElement *type_id = doc.NewElement("type_id");
    // type_id->SetText(type_id_to_str(param.type));
    // item->InsertEndChild(type_id);

    // std::ostringstream oss;
    // oss << "0x" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << param.inf;
    // tinyxml2::XMLElement *inf = doc.NewElement("inf");
    // inf->SetText(oss.str().c_str());
    // item->InsertEndChild(inf);

    // parent->InsertEndChild(item);

    tinyxml2::XMLElement *item = doc.NewElement("Item");

    // 设置 saddr 属性
    item->SetAttribute("saddr", param.saddr.c_str());

    // 设置desc属性
    item->SetAttribute("desc", param.desc.c_str());
    // 设置inf属性
    std::ostringstream oss;
    oss << "0x" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << param.inf;
    item->SetAttribute("inf_hex", oss.str().c_str());

    item->SetAttribute("inf", (int)param.inf);

    // 设置type_str属性
    item->SetAttribute("type_str", param.type_str.c_str());

    // type_id属性
    item->SetAttribute("type_id", (int)param.type);

    // 设置default_value属性
    item->SetAttribute("default_value", param.default_value.c_str());


    parent->InsertEndChild(item);

}

int output_ftu_cfg(const std::string &out_put_path)
{
    stru_ftu_cfg *p_cfg = get_ftu_cfg_ptr();
    if (NULL == p_cfg)
    {
        LOG_E("get_ftu_cfg_ptr return NULL");
        return -1;
    }

    tinyxml2::XMLDocument doc;

    tinyxml2::XMLDeclaration *decl = doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");
    doc.InsertFirstChild(decl);

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

    // ST (遥信) 信息
    {
        tinyxml2::XMLElement *st_section = doc.NewElement("St");
        st_section->SetAttribute("count", (int)p_cfg->st_info_vec.size());
        for (const auto &info : p_cfg->st_info_vec)
        {
            add_info_element(doc, st_section, info);
        }
        root->InsertEndChild(st_section);
    }

    // MX (遥测) 信息
    {
        tinyxml2::XMLElement *mx_section = doc.NewElement("Mx");
        mx_section->SetAttribute("count", (int)p_cfg->mx_info_vec.size());
        for (const auto &info : p_cfg->mx_info_vec)
        {
            add_info_element(doc, mx_section, info);
        }
        root->InsertEndChild(mx_section);
    }

    // CO (遥控) 信息
    {
        tinyxml2::XMLElement *co_section = doc.NewElement("Co");
        co_section->SetAttribute("count", (int)p_cfg->co_info_vec.size());
        for (const auto &info : p_cfg->co_info_vec)
        {
            add_info_element(doc, co_section, info);
        }
        root->InsertEndChild(co_section);
    }

    // DD (定值) 信息
    {
        tinyxml2::XMLElement *dd_section = doc.NewElement("Dd");
        dd_section->SetAttribute("count", (int)p_cfg->dd_info_vec.size());
        for (const auto &info : p_cfg->dd_info_vec)
        {
            add_info_element(doc, dd_section, info);
        }
        root->InsertEndChild(dd_section);
    }

    // 参数配置
    {
        tinyxml2::XMLElement *param_section = doc.NewElement("Param");

        // count属性
        param_section->SetAttribute("count", (int)p_cfg->param_cfg.vec_param.size());

        // MD5作为属性
        std::ostringstream md5_oss;
        for (int i = 0; i < 16; i++)
        {
            md5_oss << std::hex << std::setw(2) << std::setfill('0') << (int)p_cfg->param_cfg.md5[i];
        }
        param_section->SetAttribute("md5", md5_oss.str().c_str());


        // 展平列表（按inf顺序）
        for (const auto &param : p_cfg->param_cfg.vec_param)
        {
            add_param_element(doc, param_section, param);
        }
        param_section->InsertEndChild(param_section);

        root->InsertEndChild(param_section);
    }

    std::string output_file = out_put_path + "self_ptl.xml";
    tinyxml2::XMLError err = doc.SaveFile(output_file.c_str());
    if (err != tinyxml2::XML_SUCCESS)
    {
        LOG_E("save xml file failed, error: %d", err);
        return -1;
    }

    LOG_I("output xml file: %s", output_file.c_str());

    return 0;
}
