#include "common.h"

static void process_data(uint8_t *data, size_t data_len, le_advertising_info *info)
{
    if (data[0] == EIR_NAME_SHORT || data[0] == EIR_NAME_COMPLETE)
    {
        size_t name_len = data_len - 1;
        char *name = malloc(name_len + 1);

        memset(name, 0, name_len + 1);
        memcpy(name, &data[1], name_len);

        printf("name=%s\n", name);
        free(name);
    }
    else if (data[0] == EIR_FLAGS)
    {
        return;
        printf("Flag type: len=%d\n", data_len);
        int i;
        for (i = 1; i < data_len;)
        {
            printf("0x%0X ", data[i]);
            i++;
            if (i % 32 == 0)
                printf("\n");
            else if (i % 8 == 0)
                printf("\t");
        }
        printf("\n");
    }
    else if (data[0] == EIR_MANUFACTURE_SPECIFIC)
    {
        return;
        printf("Manufacture specific type: len=%d\n", data_len);
        int i;
        for (i = 1; i < data_len; i++)
        {
            printf("0x%0X ", data[i]);
            i++;
            if (i % 32 == 0)
                printf("\n");
            else if (i % 8 == 0)
                printf("\t");
        }
        printf("\n");
    }
    else
    {
        return;
        printf("Unknown type: type=%X\n", data[0]);
    }
}

static void scanner_callback(int fd, uint32_t events, void *user_data)
{
    unsigned char buf[512];
    ssize_t len = 0, i;
    evt_le_meta_event *meta = NULL;
    le_advertising_info *info = NULL;
    int current_index = 0;
    int data_error = 0;
    int rssi;

    if (events & (EPOLLERR | EPOLLHUP))
    {
        close(fd);
        mainloop_remove_fd(fd);
        return;
    }

    len = read(fd, buf, sizeof(buf) - len);
    if (len < 0)
    {
        if (errno == EAGAIN || errno == EINTR)
            return;

        fprintf(stderr, "Read from device descriptor failed\n");
        mainloop_remove_fd(fd);
        return;
    }
    if (0)
    {
        char print_buf[4096];
        format_hex(buf, len, print_buf, 4096);
        printf("scanner rcv data:\n%s\n", print_buf);
    }

process_packet:
    meta = (void *)(buf + (1 + HCI_EVENT_HDR_SIZE));
    len -= (1 + HCI_EVENT_HDR_SIZE);
    if (meta->subevent != EVT_LE_ADVERTISING_REPORT)
    {
        return;
    }
    info = (le_advertising_info *)(meta->data + 1);
    if (info->length == 0)
    {
        return;
    }
    // printf("buf:%p info->data:%p info->len:%d \n", buf, info->data, info->length);
    rssi = info->data[info->length];
    rssi = (256 - rssi) * -1;
    char addr[18];

    switch (info->bdaddr_type)
    {
    case LE_PUBLIC_ADDRESS:
        printf("public ");
        break;
    case LE_RANDOM_ADDRESS:
        printf("random ");
        break;
    default:
        printf("unkonwn ");
    }
    ba2str(&info->bdaddr, addr);
    printf("addr=%s RSSI:%d\n", addr, rssi);

    while (!data_error && current_index < info->length)
    {
        size_t data_len = info->data[current_index];

        if (data_len + 1 > info->length)
        {
            printf("EIR data length is longer than EIR packet length. %d + 1 > %d", data_len, info->length);
            data_error = 1;
        }
        else
        {
            process_data(info->data + current_index + 1, data_len, info);
            //get_rssi(&info->bdaddr, current_hci_state);
            current_index += data_len + 1;
        }
    }
    printf("\n=============================================\n");
}

void start_hci_scan(ble_dev_t *current_hci_state)
{
    hci_le_set_scan_enable(current_hci_state->scan_fd, 0x00, 0x00, 10000);
    if (hci_le_set_scan_parameters(current_hci_state->scan_fd, 0x00, htobs(0x0010), htobs(0x0010), 0x00, 0x00, 10000) < 0)
    {
        return;
    }

    if (hci_le_set_scan_enable(current_hci_state->scan_fd, 0x01, 1, 10000) < 0)
    {
        return;
    }

    current_hci_state->state = HCI_STATE_SCANNING;

    // Create and set the new filter
    struct hci_filter new_filter;

    hci_filter_clear(&new_filter);
    hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter);
    hci_filter_set_event(EVT_LE_META_EVENT, &new_filter);

    if (setsockopt(current_hci_state->scan_fd, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0)
    {
        printf("set filter failed\n");
        return;
    }

    current_hci_state->state = HCI_STATE_FILTERING;
    mainloop_add_fd(current_hci_state->scan_fd, EPOLLIN, scanner_callback, current_hci_state, NULL);
}
