#include "common.h"



static void read_version_complete(uint16_t op, uint16_t id, uint8_t status, uint16_t length,
                                  const void *param)
{
    const struct mgmt_rp_read_version *rp = param;

    printf("read version complete\n");

    if (status != MGMT_STATUS_SUCCESS)
    {
        printf("Failed to read version information: %s (0x%02x)",
               mgmt_errstr(status), status);
        return;
    }

    if (length < sizeof(*rp))
    {
        printf("Wrong size of read version response");
        return;
    }

    uint8_t mgmt_version = rp->version;
    uint8_t mgmt_revision = btohs(rp->revision);

    printf("Bluetooth management interface %d.%d initialized\n",
           mgmt_version, mgmt_revision);
}

static bool power_up_down(struct mgmt *mgmt, uint8_t val)
{
    int index;


    if (send_cmd(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val, setting_rsp) == 0)
    {
        printf("falied");
        return false;
    }
    return true;
}

static bool activate_controller(int fd, struct hci_dev_info *di)
{
    if (!hci_test_bit(HCI_UP, &di->flags))
    {
        char addr[18];

        ba2str(&di->bdaddr, addr);
        printf("Activating controller %s\n", addr);

        if (ioctl(fd, HCIDEVUP, di->dev_id) < 0)
        {
            if (errno != EALREADY)
            {
                perror("Failed to bring up HCI device");
                return false;
            }
        }
    }
    return true;
}

static bool probe_controllers(ble_var_t *var)
{
    struct hci_dev_list_req *dl;
    struct hci_dev_req *dr;
    bool result;
    int fd, i;

    fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
    if (fd < 0)
    {
        perror("Failed to open raw HCI socket");
        return false;
    }

    dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
    if (!dl)
    {
        perror("Failed allocate HCI device request memory");
        close(fd);
        return false;
    }

    dl->dev_num = HCI_MAX_DEV;
    dr = dl->dev_req;

    if (ioctl(fd, HCIGETDEVLIST, (void *)dl) < 0)
    {
        perror("Failed to get HCI device list");
        result = false;
        goto done;
    }

    result = true;

    var->ble_cnt = dl->dev_num;
    if (var->ble_cnt > 0)
    {
        var->dev = calloc(var->ble_cnt, sizeof(ble_dev_t));
        for (i = 0; i < dl->dev_num; i++)
        {
            struct hci_dev_info *di = NULL;

            di = calloc(1, sizeof(struct hci_dev_info));
            di->dev_id = (dr + i)->dev_id;
            var->dev[i].dev_id = di->dev_id;
            // TODO dont support oepn the given dev_id with HCI_CHANNEL_CONTROL
            // it will cause bind fail
            //var->dev[i].mgmt = mgmt_new_by_id(di->dev_id);
            // var->dev[i].mgmt = mgmt_new_default();
            var->dev[i].scan_fd = hci_open_dev(di->dev_id);

            // Set fd non-blocking
            int on = 1;
            if (ioctl(var->dev[i].scan_fd, FIONBIO, (char *)&on) < 0)
            {
                printf("set nonblock failed");
            }

            if (ioctl(fd, HCIGETDEVINFO, (void *)di) < 0)
            {
                printf("get dev info failed");
                free(di);
                continue;
            }
            var->dev[i].di = di;
            activate_controller(fd, di);
        }
    }

done:
    free(dl);
    close(fd);
    return result;
}

static bool ble_init(ble_var_t *var)
{
    bool ret = true;
    probe_controllers(var);

    return ret;
}

static bool ble_load_cfg(ble_var_t *var)
{
    // struct mgmt *mgmt = var->dev[0].mgmt;

    // power_up_down(mgmt, 0);
    // power_up_down(mgmt, 1);
    // send_cmd(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL, read_version_complete);

    // start_hci_scan(&var->dev[0]);
    // E0:51:24:CC:53:A3
    //l2cap_le_att_connect(-1, "6A:1E:28:ED:81:DF", BDADDR_LE_RANDOM, BT_SECURITY_LOW, 256);
    //l2cap_le_att_connect(-1, "E0:51:24:CC:53:A3", BDADDR_LE_PUBLIC, BT_SECURITY_LOW, 256);

    // l2cap_le_att_listen_and_accept(-1, BT_SECURITY_LOW, BDADDR_LE_PUBLIC, 256);

    // int l2cap_le_att_advertise(int dev_id, uint32_t flags, uuid_t UUIDs[], int uuid_cnt,
    //    uint8_t *adv_data, uint8_t adv_len,
    //    uint8_t *scan_rsp, uint8_t scan_rsp_len,
    //    uint16_t timeout, uint16_t duration)
static const uint8_t set_adv_data_test2[] = {
	0x07,				/* adv data len */
	0x06,				/* AD len */
	0x08,				/* AD type: shortened local name */
	0x74, 0x65, 0x73, 0x74, 0x32,	/* "test2" */
	/* padding */
};
    l2cap_le_att_advertise(-1, MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LOCAL_NAME | MGMT_ADV_FLAG_APPEARANCE,
                           NULL, 0, set_adv_data_test2, sizeof(set_adv_data_test2), NULL, 0, 0, 0, 1);
}

static void *event_loop(void *param)
{
    printf("main_loop run\n");
    while (true)
    {
        mainloop_run();
        printf("fetal error");
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    ble_var_t var = {0};
    pthread_t thread_mainloop;

    openlog("BLE", LOG_PID, LOG_DAEMON);
    memset(&var, 0, sizeof(var));

    mainloop_init();
    //ble_init(&var);
    pthread_create(&thread_mainloop, NULL, event_loop, (void *)&var);

    ble_load_cfg(&var);

    pthread_join(thread_mainloop, NULL);
    printf("exit ");
}
