#include "parse_cfg.h"
#include "myMd5.h"
#include "myFunc.h"

#include <iostream>

#include <fstream>


LOCAL int parse_fixed_param_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_param_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_param_txt(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_st_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_mx_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_co_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_dd_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_param_fixed_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_param_run_csv(const char *file_name, stru_app_cfg &app_cfg);
LOCAL int parse_iec_param_act_csv(const char *file_name, stru_app_cfg &app_cfg);

LOCAL void show_param_cfg(stru_param_cfg &param_cfg);
LOCAL stru_param_cfg *parse_param_cfg(std::string cfg_file, std::map<std::string, std::string> &signal_name_map);


LOCAL void csv_data_show(stru_csv_data *p_data);
LOCAL stru_csv_data *csv_parse(const std::string csv_file);


LOCAL stru_app_cfg g_app_cfg = {0};

stru_app_cfg *get_app_cfg_ptr(void)
{
    return &g_app_cfg;    
}

LOCAL std::string g_cfg_path = "/mnt/RTU/test/file/SYSCONFIG/";

LOCAL struct
{
    const char *file_name;
    int (*func_parse)(const char *file_name, stru_app_cfg &app_cfg);
}g_cfg_list[] = 
{
    {"fixed_param_cfg.csv", parse_fixed_param_csv},
    {"ParamMapping.csv",    parse_param_csv},
    {"st.csv",              parse_iec_st_csv},
    {"mx.csv",              parse_iec_mx_csv},
    {"co.csv",              parse_iec_co_csv},
    {"dd.csv",              parse_iec_dd_csv},
    {"fixed_param.csv",     parse_iec_param_fixed_csv},

    {"act_param.csv",       parse_iec_param_act_csv},
    {"run_param.csv",       parse_iec_param_run_csv},
    {"PARAMCONFIG.txt",     parse_param_txt},
};
LOCAL int g_cfg_list_size = sizeof(g_cfg_list) / sizeof(g_cfg_list[0]);

typedef struct
{
    uint8_t type_len;
    uint8_t type_id;
}stru_type_info;

LOCAL std::map<std::string, stru_type_info> g_type_map = 
{
    {"s8",      {1,  DATA_TYPE_S8}},
    {"u8",      {1,  DATA_TYPE_U8}},
    {"s16",     {2,  DATA_TYPE_S16}},
    {"u16",     {2,  DATA_TYPE_U16}},
    {"s32",     {4,  DATA_TYPE_S32}},
    {"u32",     {4,  DATA_TYPE_U32}},
    {"f32",     {4,  DATA_TYPE_F32}},
    {"ip",      {4,  DATA_TYPE_IP}},
    {"mac",     {8,  DATA_TYPE_MAC}},
    {"c8",      {8,  DATA_TYPE_C8}},
    {"c32",     {32, DATA_TYPE_C32}},
    {"c64",     {64, DATA_TYPE_C64}},
    {"c1",      {1,  DATA_TYPE_C1}},
};



LOCAL void param_set_signal_name_map(stru_csv_data &csv_data, std::map<std::string, std::string> &signal_name_map)
{
    for(size_t i = 1; i < csv_data.row_vec.size(); i++)
    {
        stru_csv_row &row = csv_data.row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }
        std::string signal = row.field_vec[1];
        std::string name = row.field_vec[3];
        signal_name_map[signal] = name; 
    }
}

LOCAL void hex_str_to_int(std::string &hex_str, uint16_t &data)
{
    char *endptr;
    data = strtoul(hex_str.c_str(), &endptr, 16);
}

LOCAL int parse_param_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_param_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    param_set_signal_name_map(*app_cfg.p_param_csv, app_cfg.param_signal_name_map);

    return 0;
}


LOCAL int parse_param_txt(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_param_cfg = parse_param_cfg(path, app_cfg.param_signal_name_map)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // show_param_cfg(*app_cfg.p_param_cfg);
    return 0;
}


LOCAL int parse_fixed_param_csv(const char *file_name, stru_app_cfg &app_cfg)   
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_fixed_param_cfg_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_fixed_param_cfg_csv);

    return 0;
}


LOCAL int parse_iec_st_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_st_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_st_csv);
    for(size_t i = 1; i < app_cfg.p_iec_st_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_st_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;   
        }

        stru_iec_st_info st_info;
        st_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], st_info.inf);

        app_cfg.st_info_vec.push_back(st_info);
    }

    return 0;
}

LOCAL int parse_iec_mx_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_mx_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_mx_csv);

    for(size_t i = 1; i < app_cfg.p_iec_mx_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_mx_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }

        stru_iec_mx_info mx_info;
        mx_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], mx_info.inf);

        app_cfg.mx_info_vec.push_back(mx_info);
    }

    return 0;   
}

LOCAL int parse_iec_co_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_co_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_co_csv);

    for(size_t i = 1; i < app_cfg.p_iec_co_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_co_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }

        stru_iec_co_info co_info;
        co_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], co_info.inf);

        app_cfg.co_info_vec.push_back(co_info);
    }

    return 0;
}

LOCAL int parse_iec_dd_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_dd_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_dd_csv);

    for(size_t i = 1; i < app_cfg.p_iec_dd_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_dd_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }

        stru_iec_dd_info dd_info;
        dd_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], dd_info.inf);

        app_cfg.dd_info_vec.push_back(dd_info);
    }

    return 0;
}

LOCAL int parse_iec_param_fixed_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_param_fixed_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_param_fixed_csv);

    for(size_t i = 1; i < app_cfg.p_iec_param_fixed_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_param_fixed_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }

        stru_iec_param_info param_info;
        param_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], param_info.inf);

        app_cfg.param_info_vec.push_back(param_info);
    }

    return 0;
}

LOCAL int parse_iec_param_run_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_param_run_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_param_run_csv);

    for(size_t i = 1; i < app_cfg.p_iec_param_run_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_param_run_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }

        stru_iec_param_info param_info;
        param_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], param_info.inf);

        app_cfg.param_info_vec.push_back(param_info);
    }

    return 0;
}

LOCAL int parse_iec_param_act_csv(const char *file_name, stru_app_cfg &app_cfg)
{
    std::string path = g_cfg_path + file_name;

    if(NULL == (app_cfg.p_iec_param_act_csv = csv_parse(path)))
    {
        MY_LOG_E("parse %s failed", path.c_str());
        return -1;
    }

    // csv_data_show(app_cfg.p_iec_param_act_csv);

    for(size_t i = 1; i < app_cfg.p_iec_param_act_csv->row_vec.size(); i++)
    {
        stru_csv_row &row = app_cfg.p_iec_param_act_csv->row_vec[i];
        if(row.field_vec.size() < 2)
        {
            continue;
        }

        stru_iec_param_info param_info;
        param_info.desc = row.field_vec[0];
        hex_str_to_int(row.field_vec[1], param_info.inf);

        app_cfg.param_info_vec.push_back(param_info);
    }

    return 0;
}


int parse_cfg_files(void)
{
    for(int i = 0; i < g_cfg_list_size; i++)
    {
        if(NULL == g_cfg_list[i].file_name || NULL == g_cfg_list[i].func_parse)
        {
            continue;
        }

        if(0 != g_cfg_list[i].func_parse(g_cfg_list[i].file_name, g_app_cfg))
        {
            MY_LOG_E("parse %s failed", g_cfg_list[i].file_name);
            return -1;
        }
    }
    

    return 0;
}






LOCAL void parse_param_cfg_info(std::string temp, stru_param_cfg &param_cfg, std::map<std::string, std::string> &signal_name_map)
{
    if(temp.empty())
    {
        return;
    }

    std::string name = "";
    std::string signal = "";
    std::string type = "";

    size_t pos = temp.find(":");
    if(pos != std::string::npos)
    {
        signal = temp.substr(0, pos);
        type = temp.substr(pos+1);
    }
    
    if(g_type_map.find(type) == g_type_map.end())
    {
        MY_LOG_E("type %s is not supported, signal %s", type.c_str(), signal.c_str());
        return;
    }

    stru_type_info type_info = g_type_map[type];
    

    std::vector<stru_param_cfg_data> *param_vec = &param_cfg.map_type_param[type_info.type_len];

    if(signal_name_map.find(signal) != signal_name_map.end())
    {
        name = signal_name_map[signal];
    }
    param_vec->push_back({name, signal, type, type_info.type_id});

    if(type_info.type_id == DATA_TYPE_B || type_info.type_id == DATA_TYPE_U8)
    {
        uint8_t *p_u8 = (uint8_t*)malloc(sizeof(uint8_t));
        if(NULL == p_u8)
        {
            MY_LOG_E("DATA_TYPE_B malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_u8;
    }
    else if(type_info.type_id == DATA_TYPE_C1)
    {
        char *p_c1 = (char*)malloc(sizeof(char));
        if(NULL == p_c1)
        {
            MY_LOG_E("DATA_TYPE_C1 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_c1;
    }
    else if(type_info.type_id == DATA_TYPE_S8)
    {
        int8_t *p_s8 = (int8_t*)malloc(sizeof(int8_t));
        if(NULL == p_s8)
        {
            MY_LOG_E("DATA_TYPE_S8 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_s8;
    }
    else if(type_info.type_id == DATA_TYPE_S16)
    {
        int16_t *p_s16 = (int16_t*)malloc(sizeof(int16_t));
        if(NULL == p_s16)
        {
            MY_LOG_E("DATA_TYPE_S16 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_s16;
    }
    else if(type_info.type_id == DATA_TYPE_U16)
    {
        uint16_t *p_u16 = (uint16_t*)malloc(sizeof(uint16_t));
        if(NULL == p_u16)
        {
            MY_LOG_E("DATA_TYPE_U16 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_u16;
    }
    else if(type_info.type_id == DATA_TYPE_S32)
    {
        int32_t *p_s32 = (int32_t*)malloc(sizeof(int32_t));
        if(NULL == p_s32)
        {
            MY_LOG_E("DATA_TYPE_S32 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_s32;
    }
    else if(type_info.type_id == DATA_TYPE_U32)
    {
        uint32_t *p_u32 = (uint32_t*)malloc(sizeof(uint32_t));
        if(NULL == p_u32)
        {
            MY_LOG_E("DATA_TYPE_U32 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_u32;
    }
    else if(type_info.type_id == DATA_TYPE_L64)
    {
        int64_t *p_l64 = (int64_t*)malloc(sizeof(int64_t));
        if(NULL == p_l64)
        {
            MY_LOG_E("DATA_TYPE_L64 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_l64;
    }
    else if(type_info.type_id == DATA_TYPE_UL64)
    {
        uint64_t *p_ul64 = (uint64_t*)malloc(sizeof(uint64_t));
        if(NULL == p_ul64)
        {
            MY_LOG_E("DATA_TYPE_UL64 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_ul64;
    }
    else if(type_info.type_id == DATA_TYPE_F32)
    {
        float *p_f32 = (float*)malloc(sizeof(float));
        if(NULL == p_f32)
        {
            MY_LOG_E("DATA_TYPE_F32 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_f32;
    }
    else if(type_info.type_id == DATA_TYPE_D64)
    {
        double *p_f64 = (double*)malloc(sizeof(double));
        if(NULL == p_f64)
        {
            MY_LOG_E("DATA_TYPE_D64 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_f64;
    }
    else if(type_info.type_id == DATA_TYPE_IP)
    {
        char *p_ip = (char*)malloc(sizeof(char)*4);
        if(NULL == p_ip)
        {
            MY_LOG_E("DATA_TYPE_IP malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_ip;
    }
    else if(type_info.type_id == DATA_TYPE_MAC)
    {
        char *p_mac = (char*)malloc(sizeof(char)*8);
        if(NULL == p_mac)
        {
            MY_LOG_E("DATA_TYPE_MAC malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_mac;
    }
    else if(type_info.type_id == DATA_TYPE_C8)
    {
        char *p_c8 = (char*)malloc(sizeof(char)*8);
        if(NULL == p_c8)
        {
            MY_LOG_E("DATA_TYPE_C8 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_c8;
    }
    else if(type_info.type_id == DATA_TYPE_C32)
    {
        char *p_c32 = (char*)malloc(sizeof(char)*32);
        if(NULL == p_c32)
        {
            MY_LOG_E("DATA_TYPE_C32 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_c32;
    }
    else if(type_info.type_id == DATA_TYPE_C64)
    {
        char *p_c64 = (char*)malloc(sizeof(char)*64);
        if(NULL == p_c64)
        {
            MY_LOG_E("DATA_TYPE_C64 malloc failed");
            return;
        }
        param_vec->back().p_data = (void *)p_c64;
    }
}

LOCAL stru_param_cfg *parse_param_cfg_buf(uint8_t *p_buf, uint32_t buf_size, std::map<std::string, std::string> &signal_name_map)
{
    if(NULL == p_buf || 0 == buf_size)
    {
        MY_LOG_E("p_buf is NULL or buf_size is 0");
        return NULL;
    }

    stru_param_cfg *param_cfg = new stru_param_cfg;
    if(NULL == param_cfg)
    {
        MY_LOG_E("malloc failed");
        return NULL;
    }

    MD5_CTX md5_ctx;
    StartMD5(&md5_ctx);
    EncodeMD5(&md5_ctx, p_buf, buf_size);
    GetMD5(&md5_ctx, param_cfg->md5);


    uint8_t temp[64] = {0};
    uint8_t temp_len = 0;
    uint32_t pos = 0;
    for(uint32_t i = 0; i < buf_size; i++)
    {
        if(p_buf[i] != ',' && p_buf[i] != '\n' && p_buf[i] != '\r')
        {
            temp[temp_len++] = p_buf[i];
        }
        else
        {
            temp[temp_len] = '\0';
            parse_param_cfg_info((char*)temp, *param_cfg, signal_name_map);
            temp_len = 0;
        }

        if(i == buf_size-1)
        {
            temp[temp_len] = '\0';
            parse_param_cfg_info((char*)temp, *param_cfg, signal_name_map);
            temp_len = 0;
        }
    }

    for(std::map<uint8_t, std::vector<stru_param_cfg_data>>::iterator it = param_cfg->map_type_param.begin(); it != param_cfg->map_type_param.end(); it++)
    {
        std::vector<stru_param_cfg_data> *param_vec = &it->second;
        uint16_t inf = 0;
        for(std::vector<stru_param_cfg_data>::iterator it2 = param_vec->begin(); it2 != param_vec->end(); it2++)
        {
            it2->inf = inf;
            param_cfg->vec_param.push_back(*it2);
            inf ++;
        }
    }

    return param_cfg;
}


LOCAL stru_param_cfg *do_parse_param_cfg(std::string cfg_file, std::map<std::string, std::string> &signal_name_map)
{
    uint32_t file_size = func_get_file_size(cfg_file.c_str());
    if(0 == file_size)
    {
        MY_LOG_E("cfg_file %s is empty", cfg_file.c_str());
        return NULL;
    }

    uint8_t *p_buf = (uint8_t*)malloc(file_size+1);
    if(NULL == p_buf)
    {
        MY_LOG_E("malloc failed");
        return NULL;
    }

    uint32_t read_size = 0;
    if(0 != func_read_file_to_buf(cfg_file.c_str(), (char*)p_buf, file_size, &read_size))
    {
        MY_LOG_E("read cfg_file %s failed", cfg_file.c_str());
        free(p_buf);
        return NULL;
    }

    if(file_size != read_size)
    {
        MY_LOG_E("read cfg_file %s failed, read_size %d, file_size %d", cfg_file.c_str(), read_size, file_size);
        free(p_buf);
        return NULL;
    }

    p_buf[file_size] = '\0';
    
    return parse_param_cfg_buf(p_buf, file_size, signal_name_map);
}

LOCAL void show_param_cfg(stru_param_cfg &param_cfg)
{
    MY_LOG_I("md5:");
    for(int i = 0; i < 16; i++)
    {
        printf("%02x ", param_cfg.md5[i]);
    }
    printf("\n");

    // for(std::vector<stru_param_cfg_data>::iterator it = param_cfg.vec_param.begin(); it != param_cfg.vec_param.end(); it++)
    // {
    //     MY_LOG_I("name %s, desc %s, type %s, type_id %d, inf %d", it->name.c_str(), it->desc.c_str(), it->type_str.c_str(), it->type, it->inf);
    // }

}

LOCAL stru_param_cfg *parse_param_cfg(std::string cfg_file, std::map<std::string, std::string> &signal_name_map)
{
    if(0 != func_file_exist(cfg_file.c_str()))
    {
        MY_LOG_E("cfg_file %s does not exist", cfg_file.c_str());
        return NULL;
    }

    stru_param_cfg *param_cfg = do_parse_param_cfg(cfg_file, signal_name_map);
    if(NULL == param_cfg)
    {
        MY_LOG_E("parse cfg_file %s failed", cfg_file.c_str());
        return NULL;
    }

    show_param_cfg(*param_cfg);

    return param_cfg;
}





LOCAL std::string trim(const std::string& str) {
    size_t start = str.find_first_not_of(" \t\r\n");
    if (start == std::string::npos) 
        return "";
    size_t end = str.find_last_not_of(" \t\r\n");
    std::string result = str.substr(start, end - start + 1);
    
    // 去除首尾的引号
    if (result.size() >= 2 && result.front() == '"' && result.back() == '"') 
    {
        result = result.substr(1, result.size() - 2);
    }
    
    return result;
}

LOCAL void parse_line(const std::string line, char delimiter, stru_csv_row &row)
{
    std::string field;
    int in_qutoes = 0;

    for(size_t i = 0; i < line.length(); i++)
    {
        char c = line[i];

        if(in_qutoes)
        {
            if(c == '"')
            {
                if(i + 1 < line.length() && line[i+1] == '"')
                {
                    field += c;
                    i++;
                }
                else
                {
                    in_qutoes = 0;
                }
            }
            else
            {
                field += c;
            }
        }
        else
        {
            if(c == delimiter)
            {
                row.field_vec.push_back(trim(field));
                field.clear();
            }
            else if(c == '"')
            {
                in_qutoes = 1;
            }
            else
            {
                field += c;
            }
        }
    }

    row.field_vec.push_back(trim(field));
}

LOCAL stru_csv_data *csv_parse(const std::string csv_file)
{
    std::ifstream fp(csv_file);
    if(!fp.is_open())
    {
        MY_LOG_E("csv_parse: file %s open failed", csv_file.c_str());
        return NULL;
    }

    stru_csv_data *csv_data = new stru_csv_data;
    csv_data->capacity = 0;

    std::string line;
    std::string buffer;
    int line_num = 0;

    while (std::getline(fp, line))
    {
        line_num++;

        if(!line.empty() && line.back() == '\r')
        {
            line.pop_back();
        }

        if(!buffer.empty())
        {
            buffer += "\n" + line;
            line = buffer;
            buffer.clear();
        }
        
        bool in_qutoes = false;
        for(char c : line)
        {
            if(c == '"')
            {
                in_qutoes = !in_qutoes;
            }
        }

        if(in_qutoes)
        {
            buffer = line;
            continue;
        }

        stru_csv_row row;
        parse_line(line, ',', row);

        if(!csv_data->row_vec.empty() && row.field_vec.size() == 1 && csv_data->row_vec.back().field_vec.size()>1)
        {
            if(!csv_data->row_vec.empty())
            {
                csv_data->row_vec.back().field_vec.back() += " " + row.field_vec[0];
            }
            continue;
        }

        csv_data->row_vec.push_back(row);
    }
    
    if(!buffer.empty())
    {
        stru_csv_row row;
        parse_line(buffer, ',', row);
        csv_data->row_vec.push_back(row);
    }

    fp.close();

    return csv_data;
}

LOCAL void csv_data_show(stru_csv_data *p_data)
{
    std::vector<stru_csv_row> &data = p_data->row_vec;
    if (data.empty()) 
    {
        std::cout << "No data" << std::endl;
        return;
    }
    
    // 打印列标题
    std::cout << "Total rows: " << data.size() << std::endl;
    std::cout << "Total columns: " << data[0].field_vec.size() << std::endl << std::endl;
    
    std::cout << "=== Column Headers ===" << std::endl;
    for (size_t j = 0; j < data[0].field_vec.size(); j++) {
        std::cout << "[" << j << "] " << data[0].field_vec[j] << std::endl;
    }

    // 打印前几行作为预览
    int previewRows = data.size();
    for (int i = 1; i < previewRows; i++) {
        std::cout << "Row " << i << " (" << data[i].field_vec.size() << " fields): ";
        for (size_t j = 0; j < data[i].field_vec.size(); j++) 
        { 
            std::string field = data[i].field_vec[j];

            std::cout << "[" << field << "] ";
        }

        std::cout << std::endl;
    }
}