#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>

#include "ems_smu_common.h"
#include "dy_utils/protocol.h"

static pthread_t thread_sysinfo = 0;
struct sysinfo info;

static void ems_smu_connredis(redisContext **connContext)
{
    while(true)
    {
        *connContext = redisConnect(REDIS_SERVER_IP, REDIS_SERVER_PORT);
        if ((*connContext)->err)
        {
            dbg_syslog(LOG_ERR, "connect redis server failure: %s\n", (*connContext)->errstr);
            redisFree(*connContext);
            usleep(10 * 1000 * 1000); //等待10s让redis server启动
        }
        else
        {
            dbg_syslog(LOG_NOTICE, "connect redis server success");
            break;
        }
    }
}

static void ems_smu_getstainfo(ems_smu_var_t *var)
{
    snprintf(var->lcid, MAX_ID_LEN, "2402260001");
    snprintf(var->lcsta, MAX_STA_LEN, "346.66,568.88");
    var->capacity = 900;
    var->power = 400;
    snprintf(var->loadtime, MAX_LOADTIME_LEN, "2024-02-01");
    snprintf(var->loc, MAX_LOC_LEN, "浙江省杭州市");
    snprintf(var->staname, MAX_STAN_LEN, "网关旧架构测试");
    snprintf(var->vendor, MAX_VEND_LEN, "LNXALL");
    snprintf(var->softver, MAX_SFVER_LEN, "5.375.1736");
    snprintf(var->model, MAX_MODEL_LEN, "IMX6ULL");
}

void open_sysinfo(void) {
  int ret = 0;
  ret = sysinfo(&info);
  if (ret != 0) {
    perror("get sys_info failed\n");
    exit(0);
  }
}

void *get_sysuse(void *data)
{
    ems_smu_var_t *var = (ems_smu_var_t *)data;
    double tmp;
    int tmpi;
    unsigned long long mem_used, mem_total;
    while(1)
    {
        sleep(5);
        open_sysinfo();
        get_disk_usage("/", &tmp, &mem_used, &mem_total);
        snprintf(var->sysuse.diskuse, LONG_STR_LEN, "%lld/%lld", mem_used/1024, mem_total/1024);
        get_mem_usage(&tmp);
        snprintf(var->sysuse.memuse, SHORT_STR_LEN, "%.2f%%", tmp);
        get_cpu_usage(&tmp);
        snprintf(var->sysuse.cpuuse, REG_STR_LEN, "%.2f%%", tmp);
        get_net_usage(&tmpi);
        var->sysuse.inetcnt = tmpi;

        mem_used = 0;
        mem_total = 0;
        if (cmd_call("mountpoint -q /mnt/ssd", 10, NULL, 1)==0)
        {
            get_disk_usage("/mnt/ssd", &tmp, &mem_used, &mem_total);
        }
        snprintf(var->sysuse.extdisk, LONG_STR_LEN, "%lld/%lld", mem_used/1024, mem_total/1024);

        dbg_syslog(LOG_DEBUG, "%s %s %s %s %d", var->sysuse.cpuuse, var->sysuse.diskuse, var->sysuse.extdisk, var->sysuse.memuse, var->sysuse.inetcnt);
        
    }
}

static void ems_smu_loop(ems_smu_var_t *var)
{
    int ret = 0;
    struct pollfd pfd;
    struct timespec tspec;

    while (1)
    {
        pfd.fd = var->status_timer;
        pfd.events = POLLIN;
        pfd.revents = 0;
        if (pfd.fd > 0)
            ret = poll(&pfd, 0x1, 10 * 1000);
        else {
            tspec.tv_sec = 5;
            tspec.tv_nsec = 0;
            nanosleep(&tspec, NULL);
        }
        if (ret < 0)
        {
            int error = errno;
            printf("errno %d\n", error);
            if (error == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            if (var->status_timer > 0 && pfd.revents)
            {
                comm_status_poll(var);
            }
        }
    }
}

static void ems_smu_stacfg_int(ems_smu_var_t *var, char *cfg_file)
{
    char *data = NULL;
    int lens;

    if (cfg_file == NULL)
    {
        dbg_syslog(LOG_ERR, "cfg_file:%s not exist, use defaut MQTT server", cfg_file);
        return;
    }

    data = read_file_data_and_lens(cfg_file, &lens);
    if (data == NULL)
    {
        dbg_syslog(LOG_ERR, "read cfg file %s error, load default", cfg_file);
        return;
    }

    var->staroot = cJSON_Parse(data);
    if (!var->staroot)
    {
        dbg_syslog(LOG_ERR, "parse cfg file %s error, load default", cfg_file);
        return;
    }

    GET_JSON_VALUE_STRING(var->staroot, "id", var->lcid);
    GET_JSON_VALUE_STRING(var->staroot, "station", var->lcsta);
    GET_JSON_VALUE_INT(var->staroot, "capacity", var->capacity);
    GET_JSON_VALUE_INT(var->staroot, "power", var->power);
    GET_JSON_VALUE_STRING(var->staroot, "time", var->loadtime);
    GET_JSON_VALUE_STRING(var->staroot, "local", var->loc);
    GET_JSON_VALUE_STRING(var->staroot, "station_name", var->staname);
    GET_JSON_VALUE_STRING(var->staroot, "vendor", var->vendor);
    GET_JSON_VALUE_STRING(var->staroot, "softVersion", var->softver);
    GET_JSON_VALUE_STRING(var->staroot, "model", var->model);
}

static void ems_smu_tagmap_init(ems_smu_var_t *var)
{
    char emmstag[MAX_TAG_LEN] = {0};
    char emsctrltag[MAX_TAG_LEN] = {0};
    FILE *fp = fopen(EMMSV2_TAGMAP_CONFIG, "r");
    if (fp == NULL)
    {
        dbg_syslog(LOG_ERR, "open tagmap file failed");
        return;
    }

    while (fscanf(fp, "%s %s", emmstag, emsctrltag)!= EOF)
    {
	    tagmap_entry_t* curtag;
        HASH_FIND_STR(var->tagmaps, emmstag, curtag);
        if (NULL == curtag)
        {
            curtag = malloc(sizeof(tagmap_entry_t));
            snprintf(curtag->emmstag, MAX_TAG_LEN, "%s", emmstag);
            snprintf(curtag->emsctrltag, MAX_TAG_LEN, "%s", emsctrltag);
            HASH_ADD_STR(var->tagmaps, emmstag, curtag);
        }
    }
    fclose(fp);
}

static void ems_smu_nodestructure_init(ems_smu_var_t *var)
{
    char *data = NULL;
    cJSON *root = NULL;
    int lens;
    char dtype[MAX_DEVTYPE_LEN] = {0};
    char dtypealia[MAX_DEVTYPE_LEN] = {0};
    int ca,sa1,st1,sa2,st2,smod,stmod;
    char nodestrupath[64] = {0};
    FILE *fp = fopen(DEV_TYPE_PATH, "r");
    if (NULL == fp)
    {
        dbg_syslog(LOG_ERR, "open "DEV_TYPE_PATH" failed");
        return;
    }

    while(fscanf(fp, "%s %s %d %d %d %d %d %d %d", dtype, dtypealia, &ca, &sa1, &st1, &sa2, &st2, &smod, &stmod)!= EOF)
    {
        char devno[SN_MAX_LEN] = {0};
        snprintf(nodestrupath, 64, EMS_SMU_NODESTRU"/%s.json", dtype);
        dbg_syslog(LOG_ERR, "read %s", nodestrupath);
        data = read_file_data_and_lens(nodestrupath, &lens);
        if (data == NULL)
        {
            dbg_syslog(LOG_ERR, "read cfg file %s error, load default", nodestrupath);
            continue;
        }

        root = cJSON_Parse(data);
        if (!root)
        {
            dbg_syslog(LOG_ERR, "parse cfg file %s error, load default", nodestrupath);
            continue;
        }

        GET_JSON_VALUE_STRING(root, "DEV_NO", devno);
        dbg_syslog(LOG_ERR, "devno %s", devno);
        dev_nodestruct_t *curdev;
        HASH_FIND_STR(var->devtypenode, devno, curdev);
        if (NULL == curdev)
        {
            curdev = malloc(sizeof(dev_nodestruct_t));
            memset(curdev, 0, sizeof(dev_nodestruct_t));
            GET_JSON_VALUE_STRING(root, "TYPE", curdev->devtype);
            GET_JSON_VALUE_STRING(root, "DISP", curdev->devdisp);
            strncpy(curdev->devno, devno, strlen(devno));

            cJSON *alarm = cJSON_GetObjectItem(root, "ALARM");
            cJSON *status = cJSON_GetObjectItem(root, "STATUS");
            cJSON *setting = cJSON_GetObjectItem(root, "SETTING");
            cJSON *datan = cJSON_GetObjectItem(root, "DATA");

            int node_cnt = cJSON_GetArraySize(alarm);
            for (int i = 0; i < node_cnt; i++)
            {
                char entryname[MAX_NAME_LEN] = {0};
                cJSON *node = cJSON_GetArrayItem(alarm, i);
                GET_JSON_VALUE_STRING(node, "NAME", entryname);
                alarm_entry_t* curalarm;
                HASH_FIND_STR(curdev->alarmnode, entryname, curalarm);
                if (NULL == curalarm)
                {
                    curalarm = malloc(sizeof(alarm_entry_t));
                    memset(curalarm, 0, sizeof(alarm_entry_t));
                    GET_JSON_VALUE_STRING(node, "DISP", curalarm->entryDisp);
                    GET_JSON_VALUE_INT(node, "TYPE", curalarm->type);
                    GET_JSON_VALUE_STRING(node, "DESC", curalarm->entryDesc);
                    strncpy(curalarm->entryname, entryname, strlen(entryname));
                    HASH_ADD_STR(curdev->alarmnode, entryname, curalarm);
                }
            }

            node_cnt = cJSON_GetArraySize(status);
            for (int i = 0; i < node_cnt; i++)
            {
                char entryname[MAX_NAME_LEN] = {0};
                cJSON *node = cJSON_GetArrayItem(status, i);
                GET_JSON_VALUE_STRING(node, "NAME", entryname);
                stat_entry_t* curstat;
                HASH_FIND_STR(curdev->statnode, entryname, curstat);
                if (NULL == curstat)
                {
                    curstat = malloc(sizeof(stat_entry_t));
                    memset(curstat, 0, sizeof(stat_entry_t));
                    GET_JSON_VALUE_STRING(node, "DISP", curstat->entryDisp);
                    GET_JSON_VALUE_INT(node, "TYPE", curstat->type);
                    GET_JSON_VALUE_STRING(node, "DESC", curstat->entryDesc);
                    GET_JSON_VALUE_STRING(node, "VALUE", curstat->entryValue);
                    strncpy(curstat->entryname, entryname, strlen(entryname));
                    HASH_ADD_STR(curdev->statnode, entryname, curstat);
                }
            }

            node_cnt = cJSON_GetArraySize(setting);
            for (int i = 0; i < node_cnt; i++)
            {
                char entryname[MAX_NAME_LEN] = {0};
                cJSON *node = cJSON_GetArrayItem(setting, i);
                GET_JSON_VALUE_STRING(node, "NAME", entryname);
                set_entry_t* curset;
                HASH_FIND_STR(curdev->setnode, entryname, curset);
                if (NULL == curset)
                {
                    curset = malloc(sizeof(set_entry_t));
                    memset(curset, 0, sizeof(set_entry_t));
                    GET_JSON_VALUE_STRING(node, "service", curset->sevname);
                    GET_JSON_VALUE_STRING(node, "node", curset->settag);
                    GET_JSON_VALUE_STRING(node, "DISP", curset->entryDisp);
                    GET_JSON_VALUE_INT(node, "TYPE", curset->type);
                    GET_JSON_VALUE_STRING(node, "DESC", curset->entryDesc);
                    strncpy(curset->entryname, entryname, strlen(entryname));
                    HASH_ADD_STR(curdev->setnode, entryname, curset);
                }
            }

            node_cnt = cJSON_GetArraySize(datan);
            for (int i = 0; i < node_cnt; i++)
            {
                char entryname[MAX_NAME_LEN] = {0};
                cJSON *node = cJSON_GetArrayItem(datan, i);
                GET_JSON_VALUE_STRING(node, "NAME", entryname);
                data_entry_t* curdata;
                HASH_FIND_STR(curdev->datanode, entryname, curdata);
                if (NULL == curdata)
                {
                    curdata = malloc(sizeof(data_entry_t));
                    memset(curdata, 0, sizeof(data_entry_t));
                    GET_JSON_VALUE_STRING(node, "DISP", curdata->entryDisp);
                    GET_JSON_VALUE_INT(node, "TYPE", curdata->type);
                    GET_JSON_VALUE_STRING(node, "DESC", curdata->entryDesc);
                    strncpy(curdata->entryname, entryname, strlen(entryname));
                    HASH_ADD_STR(curdev->datanode, entryname, curdata);
                }
            }

            HASH_ADD_STR(var->devtypenode, devno, curdev);
        }    
        cJSON_Delete(root);
    }

    dev_nodestruct_t *pos;
    for(pos = var->devtypenode; pos != NULL; pos = pos->hh.next)
    {
        dbg_syslog(LOG_ERR, "devno %s devtype %s", pos->devno, pos->devtype);
    }

    fclose(fp);
}

static int ems_smu_init(ems_smu_var_t *var)
{
    char cmd[CMD_SHORT_LENGTH] = {0};
    get_board_sn(var->sn_str);
    get_process_name(var->proc_name);
    get_product_name(var->product_name);
    ems_smu_getstainfo(var);
    snprintf(var->emsctrl_sn_str, SN_MAX_LEN * 2, "%s_EMSCTRL", var->sn_str);

    dy_syslog(LOG_INFO, "board SN:%s", var->sn_str);

    if (load_nodes_cfg(&var->nodes_cfg_table, NODES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load nodes cfg fail");
    }

    ems_smu_stacfg_int(var, EMMSV2_STATION_CONFIG);

    ems_smu_mqtt_init(var);
    ems_smu_nodestructure_init(var);

    var->status_timer = my_timer_create();
    if (var->status_timer > 0)
    {
        my_timer_set(var->status_timer, 1, 2000);
    }

    ems_smu_connredis(&var->context);
    snprintf(cmd, CMD_SHORT_LENGTH, "hget "REDIS_SETPARAM_BASE" "SET_CTRLMODE);
    redisReply *reply = (redisReply *)redisCommand(var->context, cmd);
    if (NULL == reply)
    {
        dbg_syslog(LOG_ERR, "execcmd %s error", cmd);
    }
    else if (reply->type == REDIS_REPLY_NIL)
    {
        var->controlMode = -1;
    }
    else
    {
        var->controlMode = atoi(reply->str);        
    }
    freeReplyObject(reply);

    ems_smu_tagmap_init(var);

    if (var->dev_interval <= 60)
        var->dev_interval = 60;

    pthread_create(&thread_sysinfo, NULL, get_sysuse, var);

    dy_syslog(LOG_INFO, "init done");
    return 0;
}

int main(int argc, char *argv[])
{
    ems_smu_var_t var = {0};
    lnxall_loglevel_set(LNXALL_LOGINFO, 1);
    memset(&var, 0, sizeof(var));

    cmd_client_init();
    ems_smu_init(&var);
    ems_smu_loop(&var);

    return 0;
}
