#include "vint_common.h"

static int send_rtu_soft_info(vint_var_t *var, payload_data_hdr_t *hdr)
{
    cJSON *root;
    char ver_str[32] = {0};
    char p_ver[32] = {0};
    int ver;
    float pver;
    char *p = NULL;
    register_info_t psoft = {0};
    node_message_action_t nm_action = {0};

    if (hdr->data == NULL)
    {
        return -1;
    }

    root = cJSON_Parse(hdr->data);
    if (!root)
    {
        dy_syslog(LOG_ERR, "parse error");
        return -1;
    }
    GET_JSON_VALUE_STRING(root, "ver", ver_str);
    GET_JSON_VALUE_STRING(root, "pver", p_ver);
    cJSON_Delete(root);

    sscanf(ver_str, "V%d-%*s", &ver);
    sscanf(p_ver, "%f", &pver);
    psoft.soft_ver = ver;
    psoft.protocol_ver = pver;
    nm_action.action = ACTION_SOFT_INFO;
    nm_action.port = VINTF_MQTT;
    strcpy(nm_action.sn, hdr->sn);
    memcpy(nm_action.res, &psoft, sizeof(psoft));
    ds_flush_status_action(var->ds, &nm_action);

    return 0;
}

static int __vint_send_data_to_rtu(vint_var_t *var, char *sn, char *cmd, char *buf, int len)
{
    char topic[32] = {0};

    //将数据加入list,由poll函数去发送
    sprintf(topic, "M/%s/%s", sn, cmd);

    mqtt_session_publish(var->session_ext, topic, buf, len);

    return 0;
}

int vint_send_data_to_rtu(vint_var_t *var, pp_regulate_signal_t *regulate_data)
{
    int ret = 0;
    char *sn = regulate_data->sn;
    int i;

    if (regulate_data->len <= 0)
    {
        return ret;
    }

    //store the identifier
    {
        char key_str[64] = {0};
        regulate_cmd_backup_t fields;

        strcpy(fields.src_identifier, regulate_data->src_identifier);
        strcpy(fields.sn, sn);
        fields.mi = regulate_data->mi;

        if (strcmp(regulate_data->src_identifier, "G_Compress") == 0)
        {
            // 召测压缩数据时，返回的MI只有最低字节
            sprintf(key_str, "%s_%u", sn, (unsigned char)regulate_data->mi);
        }
        else
        {
            sprintf(key_str, "%s_%u", sn, regulate_data->mi);
        }
        var->identifier_backup.insert(&var->identifier_backup, key_str, &fields, sizeof(fields));
    }

    __vint_send_data_to_rtu(var, regulate_data->sn, regulate_data->src_identifier, regulate_data->data, regulate_data->len);

out:
    return ret;
}

static int parse_data(mqtt_message_t *mqtt_msg, payload_data_hdr_t *hdr)
{
    char *topic = mqtt_msg->topic;
    int count = 0;
    char *buf = NULL;
    int len;

    count = sscanf(topic, "%[^/]/%[^/]/%s", hdr->source, hdr->sn, hdr->cmd);
    if (count != 3)
    {
        dy_syslog(LOG_ERR, "parse topic:%s fail", topic);
        return -1;
    }

    if (hdr->cmd[0] == 'R' && hdr->cmd[1] == '\0')
    {
        // 状态上报，压缩协议
        cJSON *root = NULL;
        char *payload = NULL;

        root = cJSON_Parse(mqtt_msg->payload);
        if (root == NULL)
        {
            dy_syslog(LOG_ERR, "json parse error");
            return -1;
        }
        GET_JSON_VALUE_DY_STRING(root, "X", payload);

        buf = (char *)malloc(MAXBUF);
        len = b64_decode(payload, buf, MAXBUF);

        hdr->mi = (unsigned char)buf[4];
        free(payload);

        cJSON_Delete(root);
        hdr->data = buf;
        hdr->len = len;
        hdr->need_free = 1;

        return 0;
    }
    else
    {
        cJSON *root = NULL;

        root = cJSON_Parse(mqtt_msg->payload);
        if (root == NULL)
        {
            dy_syslog(LOG_ERR, "json parse error");
            return -1;
        }
        GET_JSON_VALUE_INT(root, "mi", hdr->mi);

        cJSON_Delete(root);
        hdr->data = mqtt_msg->payload;
        hdr->len = strlen(mqtt_msg->payload);
        hdr->need_free = 0;
        return 0;
    }
}

static int vint_rtu_reply_common_ack(vint_var_t *var, payload_data_hdr_t *hdr)
{
    char buf[512] = {0};

    snprintf(buf, 512, "{\"ts\":%ld,\"mi\":%d,\"errid\":%d}",
             time(NULL) - UTC_AT_2000_01_01_00_00_00, hdr->mi, 0);

    __vint_send_data_to_rtu(var, hdr->sn, "A", buf, strlen(buf));
}

int handle_new_rtu_data(vint_var_t *var, mqtt_message_t *mqtt_msg)
{
    pp_real_time_data_t real_data = {0};
    node_cfg_t *p_node = NULL;
    payload_data_hdr_t hdr = {0};
    int ret = NORETURN;
    int i;
    regulate_cmd_backup_t *fields = NULL;

    if (mqtt_msg == NULL)
    {
        return -1;
    }

    ret = parse_data(mqtt_msg, &hdr);
    if (ret == -1)
    {
        dy_syslog(LOG_ERR, "parse data failed");
        return -1;
    }

    if (strcmp(hdr.source, "RTU") != 0)
    {
        dy_syslog(LOG_INFO, "The device:%s not RTU", hdr.sn);
        ret = NOT_BELONG_TO_US;
        goto out;
    }

    dy_syslog(LOG_INFO, "tcp iot data source:%s sn:%s cmd:%s mi:%u", hdr.source, hdr.sn, hdr.cmd, hdr.mi);
    for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
    {
        if (strcmp(hdr.sn, var->nodes_cfg_table->node[i].sn) == 0 &&
                var->nodes_cfg_table->node[i].port == VINTF_MQTT)
        {
            p_node = &var->nodes_cfg_table->node[i];
        }
    }
    if (p_node == NULL)
    {
        dy_syslog(LOG_INFO, "The device:%s not belong to us", hdr.sn);
        ret = NOT_BELONG_TO_US;
        goto out;
    }

    // the device use this socket to communicate
    if (strcmp(hdr.cmd, "R_LogIn") == 0)
    {
        send_rtu_soft_info(var, &hdr);
        flush_device_status_by_sn(var->ds, ACTION_LOGIN, hdr.sn);
    }
    else
    {
        flush_device_status_by_sn(var->ds, ACTION_RCV, hdr.sn);
    }

    //restore the identifier
    {
        char key_str[64] = {0};
        data_info_t *data_info = NULL;

        sprintf(key_str, "%s_%u",  hdr.sn, hdr.mi);

        data_info = var->identifier_backup.get(&var->identifier_backup, key_str);
        if (data_info)
        {
            fields = (regulate_cmd_backup_t *)data_info->data;
        }
    }

    if (strcmp(hdr.cmd, "R_LogIn") == 0 || strcmp(hdr.cmd, "HB") == 0)
    {
        // login and Heart beat
        ret = RETURN_ACK;
        goto out;
    }

    if (strcmp(hdr.cmd, "R") == 0)
    {
        ret = RETURN_ACK;
    }

    real_data.port = VINTF_MQTT;
    real_data.len = hdr.len;
    real_data.data = hdr.data;
    strcpy(real_data.sn, hdr.sn);
    real_data.mi = hdr.mi;

    if (strlen(p_node->sub_template_id))
    {
        strncpy(real_data.sub_template_id, p_node->sub_template_id, strlen(p_node->sub_template_id));
    }

    if (strcmp(hdr.cmd, "R") == 0 && fields && strlen(fields->src_identifier) != 0 && strcmp(fields->src_identifier, "G_Compress") == 0)
    {
        // 召测上来的数据
        ret = NORETURN;
    }

    if ((strcmp(hdr.cmd, "A") == 0 || strcmp(hdr.cmd, "R") == 0) && fields && strlen(fields->src_identifier) != 0)
    {
        // Device side reply ACK to us
        dy_syslog(LOG_INFO, "restore recorded identifier:%s mi:%d ", fields->src_identifier, real_data.mi);
        memcpy(real_data.src_identifier, fields->src_identifier,
               sizeof(real_data.src_identifier));
        if (fields->mi != 0)
        {
            real_data.mi = fields->mi;
        }
    }
    else if (strncmp(hdr.cmd, "B_", 2) == 0 && hdr.cmd[2] >= 'A' && hdr.cmd[2] <= 'Z')
    {
        hdr.cmd[0] = 'G';
        strcpy(real_data.src_identifier, hdr.cmd);
    }
    else
    {
        strcpy(real_data.src_identifier, hdr.cmd);
    }
    send_to_proto_parser(var->session_int, &real_data);
out:

    if (hdr.need_free)
    {
        free(hdr.data);
    }
    if (ret == RETURN_ACK)
    {
        vint_rtu_reply_common_ack(var, &hdr);
    }
    return ret;
}
