#include "kuaibu.h"

static data_ctrl_thread_var_t threads_var[ENG_ASS_GRP_MAX] = {0};
static hash_intptr_t *tag_map_hash = NULL;

static struct 
{
    int runmode;
    data_event_cb_t data_event_cb;
}item_var;


static tag_info_t tag_info_table_stack[] = {
    {"TAG_4E22",  offsetof(eng_ass_grp_data_t, pcs_fault),            E_TAG_INT},
    {"TAG_4E88",  offsetof(eng_ass_grp_data_t, pcs_active_power),     E_TAG_FLOAT},
    {"TAG_4E89",  offsetof(eng_ass_grp_data_t, pcs_reactive_power),   E_TAG_FLOAT},
    {"TAG_4E25",  offsetof(eng_ass_grp_data_t, pcs_connect_state),    E_TAG_INT},
    {"TAG_4E28",  offsetof(eng_ass_grp_data_t, pcs_conenable),        E_TAG_INT},
    //约定的PCS运行模式  0：停机 1：待机 2：启动
    {"TAG_517D",  offsetof(eng_ass_grp_data_t, pcs_run_state),        E_TAG_INT},
    {"TAG_4F30",  offsetof(eng_ass_grp_data_t, pcs_remote),           E_TAG_INT},
    // {"TAG_75E7",  offsetof(eng_ass_grp_data_t, bms_soc),              E_TAG_FLOAT},
    {"TAG_9C83",  offsetof(eng_ass_grp_data_t, bms_soc),              E_TAG_FLOAT},

    // {"TAG_75E3",  offsetof(eng_ass_grp_data_t, bms_work_state),       E_TAG_INT},
    // {"TAG_75E4",  offsetof(eng_ass_grp_data_t, bms_cha_discha_state), E_TAG_INT},
    {"TAG_9C80",  offsetof(eng_ass_grp_data_t, bms_total_voltage),    E_TAG_FLOAT},
    {"TAG_9C81",  offsetof(eng_ass_grp_data_t, bms_total_current),    E_TAG_FLOAT},
    {"TAG_9D77",  offsetof(eng_ass_grp_data_t, bms_avaiable_cha_curr),    E_TAG_FLOAT},
    {"TAG_9D78",  offsetof(eng_ass_grp_data_t, bms_avaiable_disc_curr),   E_TAG_FLOAT},
    // 电操合闸状态 0：分闸 1：合闸
    {"TAG_76C6",  offsetof(eng_ass_grp_data_t, bms_switch_on_state),  E_TAG_INT},
    {"TAG_2730",  offsetof(eng_ass_grp_data_t, meter_reactive_power), E_TAG_FLOAT},
    {"TAG_2734",  offsetof(eng_ass_grp_data_t, meter_positive_energy),E_TAG_FLOAT},
    {"TAG_2739",  offsetof(eng_ass_grp_data_t, meter_negtive_energy), E_TAG_FLOAT},
    // 电高压状态 0：下高压 1：上高压
    {"TAG_7561",  offsetof(eng_ass_grp_data_t, bms_conn_high_power),  E_TAG_INT},
    //主正接触器状态 0：断开 1：闭合
    {"TAG_9D89",  offsetof(eng_ass_grp_data_t, bms_relay_p),  E_TAG_INT},
    //主负接触器状态 0：断开 1：闭合
    {"TAG_9D8A",  offsetof(eng_ass_grp_data_t, bms_relay_n),  E_TAG_INT} ,   
};


//主接触器  快卜CAN协议特殊
static void send_cmd_set_bms_relay(energy_var_t *var,int grp_index,int value_)//给0 是断开继电器  1是闭合继电器
{ 
    int value = (value_ == 1)?2:0;
    eng_ass_tag_kv_t kv[] = {{"SBMU_No",255},{"MainRlyCmd",value}};
    data_ctrl_dev_action_muti_tag(var,GROUP_BMS_INDEX(var,grp_index,0),"M2S_CMD_DOWN",kv,ARRAY_SIZE((kv)));
    dbg_syslog(LOG_WARNING,"Set grp[%d] bms main relay=%d",grp_index,value);
}

static int chk_pcs_switch_kuaibu(energy_var_t *var,int grp,int value)
{
    // if(value == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.pcs_run_state == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    // else return (var->grp[grp].eng_ass_grp_data.pcs_run_state == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
    int grp_idx = 0;
    int match_cnt = 0;
    for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        // return (var->grp[grp].eng_ass_grp_data.pcs_run_state == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
        if(var->grp[grp].eng_ass_grp_data.pcs_run_state == value) match_cnt++;
    }
    return (match_cnt == var->eng_ass_grp_num)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;   
}

static int chk_bms_relay(energy_var_t *var,int grp,int value)
{
    if(value == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.bms_relay_p == ENG_ASS_ACTION_TYPE_INIT || var->grp[grp].eng_ass_grp_data.bms_relay_n == ENG_ASS_ACTION_TYPE_INIT)return ENG_ASS_CONDITION_SKIP;
    else return ((var->grp[grp].eng_ass_grp_data.bms_relay_p && var->grp[grp].eng_ass_grp_data.bms_relay_n) == value)?ENG_ASS_CONDITION_OK:ENG_ASS_CONDITION_NO_MATCH;
}

static void update_pcs_switch_kuaibu(energy_var_t *var,int grp,int value)
{
    int grp_idx = 0;
    for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        var->grp[grp_idx].eng_ass_grp_ctrl.run_state = value;
    }
}

//PCS 开机关机
static void send_cmd_set_pcs_switch_kuaibu(energy_var_t *var,int grp_index,int value)
{
    int grp_idx = 0;
    for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        if (value == 2)
        {
            data_ctrl_dev_action(var, var->grp[grp_idx].eng_ass_grp_cfg.pcs_sn, "kaiji", "TAG_4EAE", 1);
        }
        if (value == 1)
        {
            data_ctrl_dev_action(var, var->grp[grp_idx].eng_ass_grp_cfg.pcs_sn, "daiji", "TAG_4EB3", 1);
        }
        else if (value == 0)
        {
            data_ctrl_dev_action(var, var->grp[grp_idx].eng_ass_grp_cfg.pcs_sn, "guanji", "TAG_4EAF", 1);
        }
        dbg_syslog(LOG_WARNING, "Set grp[%d] pcs run mode=%d", grp_idx, value);
    }
}

//有功率
static void send_cmd_set_pcs_active_power_kuaibu(energy_var_t *var,int grp_index,int value)
{
    int grp_idx = 0;
    for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        data_ctrl_dev_action(var,var->grp[grp_idx].eng_ass_grp_cfg.pcs_sn,"WritePExpect","TAG_4E92",var->grp[grp_idx].eng_ass_grp_ctrl.active_power);
    }
}

//清故障
static void send_cmd_set_pcs_reset_err_kuaibu(energy_var_t *var)
{
    int grp_idx = 0;
    for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
    {
        data_ctrl_dev_action(var,var->grp[grp_idx].eng_ass_grp_cfg.pcs_sn,"ClearError","TAG_4EB0",1);
        dbg_syslog(LOG_WARNING, "Set grp[%d] pcs clear error", grp_idx);
    }

}

static action_and_check_t start_action_chk[] = {
    {"PCS模式=1", update_pcs_switch_kuaibu,                  1, chk_pcs_switch_kuaibu,                  1},
    {"PCS模式=2", update_pcs_switch_kuaibu,                  2, chk_pcs_switch_kuaibu,                  2},
};

static action_and_check_t stop_action_chk[] = {
    {"PCS模式=0", update_pcs_switch_kuaibu,                     0,      chk_pcs_switch_kuaibu,                     0},
};

static action_and_check_t staby_action_chk[] = {
    {"PCS模式=0", update_pcs_switch_kuaibu,                     1,      chk_pcs_switch_kuaibu,                     1},
};

static int protect_action_chk_size[ENG_ASS_ACTION_CHECK_LEVEL_MAX]={0};
//停机todo_list
static action_and_check_t protect_action_chk[][ENG_ASS_ACTION_CHECK_MAX] = {
    //描述
    //检查回调,0:数据比较通过;否则失败
    //检查匹配的参数
    //如果不匹配需要做的事情
    //需要做事情的参数
    {//protection level 1 :清安短期关机
        {"PCS模式", update_pcs_switch_kuaibu,                     0,      chk_pcs_switch_kuaibu,                     0},
    },
    {//protection level 2 :清安长期关机
        {"PCS模式", update_pcs_switch_kuaibu,                     0,      chk_pcs_switch_kuaibu,                     0},       
    },
    {//protection level 3 :清安系统关机,其余关闭操作在联动保护模块执行
        {"PCS模式", update_pcs_switch_kuaibu,                     0,      chk_pcs_switch_kuaibu,                     0},
        //保护联动系统,在这里负责关并网点断路器
        //保护联动系统,在这里负责关UPS
    }
};

static void *ctrl_process_loop_kuaibu(void *param)
{
    energy_var_t *var = ((data_ctrl_thread_var_t *)param)->var;
    eng_ass_grp_t *grp = ((data_ctrl_thread_var_t *)param)->grp;
    int grp_idx = ((void*)grp - (void*)var->grp)/sizeof(eng_ass_grp_t);
    int last_run_state = -1;
    int last_protect_level = ENG_ASS_PROTECT_LEVEL_INIT;
    action_and_check_t *action_steps = NULL;
    int action_steps_max = 0;
    int action_step_idx = 0;
    int last_power[ENG_ASS_GRP_MAX] = {0};
    int last_action_step_idx;
    while (1)
    {  
        sleep(1);
        int protect_level = 0;
        // int protect_level = protect_level_get(var,grp);
        if(var->eng_ass_data->protect_level > protect_level)
            protect_level = var->eng_ass_data->protect_level;
        else if(var->grp[0].eng_ass_grp_ctrl.protect_level > protect_level)
            protect_level = var->grp[0].eng_ass_grp_ctrl.protect_level;
        else if(var->grp[1].eng_ass_grp_ctrl.protect_level > protect_level)
            protect_level = var->grp[1].eng_ass_grp_ctrl.protect_level;
        if(last_protect_level != protect_level)
        {
            last_protect_level = protect_level;
            action_step_idx = 0; //状态变了执行序列从0开始
            action_steps = NULL;
            dbg_syslog(LOG_INFO,"grp[%d] action: protect level %d!",grp_idx,protect_level);
            if(protect_level > ENG_ASS_PROTECT_LEVEL_NONE)
            {
                grp->eng_ass_grp_ctrl.relay = 0;
                send_cmd_set_bms_relay(var,grp_idx,grp->eng_ass_grp_ctrl.relay);
            }
        }
        if(protect_level > ENG_ASS_PROTECT_LEVEL_NONE)
        {
            int protect_level_idx = protect_level - 1;
            action_steps = protect_action_chk[protect_level_idx];
            action_steps_max = protect_action_chk_size[protect_level_idx];
        }
        else {
            if(last_run_state != item_var.runmode)
            {
                last_run_state = item_var.runmode;
                action_step_idx = 0; //状态变了执行序列从0开始
                action_steps = NULL;
                if(item_var.runmode == 1)//待机
                {
                    if(!action_steps)dbg_syslog(LOG_INFO,"grp[%d] action: recv cmd staby!",grp_idx);
                    action_steps = staby_action_chk;
                    action_steps_max = ARRAY_SIZE(staby_action_chk);
                }
                else if(item_var.runmode == 2)//开机
                {
                    if(!action_steps)dbg_syslog(LOG_INFO,"grp[%d] action: recv cmd run!",grp_idx);
                    action_steps = start_action_chk;
                    action_steps_max = ARRAY_SIZE(start_action_chk);
                }
                else                                        //关机
                {
                    if(!action_steps)dbg_syslog(LOG_INFO,"grp[%d] action: recv cmd stop!",grp_idx);
                    action_steps = stop_action_chk;
                    action_steps_max = ARRAY_SIZE(stop_action_chk);
                }
            }
            // grp->eng_ass_grp_ctrl.relay = 1;
        }

        for (grp_idx = 0; grp_idx < var->eng_ass_grp_num; grp_idx++)
        {
            if(var->grp[grp_idx].eng_ass_grp_data.pcs_run_state != var->grp[grp_idx].eng_ass_grp_ctrl.run_state)
            dbg_syslog(LOG_INFO, "pcs[%d] mode real:%d expect:%d", grp_idx, var->grp[grp_idx].eng_ass_grp_data.pcs_run_state,var->grp[grp_idx].eng_ass_grp_ctrl.run_state);
        }
        grp_idx = 0;
        //找到由于一键启动/禁用/保护需要做的事情
        if(action_steps && action_step_idx < action_steps_max){
            action_and_check_t *step = &action_steps[action_step_idx];
            step->update_cb(var,grp_idx,step->update_param);
            dbg_syslog(LOG_INFO,"waiting step index[%d]:%s!",action_step_idx,step->desc);
            if(cond_wait_signal(grp) == 0)//等待数据变化
            {
                int ret = step->condition_cb(var,grp_idx,step->condition_param);
                //That callback of condition return zero means this check passed and to do next step.
                if(ret == ENG_ASS_CONDITION_OK || ret == ENG_ASS_CONDITION_SKIP) 
                {
                    if(ret == ENG_ASS_CONDITION_SKIP)
                        dbg_syslog(LOG_INFO,"grp[%d] ignore step,invalid feedback data:%s [%d]!",grp_idx,step->desc,action_step_idx);
                    action_step_idx++;
                    dbg_syslog(LOG_INFO,"grp[%d] go to step:%s [%d]!",grp_idx,step->desc,action_step_idx);
                }
            }
        }
        int changed = 0;
        if(action_step_idx >= action_steps_max && action_step_idx != last_action_step_idx)
        {
            last_action_step_idx = action_step_idx;
            changed = 1;
        }

        //检查PCS 运行状态
        if(chk_pcs_switch_kuaibu(var,grp_idx,grp->eng_ass_grp_ctrl.run_state) == ENG_ASS_CONDITION_NO_MATCH)
        {
            send_cmd_set_pcs_switch_kuaibu(var,grp_idx,grp->eng_ass_grp_ctrl.run_state);
        }

        //持续检查BMS主接触器
        if(chk_bms_relay(var,grp_idx,grp->eng_ass_grp_ctrl.relay) == ENG_ASS_CONDITION_NO_MATCH)
        {
            send_cmd_set_bms_relay(var,grp_idx,grp->eng_ass_grp_ctrl.relay);
        }

        if(var->grp[0].eng_ass_grp_ctrl.active_power != last_power[0]  ||  var->grp[0].eng_ass_grp_ctrl.active_power != last_power[1] || changed)
        {
            dbg_syslog(LOG_INFO,"write power:%d to each pcs",var->grp[0].eng_ass_grp_ctrl.active_power);
            last_power[0] = var->grp[0].eng_ass_grp_ctrl.active_power;
            last_power[1] = var->grp[0].eng_ass_grp_ctrl.active_power;
            send_cmd_set_pcs_active_power_kuaibu(var,grp_idx,0);
        }
    }
    return NULL;
}

static int protect_action_chk_init(void)
{
    for (size_t i = 0; i < ARRAY_SIZE(protect_action_chk) ; i++)
    {
        for (size_t m = 0; m < ENG_ASS_ACTION_CHECK_MAX; m++)
        {
            if(!protect_action_chk[i][m].desc){//如果没有表述当作结束
                if(protect_action_chk_size[i] == 0)
                {
                    protect_action_chk_size[i] = m;
                    break;
                }
            }
        }
    }
    return 0;
}

// TODO 初始化静态的TAG
static void data_col_tag_map_init(tag_info_t *tag_info,size_t size)
{
    int tag_index = 0;
    for (tag_index = 0; tag_index < size; tag_index++)
    {
        char *tag = tag_info[tag_index].tag;
        int ret = hash_intptr_addptr(&tag_map_hash, tag, strlen(tag), &tag_info[tag_index]);
        if (ret < 0)
        {
            dbg_syslog(LOG_ERR, "hash_intptr_addptr failed, key: %s", tag_info[tag_index].tag);
            return;
        }
        dbg_syslog(LOG_INFO, "Add success: %s\n", tag_info[tag_index].tag);
    }
}

static int kuaibu_abs_init(energy_var_t *var,void *param)
{
    int grp_idx = 0;
    //初始化tag映射链表
    data_col_tag_map_init(tag_info_table_stack,ARRAY_SIZE(tag_info_table_stack));
    //保护动作动态初始化
    protect_action_chk_init();
    grp_idx = 0;
    eng_ass_grp_t *grp = &var->grp[grp_idx];
    threads_var[grp_idx].var = var;
    threads_var[grp_idx].grp = grp;
    pthread_cond_init(&grp->action_cond,NULL);
    pthread_mutex_init(&grp->action_mutex,NULL);
    /* 创建一个单独的线程, 专用于执行aiot_mqtt_process, 它会自动发送心跳保活, 以及重发QoS1的未应答报文 */
    int res = pthread_create(&grp->action_thread, NULL, ctrl_process_loop_kuaibu, &threads_var[grp_idx]);
    if (res < 0) {
        dbg_syslog(LOG_WARNING, "failed to created pthread for data process %s\n", strerror(errno));
        return -1;
    }
    return 0;
}

static void kuaibu_abs_set_runmode(energy_var_t *var,int mode)
{
    item_var.runmode = mode;
}

static void kuaibu_abs_set_bms_relay(energy_var_t *var,int state)
{
    var->grp[0].eng_ass_grp_ctrl.relay = var->eng_ass_data->expect_relay_state;
}

static void kuaibu_set_total_power(energy_var_t *var,int power,int is_wggl)
{
    int grp_idx = 0;
    for(grp_idx = 0;grp_idx<var->eng_ass_grp_num;grp_idx++)
    {
        var->grp[grp_idx].eng_ass_grp_ctrl.active_power = data_grp_get_assign_power(var,grp_idx,power);
    }
}

static void kuaibu_abs_set_data_event_cb(energy_var_t *var,data_event_cb_t cb)
{
    item_var.data_event_cb = cb;
}

static void kuaibu_on_dev_data_updata(energy_var_t *var,void *json_ptr,int grp_idx) 
{
    int i = 0;
    int tag_num = 0;
    cJSON *sub = json_ptr;
    tag_num = cJSON_GetArraySize(sub);
    void *ptr = &var->grp[grp_idx].eng_ass_grp_data;
    for (i = 0; i < tag_num; i++)
    {
        cJSON *item = cJSON_GetArrayItem(sub, i);
        if (item == NULL)
        {
            dbg_syslog(LOG_ERR, "cJSON_GetArrayItem failed");
            continue;
        }
        if (item->type != cJSON_Number)
        {
            continue;
        }

        tag_info_t *info_p = NULL;
        if (hash_intptr_findptr(tag_map_hash, item->string, strlen(item->string), (void **)&info_p) < 0)
        {
            continue;
        }
        
        switch (info_p->type)
        {
        case E_TAG_INT:
            *((int *)(ptr + info_p->member_ofs)) = item->valueint;
            break;
        case E_TAG_FLOAT:
            *((float *)(ptr + info_p->member_ofs)) = item->valuedouble;
            break;
        default:
            dbg_syslog(LOG_ERR, "unsupported this type on tag:%s", item->string);
            break;
        }
        // if(strcmp("TAG_9D77",item->string) == 0 || strcmp("TAG_9D78",item->string) == 0 || strcmp("TAG_9C80",item->string) == 0)dbg_syslog(LOG_INFO, "DEBUG tag:%s = %f", item->string,*((float *)(ptr + info_p->member_ofs)));
    }
    if(item_var.data_event_cb)item_var.data_event_cb(var,NULL);
}

//使用默认的函数处理
static const abstract_item_t item _init= {
    .name = "kuaibu",
    .alias = "xxx",
    .init = kuaibu_abs_init,
    .set_runmode = kuaibu_abs_set_runmode,
    .set_total_power = kuaibu_set_total_power,
    .set_data_event_cb = kuaibu_abs_set_data_event_cb,
    .clr_pcs_error = send_cmd_set_pcs_reset_err_kuaibu,
    .on_dev_data_updata = kuaibu_on_dev_data_updata,
    .set_bms_relay = kuaibu_abs_set_bms_relay,
};

//MODULE_DECLARE(item);