#include "general_method.h"
#include "icp67.h"
#include "myLog.h"

#include <map>

LOCAL void icp67_param_get(stru_icp67 *p_icp67, stru_ti_1_2_data *p_data, uint16_t num);
LOCAL void icp67_param_set(stru_icp67 *p_icp67, uint8_t *p_data, uint16_t num);
LOCAL void icp67_iec_point_tbl_get(stru_icp67 *p_icp67, uint16_t info_addr);
LOCAL void icp67_time_set(stru_icp67 *p_icp67, stru_ti_5 *p_data);
LOCAL void icp67_self_check_get(stru_icp67 *p_icp67);
LOCAL void icp67_upgrade_start(stru_icp67 *p_icp67, uint8_t dst);

LOCAL void icp67_dir_read(stru_icp67 *p_icp67, uint8_t *p_dir, uint8_t len, uint8_t *tm_start, uint8_t *tm_end);
LOCAL void icp67_file_read_act(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len);
LOCAL void icp67_file_read_confirm(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset);
LOCAL void icp67_file_write_act(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size, uint16_t crc);
LOCAL void icp67_file_write(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, uint8_t follow, uint8_t *p_data, uint16_t len);
LOCAL void icp67_file_write_end_confirm(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint8_t *md5);

LOCAL stru_genneral_method g_genneral_method = 
{
    .param_get_cb = icp67_param_get,
    .param_pop_out_cb = NULL,
    .param_set_cb = icp67_param_set,
    .iec_point_tbl_get_cb = icp67_iec_point_tbl_get,
    .iec_point_tbl_pop_out_cb = NULL,
    .time_set_cb = icp67_time_set,
    .self_check_get_cb = icp67_self_check_get,
    .self_check_pop_out_cb = NULL,
    .upgrade_start_cb = icp67_upgrade_start,

    .dir_read_cb = icp67_dir_read,
    .dir_pop_out_cb = NULL,
    .file_read_act_cb = icp67_file_read_act,
    .file_read_act_confirm_cb = NULL,
    .file_read_cb = NULL,
    .file_read_confirm_cb = icp67_file_read_confirm,
    .file_write_act_cb = icp67_file_write_act,
    .file_write_act_confirm_cb = NULL,
    .file_write_cb = icp67_file_write,
    .file_write_confirm_cb = NULL,
    .file_write_end_cb = NULL,
    .file_write_end_confirm_cb = icp67_file_write_end_confirm,

    .zip_dir_pop_out_cb = NULL,
    .zip_file_pop_out_cb = NULL,

    .mx_trans_cb = NULL,
    .st_trans_cb = NULL,
    .dd_trans_cb = NULL,
    .soe_trans_cb = NULL,
    .fault_trans_cb = NULL,
    .mx_change_cb = NULL
};

stru_genneral_method* icp67_get_genneral_method()
{
    return &g_genneral_method;
}

void icp67_set_param_get_cb(icp67_param_get_cb *p_cb)
{
    (*p_cb) = g_genneral_method.param_get_cb;
}

void icp67_set_param_pop_out_cb(icp67_param_pop_out_cb cb)
{
    g_genneral_method.param_pop_out_cb = cb;
}

void icp67_set_param_set_cb(icp67_param_set_cb *p_cb)
{
    (*p_cb) = g_genneral_method.param_set_cb;
}

void icp67_set_iec_point_tbl_get_cb(icp67_iec_point_tbl_get_cb *p_cb)
{
    (*p_cb) = g_genneral_method.iec_point_tbl_get_cb;
}

void icp67_set_iec_point_tbl_pop_out_cb(icp67_iec_point_tbl_pop_out_cb cb)
{
    g_genneral_method.iec_point_tbl_pop_out_cb = cb;
}

void icp67_set_time_set_cb(icp67_time_set_cb *p_cb)
{
    (*p_cb) = g_genneral_method.time_set_cb;
}

void icp67_set_self_check_get_cb(icp67_self_check_get_cb *p_cb)
{
    (*p_cb) = g_genneral_method.self_check_get_cb;
}

void icp67_set_self_check_pop_out_cb(icp67_self_check_pop_out_cb cb)
{
    g_genneral_method.self_check_pop_out_cb = cb;
}

void icp67_set_upgrade_start_cb(icp67_upgrade_start_cb *p_cb)
{
    (*p_cb) = g_genneral_method.upgrade_start_cb;
}

void icp67_set_dir_read_cb(icp67_dir_read_cb *p_cb)
{
    (*p_cb) = g_genneral_method.dir_read_cb;
}

void icp67_set_dir_pop_out_cb(icp67_dir_pop_out_cb cb)
{
    g_genneral_method.dir_pop_out_cb = cb;
}

void icp67_set_file_read_act_cb(icp67_file_read_act_cb *p_cb)
{
    (*p_cb) = g_genneral_method.file_read_act_cb;
}

void icp67_set_file_read_act_confirm_cb(icp67_file_read_act_confirm_cb cb)
{
    g_genneral_method.file_read_act_confirm_cb = cb;
}

void icp67_set_file_read_cb(icp67_file_read_cb cb)
{
    g_genneral_method.file_read_cb = cb;
}

void icp67_set_file_read_confirm_cb(icp67_file_read_confirm_cb *p_cb)
{
    (*p_cb) = g_genneral_method.file_read_confirm_cb;
}

void icp67_set_file_write_act_cb(icp67_file_write_act_cb *p_cb)
{
    (*p_cb) = g_genneral_method.file_write_act_cb;
}

void icp67_set_file_write_act_confirm_cb(icp67_file_write_act_confirm_cb cb)
{
    g_genneral_method.file_write_act_confirm_cb = cb;
}

void icp67_set_file_write_cb(icp67_file_write_cb *p_cb)
{
    (*p_cb) = g_genneral_method.file_write_cb;
}

void icp67_set_file_write_confirm_cb(icp67_file_write_confirm_cb cb)
{
    g_genneral_method.file_write_confirm_cb = cb;
}

void icp67_set_file_write_end_cb(icp67_file_write_end_cb cb)
{
    g_genneral_method.file_write_end_cb = cb;
}

void icp67_set_file_write_end_confirm_cb(icp67_file_write_end_confirm_cb *p_cb)
{
    (*p_cb) = g_genneral_method.file_write_end_confirm_cb;
}

void icp67_set_zip_dir_pop_out_cb(icp67_zip_dir_pop_out_cb cb)
{
    g_genneral_method.zip_dir_pop_out_cb = cb;
}

void icp67_set_zip_file_pop_out_cb(icp67_zip_file_pop_out_cb cb)
{
    g_genneral_method.zip_file_pop_out_cb = cb; 
}

void icp67_set_mx_trans_cb(icp67_mx_trans_cb cb)
{
    g_genneral_method.mx_trans_cb = cb;
}

void icp67_set_st_trans_cb(icp67_st_trans_cb cb)
{
    g_genneral_method.st_trans_cb = cb;
}

void icp67_set_dd_trans_cb(icp67_dd_trans_cb cb)
{
    g_genneral_method.dd_trans_cb = cb;
}

void icp67_set_soe_trans_cb(icp67_soe_trans_cb cb)
{
    g_genneral_method.soe_trans_cb = cb;
}

void icp67_set_fault_trans_cb(icp67_fault_trans_cb cb)
{
    g_genneral_method.fault_trans_cb = cb;
}

void icp67_set_mx_change_cb(icp67_mx_change_cb cb)
{
    g_genneral_method.mx_change_cb = cb;
}



LOCAL void icp67_param_get(stru_icp67 *p_icp67, stru_ti_1_2_data *p_data, uint16_t num)
{
    if(NULL == p_icp67 || NULL == p_data || num == 0)
    {
        LOG_E("icp67_param_get: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_1, COT_5, TI_1_INFO_ADDR, p_tx, tx_len);

    stru_ti_1_2 *p_asdu = (stru_ti_1_2 *)&p_tx[tx_len];
    memcpy(p_asdu->md5, p_icp67->md5, 16);
    p_asdu->num = num;
    tx_len += sizeof(stru_ti_1_2);

    for(uint16_t i = 0; i < num; i++)
    {
        stru_ti_1_2_data *p = (stru_ti_1_2_data *)&p_tx[tx_len];
        memcpy(p, &p_data[i], sizeof(stru_ti_1_2_data));
        tx_len += sizeof(stru_ti_1_2_data);
    }

    icp67_make_tail(p_tx, tx_len);
    
    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);

}

LOCAL void icp67_param_set(stru_icp67 *p_icp67, uint8_t *p_data, uint16_t num)
{
    if(NULL == p_icp67 || NULL == p_data || num == 0)
    {
        LOG_E("icp67_param_set: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_2, COT_6, TI_1_INFO_ADDR, p_tx, tx_len);

    stru_ti_1_2 *p_asdu = (stru_ti_1_2 *)&p_tx[tx_len];
    memcpy(p_asdu->md5, p_icp67->md5, 16);
    p_asdu->num = num;
    tx_len += sizeof(stru_ti_1_2);

    uint16_t pos = 0;

    for(uint16_t i = 0; i < num; i++)
    {
        stru_ti_1_2_data *p_src = (stru_ti_1_2_data *)&p_data[pos];
        memcpy(&p_tx[tx_len], p_src, sizeof(stru_ti_1_2_data_info) + p_src->data_len);
        tx_len += (sizeof(stru_ti_1_2_data_info) + p_src->data_len);
        pos += (sizeof(stru_ti_1_2_data) + p_src->data_len);
    }

    icp67_make_tail(p_tx, tx_len);
    
    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
    // icp67_reset_tm_cnt(p_icp67);
}

LOCAL void icp67_iec_point_tbl_get(stru_icp67 *p_icp67, uint16_t info_addr)
{
    if(NULL == p_icp67)
    {
        LOG_E("icp67_iec_point_tbl_get: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_3, COT_5, info_addr, p_tx, tx_len);

    icp67_make_tail(p_tx, tx_len);
    
    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_time_set(stru_icp67 *p_icp67, stru_ti_5 *p_data)
{
    if(NULL == p_icp67 || NULL == p_data)
    {
        LOG_E("icp67_time_set: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_5, COT_5, TI_5_INFO_ADDR, p_tx, tx_len);

    stru_ti_5 *p_asdu = (stru_ti_5 *)&p_tx[tx_len];
    memcpy(p_asdu, p_data, sizeof(stru_ti_5));
    tx_len += sizeof(stru_ti_5);

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_self_check_get(stru_icp67 *p_icp67)
{
    if(NULL == p_icp67)
    {
        LOG_E("icp67_self_check_get: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_6, COT_5, TI_6_INFO_ADDR, p_tx, tx_len);
    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_upgrade_start(stru_icp67 *p_icp67, uint8_t dst)
{
    if(NULL == p_icp67)
    {
        LOG_E("icp67_upgrade_start: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(dst, TI_9, COT_5, TI_9_INFO_ADDR, p_tx, tx_len);
    p_tx[tx_len++] = 0x01;  // 升级类型，启动升级
    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_dir_read(stru_icp67 *p_icp67, uint8_t *p_dir, uint8_t len, uint8_t *tm_start, uint8_t *tm_end)
{
    if(NULL == p_icp67 || NULL == p_dir || len == 0)
    {
        LOG_E("icp67_dir_read: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_11, COT_5, TI_11_INFO_ADDR, p_tx, tx_len);

    stru_ti_11_1 *p_asdu = (stru_ti_11_1 *)&p_tx[tx_len];

    p_asdu->cmd = FILE_CMD_1;  // 读目录
    p_asdu->id = 0;
    p_asdu->len = len;
    tx_len += sizeof(stru_ti_11_1);

    memcpy(&p_tx[tx_len], p_dir, len);
    tx_len += len;

    stru_ti_11_1_info *p_info = (stru_ti_11_1_info *)&p_tx[tx_len];
    if(tm_start && tm_end)
    {
        p_info->flag = 1;
        memcpy(p_info->start_tm, tm_start, 7);
        memcpy(p_info->end_tm, tm_end, 7);
    }
    else
    {
        p_info->flag = 0;
        memset(p_info->start_tm, 0, 7);
        memset(p_info->end_tm, 0, 7);
    }
    tx_len += sizeof(stru_ti_11_1_info);

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_file_read_act(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len)
{
    if(NULL == p_icp67 || NULL == p_name || len == 0)
    {
        LOG_E("icp67_file_read_act: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_11, COT_5, TI_11_INFO_ADDR, p_tx, tx_len);

    stru_ti_11_3 *p_asdu = (stru_ti_11_3 *)&p_tx[tx_len];
    p_asdu->cmd = FILE_CMD_3;  // 读文件
    p_asdu->len = len;
    tx_len += sizeof(stru_ti_11_3);

    memcpy(&p_tx[tx_len], p_name, len);
    tx_len += len;

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_file_read_confirm(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint32_t offset)
{
    if(NULL == p_icp67)
    {
        LOG_E("icp67_file_read_confirm: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    uint8_t cot = (result == 0 ? COT_7 : COT_8); // 0:成功，1:失败

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_11, cot, TI_11_INFO_ADDR, p_tx, tx_len);

    stru_ti_11_6 *p_asdu = (stru_ti_11_6 *)&p_tx[tx_len];

    p_asdu->cmd = FILE_CMD_6;  // 读文件确认
    p_asdu->id = id;
    p_asdu->offset = offset;
    p_asdu->result = result;
    tx_len += sizeof(stru_ti_11_6);

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_file_write_act(stru_icp67 *p_icp67, uint8_t *p_name, uint8_t len, uint32_t id, uint32_t size, uint16_t crc)
{
    if(NULL == p_icp67 || NULL == p_name || len == 0)
    {
        LOG_E("icp67_file_write_act: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_11, COT_5, TI_11_INFO_ADDR, p_tx, tx_len);

    stru_ti_11_7 *p_asdu = (stru_ti_11_7 *)&p_tx[tx_len];
    p_asdu->cmd = FILE_CMD_7;  // 写文件
    p_asdu->len = len;
    tx_len += sizeof(stru_ti_11_7);

    memcpy(&p_tx[tx_len], p_name, len);
    tx_len += len;

    stru_ti_11_file_info *p_info = (stru_ti_11_file_info *)&p_tx[tx_len];
    p_info->id = id;
    p_info->size = size;
    p_info->crc = crc;
    tx_len += sizeof(stru_ti_11_file_info);

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);

    LOG_I("icp67_file_write_act: id=%d, size=%d, crc=%d ,name=%s", id, size, crc, p_name);
}

LOCAL void icp67_file_write(stru_icp67 *p_icp67, uint32_t id, uint32_t offset, uint8_t follow, uint8_t *p_data, uint16_t len)
{
    if(NULL == p_icp67 || NULL == p_data || len == 0)
    {
        LOG_E("icp67_file_write: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_11, COT_5, TI_11_INFO_ADDR, p_tx, tx_len);

    stru_ti_11_9 *p_asdu = (stru_ti_11_9 *)&p_tx[tx_len];
    p_asdu->cmd = FILE_CMD_9;  // 写文件
    p_asdu->id = id;
    p_asdu->offset = offset;
    p_asdu->follow = follow;
    p_asdu->len = len;
    tx_len += sizeof(stru_ti_11_9);

    memcpy(&p_tx[tx_len], p_data, len);
    tx_len += len;

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}

LOCAL void icp67_file_write_end_confirm(stru_icp67 *p_icp67, uint8_t result, uint32_t id, uint8_t *md5)
{
    if(NULL == p_icp67 || NULL == md5)
    {
        LOG_E("icp67_file_write_end_confirm: invalid input parameter\n");
        return;
    }

    uint8_t *p_tx = p_icp67->tx;
    uint16_t tx_len = 0;

    uint8_t cot = (result == 0 ? COT_7 : COT_8); // 0:成功，1:失败

    icp67_make_head(ENUM_DEV_TYPE_SYS, TI_11, cot, TI_11_INFO_ADDR, p_tx, tx_len);

    stru_ti_11_11 *p_asdu = (stru_ti_11_11 *)&p_tx[tx_len];
    p_asdu->cmd = FILE_CMD_11;  // 写文件结束确认
    p_asdu->id = id;
    p_asdu->result = result;
    memcpy(p_asdu->md5, md5, 16);
    tx_len += sizeof(stru_ti_11_11);

    icp67_make_tail(p_tx, tx_len);

    p_icp67->tx_len = tx_len;
    p_icp67->send_cb(p_tx, tx_len, p_icp67->arg);

    // icp67_rtx_flag_set(p_icp67, ICP67_TX_FLAG, 0, 0);
}



