#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "mac_protocol.h"
#include "raw_sock.h"
#include "../common.h"

#define MAX_PROTO_DATA_LE 1400
int send_protocol_data(RAW_SOCK *raw,char *data,int len)
{
    if(raw == NULL) return -1;
    // protocol_potocol protocol_potocol_t={.protocolType=1,.data};
    char alldata[RAW_PACKET_LEN_MAX-sizeof(ETH_HEADER)] = {0};
    if(len>MAX_PROTO_DATA_LE) len = MAX_PROTO_DATA_LE;
    int index = 0;
    alldata[index++] = 0; //总长度
    strcpy((char *)&alldata[index],raw->channel_name);
    index += strlen(raw->channel_name);
    memset(&alldata[index],0xff,40);//简单的填充FF保证长度
    index+=40;
    alldata[index++] = len; //data长度
    memcpy(&alldata[index],data,len);
    index+=len;
    alldata[0] = index-1;
    alldata[index] = csum((unsigned char *)&alldata[0],index);
    index++;
    proto_syslog_hex(LOG_DEBUG,alldata,index,"mac_proto_send:");
    return send_data_frame(raw,alldata,index);
}

int check_data_and_get(RAW_SOCK *raw,char *dist_data,int *len)
{   
    int ret = ERROR;
    if(raw == NULL || dist_data == NULL || len == NULL) return ret;
    if ((raw->len > 46)&&(strstr(raw->rcv_buffer + sizeof(ETH_HEADER),raw->channel_name)))
    {
        int sum0, sum1;
        proto_syslog(LOG_INFO,"channel :%s check protocol head success len:%d!\n",raw->channel_name,raw->len);
        proto_syslog_hex(LOG_DEBUG,raw->rcv_buffer,raw->len,"[%s] recv:",raw->channel_name);
        // printf("data:");
        // for (size_t i = 0; i < raw->len; i++)
        // {
        //     printf("%02x",raw->rcv_buffer[i]);
        // }
        // printf("\n");
        
        int recv_data_len = raw->len - sizeof(ETH_HEADER);
        char *pt = raw->rcv_buffer + sizeof(ETH_HEADER);
        sum0 = (int) pt[0];
        sum0 = (sum0 & 0xff) + 2;
        if(sum0 != recv_data_len)
        {
            proto_syslog(LOG_ERR,"check len error :pt[0]+2:%d recv_len :%d\n",pt[0]+2,recv_data_len);
            return ret;
        }

        sum0 = (int) csum((unsigned char *)pt, pt[0] + 1);
        sum0 &= 0xff;
        sum1 = (int) pt[pt[0] + 1];
        sum1 &= 0xff;
        if(sum0 != sum1) {
            proto_syslog(LOG_ERR,"check csum error: %02x -> %02x", sum0, sum1);
            return ret;
        }
        int data_len = (int)(pt[40 + strlen(raw->channel_name) + 1] & 0xff);
        if (data_len <= 0 || data_len > MAX_PROTO_DATA_LE) {
            proto_syslog(LOG_ERR, "invalid data len: %d\n", data_len);
            return ret;
        }
        size_t name_len = strlen(raw->channel_name);
        size_t header_offset = 40 + name_len + 1 + 1;
        if (header_offset + data_len > (size_t)recv_data_len) {
            proto_syslog(LOG_ERR, "data len out of range\n");
            return ret;
        }
        *len = data_len;
        memcpy(dist_data, pt + header_offset, data_len);
        proto_syslog_hex(LOG_DEBUG,dist_data,*len,"[%s] data_get:",raw->channel_name);
        // printf("get data:");
        // for (size_t i = 0; i < *len; i++)
        // {
        //     printf("%02x",dist_data[i]);
        // }
        // printf("\n");
        ret = OK;
    }
    // else
    // {
    //     printf("channel :%s check protocol head error len:%d!\n",raw->channel_name,raw->len);
    //     printf("data:");
    //     for (size_t i = 0; i < raw->len; i++)
    //     {
    //         printf("%02x",raw->rcv_buffer[i]);
    //     }
    //     printf("\n");
    // }
    return ret  ;  
}

int read_protocol_data(RAW_SOCK *raw,char *dist_data,int *len)
{
    if(raw == NULL || dist_data == NULL || len == NULL) return -1;
    if(raw_data_recv(raw) != OK || raw->len <= 0)
    {
        // proto_syslog(LOG_INFO,"get data timeout!\n");
        return ERROR;
    }
    if(check_data_and_get(raw,dist_data,len) != OK)
    {
        proto_syslog(LOG_DEBUG,"analysis data error!\n");
        return ERROR;
    }
    return OK;
}

RAW_SOCK *protocol_Init(char *ifname,char*channel_name)
{
    return raw_config_init(ifname,channel_name);
}

RAW_SOCK *protocol_Init_with_group(char *ifname, const char *group, const char *channel_name)
{
    char ch_name[64] = {0};

    if (group == NULL)
    {
        return raw_config_init(ifname, ch_name);
    }
    //
    if ((strlen(group) + strlen(channel_name)) >= (sizeof(ch_name) - 1))
    {
        proto_syslog(LOG_ERR, "protocol_Init_with_group parameter too long,%s.%s", group, channel_name);
        return NULL;
    }
    else
    {
        snprintf(ch_name, sizeof(ch_name), "%s-%s", group, channel_name);
        return raw_config_init(ifname, ch_name);
    }
}
