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

#include "bmser_can_init.h"
#include "bmser_can_parse_cfg.h"
#include "xieneng_can_supervisor.h"
#include "j1939_compress.h"
#include "bmser_can_j1939_send.h"
#include "bmser_can_j1939_recv.h"
#include "bmser_can_j1939_syn_data.h"
#include "bmser_project_para.h"

#define PRO_CFG_MAX_KEY_LEN 64
#define PRO_CFG_MAX_KEY_CNT 64

typedef struct
{
    char key[PRO_CFG_MAX_KEY_LEN + 1];
    u_int8_t value;
} BMSER_PRO_CFG_INFO_S;

typedef struct
{
    u_int8_t cnt;
    BMSER_PRO_CFG_INFO_S cfg_info[PRO_CFG_MAX_KEY_CNT + 1];
} BMSER_PRO_CFG_INFO_TABLES_S;

BMSER_CAN_BUS_CFG_TABLE_S g_bmser_can_bus_cfg_table = {0};

/**
 * @description: 获取CFG配置文件配置的CAN个数 
 * @return {*} CAN个数
 */
int bmser_can_get_cfg_can_num()
{
    return g_bmser_can_bus_cfg_table.num;
}

/**
 * @description: 获取CAN CFG TABLES句柄 
 * @return {*} BMSER_CAN_BUS_CFG_TABLE_S句柄
 */
BMSER_CAN_BUS_CFG_TABLE_S* bmser_can_get_cfg_tables_mgr()
{
    return &g_bmser_can_bus_cfg_table;
}

/**
 * @description: BMSER CAN 初始化
 * @param {xieneng_can_var_t} *var
 * @return {*} 0:success, others:fail.
 */
bool bmser_can_cfg_file_enable()
{
    return g_bmser_can_bus_cfg_table.num > 0 ? true : false;
}

/**
 * @description: 获取j1939主动请求开关使能状态
 * @param 
 * @return {*} 0:disable, 1:enable.
 */
bool bmser_general_cfg_j1939_req_enable()
{
    return g_bmser_can_bus_cfg_table.general_cfg.j1939_req_enable;
}

/**
 * @description: 获取j1939监听开关使能状态
 * @param 
 * @return {*} 0:disable, 1:enable.
 */
bool bmser_general_cfg_j1939_listen_enable()
{
    return g_bmser_can_bus_cfg_table.general_cfg.j1939_listen_enable;
}

/**
 * @description: 获取设备的CAN OBJ ID
 * @param {uint8_t} dev_id 设备id
 * @return {*} 设备所在的CAN网口的OBJ ID: success, -1: fail
 */
int bmser_can_get_can_obj_id(uint8_t dev_id)
{
    uint8_t i = 0;
    BMSER_CAN_BUS_CFG_S *can_cfg = NULL;
    for (i = 0; i < g_bmser_can_bus_cfg_table.num; i++) {
        can_cfg = &g_bmser_can_bus_cfg_table.can_cfg[i];
        if (!can_cfg->disable) {
            if (0 == dev_id || 62 == dev_id) { //动环信息默认存到第62簇，默认走总主CAN
                if (can_cfg->main_can) {
                    break;
                }
            } else {
                if (dev_id >= can_cfg->rack_id_start && dev_id <= can_cfg->rack_id_end) {
                    break;
                }
            }
        }
    }

    if (i < g_bmser_can_bus_cfg_table.num && can_cfg && can_cfg->name + strlen(CAN_BUS_INTERFACE_NAME)) {
        return atoi(can_cfg->name + strlen(CAN_BUS_INTERFACE_NAME));
    }
    return -1;
}

static int add_period_read_reg_to_table(uint8_t devType, uint8_t dev_id, period_table_t *period_table, BMSER_CAN_REG_READ_TABLE_S *reg_read_table)
{
    if (NULL == period_table || NULL == reg_read_table) {
        return OPRT_PARA_NULL;
    }

    uint32_t i = 0, j = 0;
    period_node_t *node = NULL;

    for (i = 0; i < reg_read_table->cnt; i++) {

        if (period_table->cnt == 0 || period_table->nodes == NULL) {
            period_table->nodes = calloc(4, sizeof(period_node_t));
            period_table->size = 4;
        } else if (period_table->cnt == period_table->size) {
            period_table->nodes = realloc(period_table->nodes, (period_table->size + 4) * (sizeof(period_node_t)));
            memset(&period_table->nodes[period_table->size], 0, 4 * (sizeof(period_node_t)));
            period_table->size += 4;
        }

        for (j = 0; j < period_table->size; j++) {
            if (period_table->nodes[j].used == 1) {
                continue;
            }

            node = &period_table->nodes[j];
            node->start_addr    = reg_read_table->reg_read[i].start;
            node->term_addr     = (((uint16_t)devType) << 8) | dev_id;
            node->reg_cnt       = reg_read_table->reg_read[i].stop - reg_read_table->reg_read[i].start + 1;
            node->period        = reg_read_table->reg_read[i].period_ms;
            node->used          = 1;
            node->last_send     = 0;
            period_table->cnt   = period_table->cnt + 1;
			#ifdef LOCAL_DEBUG
            dy_syslog(LOG_DEBUG, "devid = %hhu, term_addr = %u, star_addr = %u, reg_cnt = %u, period = %u.",\
            dev_id, node->term_addr, node->start_addr, node->reg_cnt, node->period);
			#endif
            break;
        }
    }
    return 0;
}

/**
 * @description: 设置周期读reg信息到tables
 * @return {*}
 */
static int set_read_reg_tables(xieneng_can_var_t *var)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(var, OPRT_PARA_NULL);

    int ret = 0;
    uint8_t i = 0, k = 0, l = 0;
    period_table_t *period_table = NULL;
    BMSER_CAN_BUS_CFG_S *can_cfg = NULL;

    for (i = 0; i < g_bmser_can_bus_cfg_table.num; i++) {

        period_table = &var->period_tables[i];
        can_cfg = &g_bmser_can_bus_cfg_table.can_cfg[i];
        if (true == can_cfg->disable) {
            continue;
        }

        for (k = 0; k < BMSER_REG_TYPE; k++) {
            if ((BMSER_BAU_REG == k || BMSER_ENV_REG == k) && false == can_cfg->main_can) {
                continue;
            }

            if (BMSER_BAU_REG == k && can_cfg->reg_read_table[k].cnt > 0) {
                BMSER_CALL_FUNC_RETURN_VAL(add_period_read_reg_to_table(TOTAL_LAYER, 0, period_table, &can_cfg->reg_read_table[k]));
            }

            //动环信息，devId为62
            if (BMSER_ENV_REG == k && can_cfg->reg_read_table[k].cnt > 0) {
                BMSER_CALL_FUNC_RETURN_VAL(add_period_read_reg_to_table(TOTAL_LAYER, 62, period_table, &can_cfg->reg_read_table[k]));
            }

            if (BMSER_BCU_REG == k && can_cfg->reg_read_table[k].cnt > 0) {
                for (l = can_cfg->rack_id_start; l <= can_cfg->rack_id_end; l++) { //这里优化下,只需要保存一簇的周期读node
                    BMSER_CALL_FUNC_RETURN_VAL(add_period_read_reg_to_table(MASTER_LAYER, l, period_table, &can_cfg->reg_read_table[k]));
                }
            }

            if (BMSER_BDU_REG == k && can_cfg->reg_read_table[k].cnt > 0) {
                for (l = can_cfg->bdu_id_start; l <= can_cfg->bdu_id_end; l++) { //这里优化下,只需要保存一簇的周期读node
                    BMSER_CALL_FUNC_RETURN_VAL(add_period_read_reg_to_table(BDU_LAYER, l, period_table, &can_cfg->reg_read_table[k]));
                }
            }
        }
    }
    return ret;
}

static int update_period_read_reg_to_table(xieneng_can_var_t *var, uint8_t rack_num)
{
    period_node_t *node = NULL;
    uint32_t i = 0, j = 0, port_index = 0, dev_id = 0;

    for (j = 0; j < g_bmser_can_bus_cfg_table.num; j++) {
        if (g_bmser_can_bus_cfg_table.can_cfg[j].disable) {
            continue;
        }

        period_table_t *period_table = &var->period_tables[j];
        for (i = 0; i < period_table->size; i++) {
            node = &period_table->nodes[i];
            dev_id = node->term_addr & 0xFF;
            dy_syslog(LOG_DEBUG, "can%hhu, dev_id = %hhu, start_addr = %u, reg_cnt = %u, used = %d, rack_num = %hhu", j, dev_id, node->start_addr, node->reg_cnt, node->used, rack_num);
            if (period_table->nodes[i].used == 1) {
                if (dev_id > rack_num && 62 != dev_id) {
                    node->used = 0;
                }
            } else if (period_table->nodes[i].used == 0) {
                if (dev_id <= rack_num || 62 == dev_id) {
                    node->used = 1;
                    node->last_send = 0;
                }
            }
        }
    }
    return 0;
}

/**
 * @brief       bmser_can 初始化
 * @return      int
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-03-08           JHC        创建初始版本          \n
 * 2023-10-12           QZY        配置的can总线数量为0时，直接返回错误   \n
*/
int bmser_can_init()
{
    int ret = 0, i = 0;
    CAN_INF_CFG_STRU canCfg = {0};
    BMSER_CALL_FUNC_RETURN_VAL(bmser_can_parse_db3_canbusConfig());
    BMSER_CALL_FUNC_RETURN_VAL(bmser_can_parse_cfg_file(BMSER_CAN_BUS_CFG_FILE));
    g_bmser_can_bus_cfg_table.rack_num = bmser_jsonGetRackNum();
    if(0 == g_bmser_can_bus_cfg_table.num){
        dy_syslog(LOG_DEBUG,"can num = 0!\n");
        return -1;
    }
    for (i = 0; i < g_bmser_can_bus_cfg_table.num; i++) {
        canCfg.canObjId = i;
        canCfg.canBitRate = g_bmser_can_bus_cfg_table.can_cfg[i].bitrate;
        if (false == g_bmser_can_bus_cfg_table.can_cfg[i].disable) {
            BMSER_CALL_FUNC_RETURN_VAL(canInf_init(&canCfg));
            if(bmser_general_cfg_j1939_listen_enable()){
                // J1939接收初始化
                BMSER_CALL_FUNC_RETURN_VAL(J1939RecvMsg_Init(&canCfg));
            }
        }
    }
    if(bmser_general_cfg_j1939_req_enable()){
        // J1939请求(发送)初始化
        BMSER_CALL_FUNC_RETURN_VAL(J1939SendMsg_Init(&g_bmser_can_bus_cfg_table));
    }
    if(bmser_general_cfg_j1939_listen_enable())
    {
        //J1939压缩算法初始化
        BMSER_CALL_FUNC_RETURN_VAL(Compress_Init());
        //同步采样信息初始化
        BMSER_CALL_FUNC_RETURN_VAL(SynSampleDataMaster_Init());
    }
    xieneng_can_var_t *var = get_xieneng_can_var();
    BMSER_CALL_FUNC_RETURN_VAL(set_read_reg_tables(var));
    update_period_read_reg_to_table(var, g_bmser_can_bus_cfg_table.rack_num);
    return ret;
}

static int parse_projcet_mqtt_message(const char *payload, int paylaod_len, BMSER_PRO_CFG_INFO_TABLES_S *info)
{
    if (NULL == payload || paylaod_len <= 0 || NULL == info) {
        return -1;
    }

    cJSON* root = NULL, *frames = NULL;
    cJSON* identifier = NULL, *regs = NULL, *node = NULL, *key = NULL, *value = NULL;
    char key_str[64] = {0};
    int key_value = 0;

    root = cJSON_Parse(payload);
    if (NULL == root) {
        return -1;
    }

    identifier = cJSON_GetObjectItem(root, "identifier");
    if (NULL == identifier || NULL == cJSON_GetStringValue(identifier)) {
        cJSON_Delete(root);
        root = NULL;
        return -1; 
    }

    frames = cJSON_GetObjectItem(root, "frames");
    if (NULL == frames) {
        cJSON_Delete(root);
        root = NULL;
        return -1;  
    }

    int i = 0, j = 0, cnt = 0, reg_cnt = 0;
    cnt = cJSON_GetArraySize(frames);
    for (i = 0; i < cnt; i++) {
        node = cJSON_GetArrayItem(frames, i);
        if (NULL == node) {
            continue;
        }

        regs = cJSON_GetObjectItem(node, "regs");
        if (NULL == regs) {
            continue;
        }

        reg_cnt = cJSON_GetArraySize(regs);
        for (j = 0; j < reg_cnt && j < PRO_CFG_MAX_KEY_CNT + 1; j++) {
            node = cJSON_GetArrayItem(regs, j);
            if (NULL == node) {
                continue;
            }

            key = cJSON_GetObjectItem(node, "key");
            value = cJSON_GetObjectItem(node, "value");
            if (!key || !value) {
                continue;
            }

            snprintf(info->cfg_info[j].key, PRO_CFG_MAX_KEY_LEN + 1, "%s", cJSON_GetStringValue(key));
            info->cfg_info[j].value = cJSON_GetNumberValue(value);
            info->cnt++;
            dy_syslog(LOG_DEBUG, "get cfg para key = %s, value = %d.", info->cfg_info[j].key, info->cfg_info[j].value);
        }
    }

    cJSON_Delete(root);
    root = NULL;
    
    return 0;
}

/**
 * @description: 处理设置项目参数(修改簇数等)
 * @param {char} *payload 消息内容
 * @param {int} payload_len 消息长度
 * @return {*}
 */
int bmser_can_set_mqtt_project_para(const char *payload, int payload_len)
{
    
    BMSER_PRO_CFG_INFO_TABLES_S cfg_tables = {0};
    parse_projcet_mqtt_message(payload, payload_len, &cfg_tables);

    uint8_t i = 0, rack_num = 0;
    while (i < cfg_tables.cnt)
    {
        if (0 == strcmp(cfg_tables.cfg_info[i].key, "racknum")) {
            rack_num = cfg_tables.cfg_info[i].value;
            break;
        } else {
            i++;
        }
    }

    dy_syslog(LOG_DEBUG, "get rack_num is %hhu.", rack_num);
    xieneng_can_var_t *var = get_xieneng_can_var();
    if (rack_num > 0 && rack_num != g_bmser_can_bus_cfg_table.rack_num) {
        update_period_read_reg_to_table(var, rack_num);
        g_bmser_can_bus_cfg_table.rack_num = rack_num;
    }
	return 0;
}

