#pragma once
//stl
#include <iostream>
#include <sstream>
#include <vector>
//boost
#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/xml_parser.hpp>
//robotics
#include <robotics/linq.hpp>
//local
#include "../models/web_user_config_info.h"
#include "../models/web_drop_config_info.h"
#include "../models/web_general_config_info.h"
#include "../models/web_regex_config_info.h"
#include "../models/web_sync_config_info.h"
/**
 * @brief 配置
 */
class xml_context {
public:
    /**
     * @brief 
     * @tparam _Type 
     * @param reset 
     * @return 
     */
    template<typename _Type>
    static v3::linq_ptr<_Type>& from(bool reset = true) {
        if constexpr (std::is_same<web_user_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_user_config_->reset();
            }
            return *instance()->linq_user_config_;
        }
        else if constexpr (std::is_same<web_drop_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_drop_config_->reset();
            }
            return *instance()->linq_drop_config_;
        }
        else if constexpr (std::is_same<web_regex_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_regex_config_->reset();
            }
            return *instance()->linq_regex_config_;
        }
        else if constexpr (std::is_same<web_general_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_general_config_->reset();
            }
            return *instance()->linq_general_config_;
        }
        else if constexpr (std::is_same<web_sync_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_sync_config_->reset();
            }
            return *instance()->linq_sync_config_;
        }
    }
private:
    /**
     * @brief 单例
     * @return
     */
    static xml_context* instance() {
        static xml_context g_xml_context;
        return &g_xml_context;
    }
private:
    /**
     * @brief 构造
     */
    xml_context() {
        load();
        //配置列表交给linq管理
        linq_user_config_.reset(new v3::linq_ptr<web_user_config_info>(user_config_list_));
        //绑定改变事件
        linq_user_config_->changed_bind(&xml_context::on_table_save<web_user_config_info>, this);

        //配置列表交给linq管理
        linq_drop_config_.reset(new v3::linq_ptr<web_drop_config_info>(drop_config_list_));
        //绑定改变事件
        linq_drop_config_->changed_bind(&xml_context::on_table_save<web_drop_config_info>, this);

        //配置列表交给linq管理
        linq_regex_config_.reset(new v3::linq_ptr<web_regex_config_info>(regex_config_list_));
        //绑定改变事件
        linq_regex_config_->changed_bind(&xml_context::on_table_save<web_regex_config_info>, this);

        //配置列表交给linq管理
        linq_general_config_.reset(new v3::linq_ptr<web_general_config_info>(general_config_list_));
        //绑定改变事件
        linq_general_config_->changed_bind(&xml_context::on_table_save<web_general_config_info>, this);

        //配置列表交给linq管理
        linq_sync_config_.reset(new v3::linq_ptr<web_sync_config_info>(sync_config_list_));
        //绑定改变事件
        linq_sync_config_->changed_bind(&xml_context::on_table_save<web_sync_config_info>, this);
    }
    /**
     * @brief 加载xml
     */
    void load() {
        boost::property_tree::ptree root;
        try {
            read_xml("./config/config.xml", root);
            //用户读取
            for (auto& it : root.get_child("root.users")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_user_config_info> item(new web_user_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->name = it.second.get<std::string>("<xmlattr>.name", "管理员");
                item->code = it.second.get<std::string>("<xmlattr>.code", "admin");
                item->password = it.second.get<std::string>("<xmlattr>.password", "123456");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                user_config_list_.push_back(item);
            }
            //落格读取
            for (auto& it : root.get_child("root.drop")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_drop_config_info> item(new web_drop_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->type = it.second.get<int>("<xmlattr>.type", 0);
                item->name = it.second.get<std::string>("<xmlattr>.name", "");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                drop_config_list_.push_back(item);
            }
            //正则读取
            for (auto& it : root.get_child("root.regex")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_regex_config_info> item(new web_regex_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->type = it.second.get<int>("<xmlattr>.type", 1);
                item->name = it.second.get<std::string>("<xmlattr>.name", "");
                item->regex = it.second.get<std::string>("<xmlattr>.regex", "");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                regex_config_list_.push_back(item);
            }
            //通用读取
            for (auto& it : root.get_child("root.general")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_general_config_info> item(new web_general_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->key = it.second.get<int>("<xmlattr>.key", 1);
                item->value = it.second.get<std::string>("<xmlattr>.value", "");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                general_config_list_.push_back(item);
            }
            //同步读取
            for (auto& it : root.get_child("root.sync")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_sync_config_info> item(new web_sync_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->create_time = it.second.get<std::string>("<xmlattr>.create_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->device_id = it.second.get<std::string>("<xmlattr>.device_id", "");
                item->summary_time = it.second.get<std::string>("<xmlattr>.summary_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->running_distance = it.second.get<double>("<xmlattr>.running_distance", 0);
                item->speed = it.second.get<double>("<xmlattr>.speed", 0);
                item->express_type = it.second.get<int>("<xmlattr>.express_type", 0);
                item->lattice_count = it.second.get<int>("<xmlattr>.lattice_count", 0);
                item->supply_count = it.second.get<int>("<xmlattr>.supply_count", 0);
                item->reflux_count = it.second.get<int>("<xmlattr>.reflux_count", 0);
                item->supply_summay = it.second.get<std::string>("<xmlattr>.supply_summay","");
                item->lattice_summay = it.second.get<std::string>("<xmlattr>.lattice_summay", "");
                item->reflux_summay = it.second.get<std::string>("<xmlattr>.reflux_summay", "");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                sync_config_list_.push_back(item);
            }
        }
        catch (std::exception const& ec) {
            LOG_ERROR << "读取xml配置异常" << ec;
        }
    }
    /**
     * @brief 保存xml
     */
    void save() {
        std::lock_guard<std::mutex> lock(mutex_);
        boost::property_tree::ptree root;
        try {
            //保存用户
            auto& user = root.add("root.users", "");
            for (auto& it : user_config_list_) {
                auto& item = user.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.name", it->name);
                item.put("<xmlattr>.code", it->code);
                item.put("<xmlattr>.password", it->password);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            //落格保存
            auto& drop = root.add("root.drop", "");
            for (auto& it : drop_config_list_) {
                auto& item = drop.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.type", it->type);
                item.put("<xmlattr>.name", it->name);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            //正则保存
            auto& regex = root.add("root.regex", "");
            for (auto& it : regex_config_list_) {
                auto& item = regex.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.type", it->type);
                item.put("<xmlattr>.name", it->name);
                item.put("<xmlattr>.regex", it->regex);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            //通用保存
            auto& general = root.add("root.general", "");
            for (auto& it : general_config_list_) {
                auto& item = general.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.key", it->key);
                item.put("<xmlattr>.value", it->value);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            //同步保存
            auto& sync = root.add("root.sync", "");
            for (auto& it : sync_config_list_) {
                auto& item = sync.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.create_time", it->create_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.device_id", it->device_id);
                item.put("<xmlattr>.summary_time", it->summary_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.running_distance", it->running_distance);
                item.put("<xmlattr>.speed", it->speed);
                item.put("<xmlattr>.express_type", it->express_type);
                item.put("<xmlattr>.lattice_count", it->lattice_count);
                item.put("<xmlattr>.supply_count", it->supply_count);
                item.put("<xmlattr>.reflux_count", it->reflux_count);
                item.put("<xmlattr>.supply_summay", it->supply_summay);
                item.put("<xmlattr>.lattice_summay", it->lattice_summay);
                item.put("<xmlattr>.reflux_summay", it->reflux_summay);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            boost::property_tree::xml_writer_settings<std::string> settings(' ', 4);
            write_xml("./config/config.xml", root, std::locale(), settings);
        }
        catch (std::exception const& ec) {
            LOG_ERROR << ec;
        }
    }
private:
    /**
     * @brief 在表格保存操作中，根据条件决定是否执行保存。
     * @tparam _Table 表格数据的类型。
     * @param value 当前表格的值。
     * @param value_tmp 临时表格的值。
     * @param type 更改类型，指示表格发生了什么类型的更改（v3::linq_change_type）。
     * @param end 布尔值，指示是否为保存操作的结束阶段。
     */
    template<typename _Table>
    void on_table_save(_Table const& value, _Table const& value_tmp, v3::linq_change_type type, bool end) {
        if (end) {
            save();
        }
    }
private:
    std::mutex												        mutex_;
    std::vector<std::shared_ptr<web_user_config_info>>	            user_config_list_;
    std::shared_ptr<v3::linq_ptr<web_user_config_info>>	            linq_user_config_;

    std::vector<std::shared_ptr<web_drop_config_info>>	            drop_config_list_;
    std::shared_ptr<v3::linq_ptr<web_drop_config_info>>	            linq_drop_config_;

    std::vector<std::shared_ptr<web_regex_config_info>>	            regex_config_list_;
    std::shared_ptr<v3::linq_ptr<web_regex_config_info>>	        linq_regex_config_;

    std::vector<std::shared_ptr<web_general_config_info>>	        general_config_list_;
    std::shared_ptr<v3::linq_ptr<web_general_config_info>>	        linq_general_config_;

    std::vector<std::shared_ptr<web_sync_config_info>>	            sync_config_list_;
    std::shared_ptr<v3::linq_ptr<web_sync_config_info>>	            linq_sync_config_;
};