/*
 * @Description: 
 * @Version: 1.0
 * @Autor: lishengyin
 * @Date: 2022-03-07 11:52:23
 * @LastEditors: lishengyin
 * @LastEditTime: 2022-07-22 16:56:04
 */
#include "config.hpp"
#include "Shell.h"
#include "BasicConfig.h"
#include <regex>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <cstddef>
#include <string.h>
#include "httplib.h"

static std::mutex m_mutex;

/**
 * @description: 获取智能指针
 * @param {*}
 * @return {*}
 */
std::shared_ptr<config> config::getPtr(){
    static Ptr m_config = nullptr;
    if(m_config == nullptr){
        std::lock_guard<std::mutex> lk(m_mutex);
        m_config = std::shared_ptr<config>(new config);
    } 
    return m_config;
}

/**
 * @description: 更新数据
 * @param {*}
 * @return {*}
 */
bool config::Update(){
    if(m_ini.load(configFile) != 0){
        ErrorL << "No configuration file is found, please check if the configuration file exists!";
        return false;
    }
    int ret = 0;
    this->NettyIP = m_ini.getStringValue("web", "wed_ip", ret);
    this->NettyPort = m_ini.getIntValue("web", "wed_port", ret);
    this->vpnIP = m_ini.getStringValue("vpn", "vpn_ip", ret);

    this->usr = m_ini.getStringValue("monitor", "usr", ret);
    this->pwd = m_ini.getStringValue("monitor", "pwd", ret);
    this->comPort = m_ini.getStringValue("expel", "com_port", ret);

    this->sensitivity = m_ini.getIntValue("Filter", "sensitivity", ret);
    this->interval = m_ini.getIntValue("Filter", "interval", ret);
    this->TimeOut = m_ini.getIntValue("Filter", "TimeOut", ret);

    this->Spug_IP = m_ini.getStringValue("Spug", "Spug_IP", ret);
    this->Spug_Port = m_ini.getIntValue("Spug", "Spug_Port", ret);

    this->mysql_IP  = m_ini.getStringValue("Mysql", "mysql_IP", ret);
    this->mysql_port = m_ini.getIntValue("Mysql", "mysql_port", ret);

    this->SimCode = this->getSimCode();
    this->app = this->getApp();
    
     // 同步数据
    this->getBasicConfig();
    if(config::getPtr()->LowVersion){
        int count = m_ini.getIntValue("Device", "count", ret);
        DeviceIds.clear();
        for(int i = 1; i <= count; i++){
            int deviceId = m_ini.getIntValue("Device", "device_"+ std::to_string(i), ret);
            DeviceIds.push_back(deviceId);
        }
        this->deviceType = m_ini.getIntValue("Device", "DeviceType", ret);
        this->vpnIP = m_ini.getStringValue("vpn","vpn_ip", ret);
    }
    this->HostIPs = this->getHostIP();
    int flag = 0;
    for(auto iter = HostIPs.begin(); iter != HostIPs.end(); iter++){
        string::size_type idx;
        idx = iter->find("10.8.0.");
        if(idx != string::npos){
            this->vpnIP = *iter;
            flag = 1;
        }
    }
    if(this->localIP != "" && !flag) this->vpnIP = localIP;
    return true;
}

/**
 * @description: 获取SIMCODE
 * @param {*}
 * @return {*}
 */
std::string config::getSimCode(){
    ifstream fin;
    fin.open("/etc/gsd/gsdinfo", ios::in);
    if (!fin.is_open()){
		ErrorL << "无法找到这个文件！" << endl;
		return "";
	}
    char buff[1024] = { 0 };
    while (fin >> buff);
	fin.close();
    std::string str = buff;
    return str;
}

/**
 * @description: 获取app
 * @param {*}
 * @return {*}
 */
std::string config::getApp(){
    ifstream fin;
    fin.open("/etc/gsd/gsdApp", ios::in);
    if (!fin.is_open()){
		ErrorL << "无法找到这个文件！" << endl;
		return "";
	}
    char buff[1024] = { 0 };
    while (fin >> buff);
	fin.close();
    std::string str = buff;
    return str;
}

/**
 * @description: 获取基础配置
 * @param {*}
 * @return {*}
 */
bool config::getBasicConfig(){
    static shared_ptr<httplib::Client> httpClient = nullptr;
    if(httpClient == nullptr) httpClient = std::make_shared<httplib::Client>(this->Spug_IP, this->Spug_Port);
    httplib::Params params;
    params.emplace("apiKey", this->apiKey);
    params.emplace("app", this->app + "_app");
    if(this->app != "gsd_dev") params.emplace("env", "gsd_deploy");
    else params.emplace("env", "gsd_dev");
    params.emplace("noPrefix", "1");
    params.emplace("format", "json");
    httplib::Headers headers = {};
    if (auto res = httpClient->Get("/api/apis/config/", params, headers)){
        if (res->status == 200) {
            BasicConfig basicConfig;
            if(basicConfig.JsonToObject(res->body)){
                this->NettyIP = basicConfig.NettyIP;
                this->NettyPort = basicConfig.NettyPort;
                this->usr = basicConfig.usr;
                this->pwd = basicConfig.pwd;
                this->DiskUsageThreshold = basicConfig.DiskUsageThreshold;
                this->HardDiskCleanupTime = basicConfig.HardDiskCleanupTime;
                this->InferDataRetentionTime = basicConfig.InferDataRetentionTime;
                this->interval = basicConfig.interval;
                this->sensitivity = basicConfig.sensitivity;
                this->TimeOut = basicConfig.TimeOut;
                this->mysql_IP = basicConfig.mysql_IP;
                this->mysql_port =  basicConfig.mysql_port;
                this->debug = basicConfig.debug;
                this->getHistoryVideoFlag = basicConfig.getHistoryVideoFlag;
                this->ClearPastRecords = basicConfig.ClearPastRecords;
                this->bboxSize = basicConfig.bboxSize;
                this->ExpelInterval = basicConfig.ExpelInterval;
                this->LowVersion = basicConfig.LowVersion;
                this->ExpelPort = basicConfig.ExpelPort;
                this->InferInterval = basicConfig.InferInterval;
                
                if(basicConfig.com_port != "") this->comPort = basicConfig.com_port;

                // 写入并保存
                int ret;
                ret = m_ini.setValue("web", "wed_ip", this->NettyIP);
                m_ini.setValue("web", "wed_port", std::to_string(this->NettyPort));
                m_ini.setValue("monitor", "usr", this->usr);
                m_ini.setValue("monitor", "pwd", this->pwd);
                m_ini.setValue("expel", "com_port", this->comPort);

                m_ini.setValue("Filter", "sensitivity", std::to_string(this->sensitivity));
                m_ini.setValue("Filter", "interval", std::to_string(this->interval));
                m_ini.setValue("Filter", "TimeOut", std::to_string(this->TimeOut));
                m_ini.setValue("Mysql", "mysql_IP", this->mysql_IP);
                m_ini.setValue("Mysql", "mysql_port", std::to_string(this->mysql_port));
                m_ini.setValue("vpn", "vpn_ip", this->vpnIP);
                m_ini.save();
                return true;
            }else{
                WarnL << "Parsing failure" << endl;
            }
        }else{
            ErrorL << "status:" << res->status << "," << res->body << endl;
        }
        return false;
    }else{
        auto err = res.error();
        ErrorL << "Service unavailable " << err << endl;
        return false;
    }

    return false;
}

/**
 * @description: 获取版本号
 * @return {*}
 */
std::string config::getVersion(){
    std::string version;
    version = std::to_string(GSD_MAJOR_VERSION) + "." + std::to_string(GSD_MINOR_VERSION) + "." + std::to_string(GSD_PATCH_VERSION);
    return version;
}

/**
 * @description: 获取IP列表
 * @return {*}
 */
vector<string> config::getHostIP(){
    std::string shell = "hostname -I | awk '{print NF}'";
    vector<string> results;
    CShell::exeShellCmd(shell, results);
    int num;
    for(auto iter = results.begin(); iter != results.end(); iter++){
        num = atoi(iter->c_str());
    }
    vector<std::string> ips;
    for(int i = 1; i <= num; i++){
        shell = "hostname -I | awk '{print $" + std::to_string(i) + "}'";
        results.clear();
        CShell::exeShellCmd(shell, results);
        ips.push_back(results[0]);
    }
    return ips;
}

void getFiles(const std::string path, std::vector<std::string> &files)
{
  DIR *dir;
  struct dirent *ptr;

  if ((dir = opendir(path.c_str())) == NULL)
  {
    perror("Open dir error...");
    return;
  }

  while ((ptr = readdir(dir)) != NULL)
  {
    if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
      continue;
    } else if (ptr->d_type == 8) {
      files.push_back(ptr->d_name);
    } else if (ptr->d_type == 10) {
      continue;
    } else if (ptr->d_type == 4) {
      //files.push_back(ptr->d_name);
      getFiles(path + ptr->d_name + "/", files);
    }
  }
  closedir(dir);
}

/**
 * @description: 获取历史视频
 * @return {*}
 */
void config::getHistoryVideo(vector<std::string>& result){
    getFiles( "/home/GSD/video/",result);
}





