#include "wave_feature_set.hpp"
#include <fstream>
#include "common/common_func.hpp"
#include <zlog.h>

extern zlog_category_t *zct;
extern zlog_category_t *zbt;

WaveFeatureSetting::WaveFeatureSetting() {
    std::ifstream feature_filter_file(FEATURE_FILTER_CFG);
    if (!feature_filter_file.good()) {
        zlog_info(zbt, "[WaveFeatureSetting] no file %s", FEATURE_FILTER_CFG);
        global_feature_.short_addr = 0;
        global_feature_.x = 1;
        global_feature_.y = 1;
        global_feature_.z = 1;   
    } else {
        Json::Reader reader;
        Json::Value root;
        if (!reader.parse(feature_filter_file, root, false)) {
            zlog_error(zbt, "[WaveFeatureSetting] invalid format, fail to parse %s", FEATURE_FILTER_CFG);
            feature_filter_file.close();  
            global_feature_.short_addr = 0;
            global_feature_.x = 1;
            global_feature_.y = 1;
            global_feature_.z = 1;          
        } else {
            uint16_t short_addr;
            char *end_ptr;
            for (const auto &key : root.getMemberNames()) {
                if (key == "global") {
                    Json::Value v = root[key];
                    global_feature_.short_addr = 0;
                    for (size_t i = 0; i < v.size(); ++i) {
                        if (i == 0) {
                            global_feature_.x = v.get(i, 0).asInt();
                        } else if (i == 1) {
                            global_feature_.y = v.get(i, 0).asInt();
                        } else if (i == 2) {
                            global_feature_.z = v.get(i, 0).asInt();
                        }                        
                    }
                } else {
                    short_addr = strtol(key.c_str(), &end_ptr, 16);
                    Json::Value v = root[key];
                    FeatureEntryPrivateCfg item;
                    for (size_t i = 0; i < v.size(); ++i) {
                        if (i == 0) {
                            item.x = v.get(i, 0).asInt();
                        } else if (i == 1) {
                            item.y = v.get(i, 0).asInt();
                        } else if (i == 2) {
                            item.z = v.get(i, 0).asInt();
                        }                           
                    }                   
                    eigen_map_[short_addr] = item;
                }
            }
        }
    }

    std::ifstream wave_filter_file(WAVE_FILTER_CFG);
    if (!wave_filter_file.good()) {
        zlog_info(zbt, "[WaveFeatureSetting] no file %s", WAVE_FILTER_CFG);
        global_wave_.short_addr = 0;
        global_wave_.x = 1;
        global_wave_.y = 1;
        global_wave_.z = 1;   
    } else {
        Json::Reader reader;
        Json::Value root;
        if (!reader.parse(wave_filter_file, root, false)) {
            zlog_error(zbt, "[WaveFeatureSetting] invalid format, fail to parse %s", WAVE_FILTER_CFG);
            wave_filter_file.close();  
            global_wave_.short_addr = 0;
            global_wave_.x = 1;
            global_wave_.y = 1;
            global_wave_.z = 1;          
        } else {
            uint16_t short_addr;
            char *end_ptr;
            for (const auto &key : root.getMemberNames()) {
                if (key == "global") {
                    Json::Value v = root[key];
                    global_wave_.short_addr = 0;
                    for (size_t i = 0; i < v.size(); ++i) {
                        if (i == 0) {
                            global_wave_.x = v.get(i, 0).asInt();
                        } else if (i == 1) {
                            global_wave_.y = v.get(i, 0).asInt();
                        } else if (i == 2) {
                            global_wave_.z = v.get(i, 0).asInt();
                        }                     
                    }                    
                } else {
                    short_addr = strtol(key.c_str(), &end_ptr, 16);
                    Json::Value v = root[key];
                    FeatureEntryPrivateCfg item;
                    for (size_t i = 0; i < v.size(); ++i) {
                        if (i == 0) {
                            item.x = v.get(i, 0).asInt();
                        } else if (i == 1) {
                            item.y = v.get(i, 0).asInt();
                        } else if (i == 2) {
                            item.z = v.get(i, 0).asInt();
                        }                            
                    }  
                    
                    wave_map_[short_addr] = item;
                }
            }
        }
    }
}

int WaveFeatureSetting::GetFeatureCfg(uint16_t short_addr, uint8_t &x, uint8_t &y, uint8_t &z) {
    if (short_addr == 0) {
        x = global_feature_.x;
        y = global_feature_.y;
        z = global_feature_.z;
        return 0;
    }
    auto iter = eigen_map_.find(short_addr);
    if (iter == eigen_map_.end()) {
        x = global_feature_.x;
        y = global_feature_.y;
        z = global_feature_.z;
        return 0;
    }

    x = iter->second.x;
    y = iter->second.y;
    z = iter->second.z;
    return 0; 
}

void WaveFeatureSetting::SetFeatureCfg(uint16_t short_addr, uint8_t x, uint8_t y, uint8_t z) {
    bool need_submit = false;
    if (short_addr == 0) {
        if (global_feature_.x == x && global_feature_.y == y && global_feature_.z == z) {
            return;
        }
        need_submit = true;
        global_feature_.x = x;
        global_feature_.y = y;
        global_feature_.z = z;        
    } else {
        auto iter = eigen_map_.find(short_addr);
        if (iter == eigen_map_.end()) {
            FeatureEntryPrivateCfg cfg;
            cfg.x = x;
            cfg.y = y;
            cfg.z = z;
            eigen_map_[short_addr] = cfg;
            need_submit = true;
        } else {
            if (iter->second.x == x && iter->second.y == y && iter->second.z == z) {
                return;
            }
            
            iter->second.x = x;
            iter->second.y = y;
            iter->second.z = z;            
            need_submit = true;
        }
    }

    if (need_submit) {
        WriteFeatureCfgFile();
    }
}

void WaveFeatureSetting::SetAllFeatureCfg(std::vector<FeatureEntryUploadCfg> cfg) {
    eigen_map_.clear();
    for (auto item : cfg) {
        if (item.short_addr == 0) {
            global_feature_.short_addr = 0;
            global_feature_.x = item.x;
            global_feature_.y = item.y;
            global_feature_.z = item.z;
        } else {
            FeatureEntryPrivateCfg entry;
            entry.x = item.x;
            entry.y = item.y;
            entry.z = item.z;
            eigen_map_[item.short_addr] = entry;
        }
    }
    WriteFeatureCfgFile();
}

int WaveFeatureSetting::GetAllFeatureCfg(std::vector<FeatureEntryUploadCfg> &cfg) {
    cfg.clear();
    cfg.push_back(global_feature_); 
    for (auto item : eigen_map_) {
        FeatureEntryUploadCfg current;
        current.short_addr = item.first;
        current.x = item.second.x;
        current.y = item.second.y;
        current.z = item.second.z;
        cfg.push_back(current);
    }
    return 0; 
}

void WaveFeatureSetting::RemoveFeatureCfg(uint16_t short_addr) {
    auto iter = eigen_map_.find(short_addr);
    if (iter == eigen_map_.end()) {
        return;
    }
    eigen_map_.erase(short_addr);
    WriteFeatureCfgFile();
}

void WaveFeatureSetting::RemoveAllFeatureCfg() {
    std::string clear_cmd = "rm -rf ";
    clear_cmd.append(FEATURE_FILTER_CFG);
    system(clear_cmd.c_str());
}

void WaveFeatureSetting::WriteFeatureCfgFile() {
    Json::Value root;
    Json::Value global_arr;
    global_arr.append(global_feature_.x);
    global_arr.append(global_feature_.y);
    global_arr.append(global_feature_.z);
    root["global"] = global_arr;

    char buf[8] = {0};
    for (auto item : eigen_map_) {
        memset(buf, 0, 8);
        snprintf(buf, 8, "%02x%02x", UINT16_HIGH(item.first), UINT16_LOW(item.first));
        Json::Value arr;
        arr.append(item.second.x);
        arr.append(item.second.y);
        arr.append(item.second.z);
        root[buf] = arr;
    }
    Json::StyledStreamWriter streamWriter;
    std::ofstream out_file(FEATURE_FILTER_CFG);
    streamWriter.write(out_file, root);
}

void WaveFeatureSetting::WriteWaveCfgFile() {
    Json::Value root;
    Json::Value global_arr;
    global_arr.append(global_wave_.x);
    global_arr.append(global_wave_.y);
    global_arr.append(global_wave_.z);
    root["global"] = global_arr;

    char buf[8] = {0};
    for (auto item : wave_map_) {
        memset(buf, 0, 8);
        snprintf(buf, 8, "%02x%02x", UINT16_HIGH(item.first), UINT16_LOW(item.first));
        Json::Value arr;
        arr.append(item.second.x);
        arr.append(item.second.y);
        arr.append(item.second.z);
        root[buf] = arr;
    }
    Json::StyledStreamWriter streamWriter;
    std::ofstream out_file(WAVE_FILTER_CFG);
    streamWriter.write(out_file, root);
}

int WaveFeatureSetting::GetWaveCfg(uint16_t short_addr, uint8_t &x, uint8_t &y, uint8_t &z) { 
    if (short_addr == 0) {
        x = global_wave_.x;
        y = global_wave_.y;
        z = global_wave_.z;
        return 0;
    }
    auto iter = wave_map_.find(short_addr);
    if (iter == wave_map_.end()) {
        x = global_wave_.x;
        y = global_wave_.y;
        z = global_wave_.z;
        return 0;
    }

    x = iter->second.x;
    y = iter->second.y;
    z = iter->second.z;
    return 0;
}

void WaveFeatureSetting::SetWaveCfg(uint16_t short_addr, uint8_t x, uint8_t y, uint8_t z) {
    bool need_submit = false;
    if (short_addr == 0) {
        if (global_wave_.x == x && global_wave_.y == y && global_wave_.z == z) {
            return;
        }
        need_submit = true;
        global_wave_.x = x;
        global_wave_.y = y;
        global_wave_.z = z;        
    } else {
        auto iter = wave_map_.find(short_addr);
        if (iter == wave_map_.end()) {
            FeatureEntryPrivateCfg cfg;
            cfg.x = x;
            cfg.y = y;
            cfg.z = z;
            wave_map_[short_addr] = cfg;
            need_submit = true;
        } else {
            if (iter->second.x == x && iter->second.y == y && iter->second.z == z) {
                return;
            }
            
            iter->second.x = x;
            iter->second.y = y;
            iter->second.z = z;            
            need_submit = true;
        }
    }

    if (need_submit) {
        WriteWaveCfgFile();
    }
}

void WaveFeatureSetting::SetAllWaveCfg(std::vector<FeatureEntryUploadCfg> cfg) {
    eigen_map_.clear();
    for (auto item : cfg) {
        if (item.short_addr == 0) {
            global_wave_.short_addr = 0;
            global_wave_.x = item.x;
            global_wave_.y = item.y;
            global_wave_.z = item.z;
        } else {
            FeatureEntryPrivateCfg entry;
            entry.x = item.x;
            entry.y = item.y;
            entry.z = item.z;
            wave_map_[item.short_addr] = entry;
        }
    }
    WriteWaveCfgFile();
}

int WaveFeatureSetting::GetAllWaveCfg(std::vector<FeatureEntryUploadCfg> &cfg) { 
    cfg.clear();
    cfg.push_back(global_wave_); 
    for (auto item : wave_map_) {
        FeatureEntryUploadCfg current;
        current.short_addr = item.first;
        current.x = item.second.x;
        current.y = item.second.y;
        current.z = item.second.z;
        cfg.push_back(current);
    }
    return 0; 
}

void WaveFeatureSetting::RemoveWaveCfg(uint16_t short_addr) {
    auto iter = wave_map_.find(short_addr);
    if (iter == wave_map_.end()) {
        return;
    }
    wave_map_.erase(short_addr);
    WriteWaveCfgFile();
}

void WaveFeatureSetting::RemoveAllWaveCfg() {
    std::string clear_cmd = "rm -rf ";
    clear_cmd.append(WAVE_FILTER_CFG);
    system(clear_cmd.c_str());
}
