#include <math.h>
#include <errno.h>
#include <syslog.h>
#include "define.h"
#include "sys/param.h"
#include "assert.h"
#include "pthread.h"
#include "../common.h"
#include "../mac_mul/raw_sock.h"
#include "../mac_mul/mac_protocol.h"
#include "discover.h"
#include "dy_utils/hash_intptr.h"
#include "collector-api.h"
#include "jsonct.h"

// char g_send_message[1024] = {0};//这个帧固定的可以不变一直用 免得一直拼 下一级做了校验这一级直接当数据用
// int g_message_len = 0;
hash_intptr_t *g_discover_hash; 
discover_message_info *g_discover_message_info;
RAW_SOCK *g_raw = NULL;


static fire_cb g_fire_cb = NULL;

struct total_info_t 
{
    int num;
    int fire;
    float pcs_val;    // 其他柜总功率
    float pcs_a_val;    // 其他柜A相功率 
    float pcs_b_val;    // 其他柜B相功率
    float pcs_c_val;    // 其他柜C相功率
    int ex_acc_val; // 其他柜K3之和
    float pcs_low_power; // 低压侧功率
    int low_num;    // 低压侧柜子数量
    int Lkvl;        // 低压侧柜子k3之和
    char self_LPID[64];  // 自己的低压侧并网点ID
}total_info;
pthread_rwlock_t total_rwlock = PTHREAD_RWLOCK_INITIALIZER;
pthread_rwlock_t setdata_rwlock = PTHREAD_RWLOCK_INITIALIZER;


int package_and_send_discover(RAW_SOCK *raw)
{
    if (g_discover_message_info == NULL)
    {
        return -1;
    }
    pthread_rwlock_rdlock(&setdata_rwlock);
    g_discover_message_info->fire = dev_get_dev_tag_int(DEV_NO_EMS, FIRE);
    int ret = send_protocol_data(raw,(char *)g_discover_message_info,sizeof(discover_message_info));
    pthread_rwlock_unlock(&setdata_rwlock);
    return ret;
}

void write_fire_and_send_now(int fireState)
{
    if ((g_raw==NULL)||(g_discover_message_info==NULL))
        return;
    pthread_rwlock_wrlock(&setdata_rwlock);
    g_discover_message_info->fire = fireState;
    pthread_rwlock_unlock(&setdata_rwlock);

    pthread_rwlock_rdlock(&setdata_rwlock);
    send_protocol_data(g_raw,(char *)g_discover_message_info,sizeof(discover_message_info));
    pthread_rwlock_unlock(&setdata_rwlock);
}

void write_self_pcs_val_and_k3(float pcs_val,int k3, char *ID)
{
    if (g_discover_message_info == NULL)
    {
        return;
    }
    pthread_rwlock_wrlock(&setdata_rwlock);
    g_discover_message_info->pcs_val = pcs_val;
    g_discover_message_info->K3 = k3;
    strncpy(g_discover_message_info->LPID, ID, 63);
    g_discover_message_info->LPID[63] = '\0';
    pthread_rwlock_unlock(&setdata_rwlock);
}

void write_self_pcs_status(int status)
{
    if (g_discover_message_info == NULL)
    {
        return;
    }
    int s = status + dev_get_dev_tag_int(DEV_NO_EMS, SYSTEM_STATUS) +
            dev_get_dev_tag_int(DEV_NO_EMS, PROHIBITE_CHARGE) +
            dev_get_dev_tag_int(DEV_NO_EMS, PROHIBITE_DISCHARGE);
    s += dev_get_dev_tag_int(DEV_NO_EMS, CONTROL_MODE) == 1 ? 0 : 1;
    pthread_rwlock_wrlock(&setdata_rwlock);
    g_discover_message_info->status = s;
    pthread_rwlock_unlock(&setdata_rwlock);
}

void write_self_pcs_abc_val(float pcs_a_val, float pcs_b_val, float pcs_c_val)
{
    if (g_discover_message_info == NULL)
    {
        return;
    }
    pthread_rwlock_wrlock(&setdata_rwlock);
    g_discover_message_info->pcs_a_val = pcs_a_val;
    g_discover_message_info->pcs_b_val = pcs_b_val;
    g_discover_message_info->pcs_c_val = pcs_c_val;
    pthread_rwlock_unlock(&setdata_rwlock);
}

int send_message_init(discover_init_config *init_message)
{
    if (init_message->sn==NULL)
    {
        return -1;
    }
    g_discover_message_info = calloc(1,sizeof(discover_message_info));
    local_strlcpy(g_discover_message_info->sn,init_message->sn,sizeof(g_discover_message_info->sn));
    g_discover_message_info->capacity = init_message->capacity;
    g_discover_message_info->power = init_message->power;
    g_discover_message_info->K3     = init_message->K3;
    g_discover_message_info->status = 0;
    strncpy(g_discover_message_info->LPID, get_cabinet_info()->cnt_id_l, 64);
    g_discover_message_info->LPID[63] = '\0';
    return 0;
}

int detail_discover_data(char *data,int len)
{
    discover_message_info *get_discover_info = (discover_message_info *)data;
    discover_message_info *discover_info = NULL;
    if (hash_intptr_findptr(g_discover_hash,get_discover_info->sn,strlen(get_discover_info->sn), (void **)&discover_info) < 0)
    {
        discover_info = calloc(sizeof(discover_message_info)+sizeof(var_info),1);
        memcpy(discover_info,get_discover_info,sizeof(discover_message_info));
        discover_info->var_info_t[0].timestamp =  time(NULL);

        int ret = hash_intptr_addptr(&g_discover_hash,get_discover_info->sn,strlen(get_discover_info->sn),discover_info);
        if (ret == 0)
        {
            proto_syslog(LOG_NOTICE, "find new dev :%s!",get_discover_info->sn);
        }
    }
    else
    {
        memcpy(discover_info,get_discover_info,sizeof(discover_message_info));
        discover_info->var_info_t[0].timestamp =  time(NULL);
    }
    return 0;
}

static int iter_func(struct hash_intptr *hash_p, int unknow, void *param)
{
    struct total_info_t *total_info=param;
    discover_message_info *discover_info_dev = hash_p->hh_ptr;
    if ((time(NULL) - discover_info_dev->var_info_t[0].timestamp)<AVLID_TIME)
    {
        ems_syslog(LOG_ERR,"take sn :%s fire:%d pcs_val:%.2f a:%.2f b:%.2f c:%.2f valid!!",
            discover_info_dev->sn, discover_info_dev->fire,
            discover_info_dev->pcs_val,
            discover_info_dev->pcs_a_val,
            discover_info_dev->pcs_b_val,
            discover_info_dev->pcs_c_val);
        total_info->num++;
        if (discover_info_dev->fire)
        {
            total_info->fire++;
        }
        // if(discover_info_dev->status == 0) //不使用这个判断，因为多柜均衡算法占时没有使用这个字段，如果打开其他柜禁充禁放时候status字段会为1,导致pcs_val和ex_acc_val不准
        {
            total_info->pcs_val += discover_info_dev->pcs_val;
            total_info->pcs_a_val += discover_info_dev->pcs_a_val;
            total_info->pcs_b_val += discover_info_dev->pcs_b_val;
            total_info->pcs_c_val += discover_info_dev->pcs_c_val;
        }
        total_info->ex_acc_val += discover_info_dev->K3;
        if(0 == strcmp(discover_info_dev->LPID, get_cabinet_info()->cnt_id_l))
        {
            total_info->pcs_low_power += discover_info_dev->pcs_val;
            total_info->low_num += 1;
            total_info->Lkvl += discover_info_dev->K3;
        }
    }
    else
    {
        ems_syslog(LOG_INFO,"take sn :%s fire:%d  this value is invalid [time now:%ld -> old:%ld]!!",discover_info_dev->sn,discover_info_dev->fire,time(NULL),discover_info_dev->var_info_t[0].timestamp);
    }
    return 0;
}

void register_fire_cb(fire_cb fire_cb_t)
{
    if (fire_cb_t!=NULL)
    {
        g_fire_cb = fire_cb_t;
    }
}

float get_total_pcs_val() //返回其他PCS总有功功率总和值不包括自己
{
    
    pthread_rwlock_rdlock(&total_rwlock);
    float pcs_val = total_info.pcs_val;
    pthread_rwlock_unlock(&total_rwlock);
    return pcs_val;
}

float get_total_pcs_a_val()
{
    
    pthread_rwlock_rdlock(&total_rwlock);
    float pcs_a_val = total_info.pcs_a_val;
    pthread_rwlock_unlock(&total_rwlock);
    return pcs_a_val;
}

float get_total_pcs_b_val()
{
    
    pthread_rwlock_rdlock(&total_rwlock);
    float pcs_b_val = total_info.pcs_b_val;
    pthread_rwlock_unlock(&total_rwlock);
    return pcs_b_val;
}

float get_total_pcs_c_val()
{
    
    pthread_rwlock_rdlock(&total_rwlock);
    float pcs_c_val = total_info.pcs_c_val;
    pthread_rwlock_unlock(&total_rwlock);
    return pcs_c_val;
}

// 其他PCS的功率和K3值总和
void get_extern_agv_pcs_val(float* ex_pcs_val, int * ex_acc_val) 
{
    pthread_rwlock_rdlock(&total_rwlock);
    *ex_pcs_val = total_info.pcs_val;
    *ex_acc_val = total_info.ex_acc_val;
    pthread_rwlock_unlock(&total_rwlock);
}

void get_total_low_point_info(double *pcs_power, int *ems_num, int *kvl)
{
    int num = 0;
    pthread_rwlock_rdlock(&total_rwlock);
    num=total_info.low_num;
    *pcs_power = total_info.pcs_low_power;
    *kvl = total_info.Lkvl;
    pthread_rwlock_unlock(&total_rwlock);
    ems_syslog(LOG_INFO,"get discover num :%d!!",num+1);
    *ems_num = num+1;
}

static int get_ems_sn(struct hash_intptr* hash_p, int unknow, void* param)
{
    if (param == NULL) {
        return -1;
    }
    char sn[64] = {0};
    struct lnxall_buff* buf = param;
    discover_message_info *discover_info_dev = hash_p->hh_ptr;
    if ((time(NULL) - discover_info_dev->var_info_t[0].timestamp)<AVLID_TIME && strcmp(discover_info_dev->sn, g_discover_message_info->sn) != 0)
    {
        int len = snprintf(sn, sizeof(sn), "\"%s\",", discover_info_dev->sn);
        lbuff_append(buf, sn, len);
    }
    return 0;
}

int get_all_ems_sn(struct lnxall_buff* buf)
{
    if (buf == NULL) {
        return -1;
    }
    char sn[64] = {0};
    int len = snprintf(sn, sizeof(sn), "\"%s\",", g_discover_message_info->sn);
    lbuff_append(buf, sn, len);
    hash_intptr_iter(&g_discover_hash, get_ems_sn, buf);
    return 0;
}

void get_total_info()
{
    struct total_info_t total_info_h={0};
    hash_intptr_iter(&g_discover_hash,iter_func,&total_info_h);
    pthread_rwlock_wrlock(&total_rwlock);
    memcpy(&total_info,&total_info_h,sizeof(total_info));
    pthread_rwlock_unlock(&total_rwlock);

    if (g_fire_cb!=NULL) //消防的紧急处理
    {
        g_fire_cb(total_info_h.fire);
    }
}

int get_discover_dev_num()//返回数量包括自己
{
    int num = 0;
    pthread_rwlock_rdlock(&total_rwlock);
    num=total_info.num;
    pthread_rwlock_unlock(&total_rwlock);
    return num+1;
}
long long get_timestamp(void)
{
    long long tmp;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    tmp = tv.tv_sec;
    tmp = tmp * 1000;
    tmp = tmp + (tv.tv_usec / 1000);

    return tmp;
}

static void *discover_task(void *arg)
{
    extern char *get_cnt_id(void);
    RAW_SOCK *raw = NULL;
RETURY:
    if ((raw = protocol_Init_with_group(get_pcs_ctrl_var()->net_node,  get_cnt_id(), DISCOVER_CHANNEL_NAME))==NULL)
    {
        sleep(10);
        goto RETURY;
    }
    g_raw = raw;
    time_t now;
    long long int send_message_time = 0;
    char message[1024]= {0};
    int len = 0;
    while (1)
    {
        memset(message,0,sizeof(message));
        len = 0;
        if((read_protocol_data(raw,message,&len)==0)&&(len > 0)) //读取广播包
        {
            detail_discover_data(message,len);
        }
        get_total_info();
        now = time(NULL);
        if (check_timeout_msecond(now, &send_message_time, 1)) //定时广播自己的信息
        {
            ems_syslog(LOG_INFO,"send discover msg time:%ld",now);
            package_and_send_discover(raw);
        }

    }
    return NULL;
}





void discover_init(discover_init_config *init_message)
{
    pthread_t tid=PTHREAD_NULL;
    if((init_message==NULL)||(send_message_init(init_message)!=0))
    {
        ems_syslog(LOG_ERR,"The data is incomplete!!");
        return;
    }
    if(pthread_create(&tid,NULL,discover_task,NULL)!=0)
    {
        ems_syslog(LOG_ERR,"discover init error!!");
    }
    else
    {
        pthread_setname_np(tid, "discoverTask");
    }
        
}
