#include <string.h>

#include "hc_config.h"
#include "omw_dbg.h"
#include "omw_svc.h"

#ifdef OMW_BLE_HOST_V0
#include "hci_core.h"
#include "ll.h"

#include "ll_conn.h"

#ifdef CONFIG_BT_SMP
#include "smp.h"
#endif

#define OMW_DEFT_ADV_INTLV_MIN BT_GAP_ADV_SLOW_INT_MIN
#define OMW_DEFT_ADV_INTLV_MAX BT_GAP_ADV_SLOW_INT_MIN
#endif

#ifdef OMW_BLE_HOST_V2
#include "ble_gap.h"
#define OMW_DEFT_ADV_INTLV_MIN BLE_GAP_ADV_FAST_INTERVAL2_MIN
#define OMW_DEFT_ADV_INTLV_MAX BLE_GAP_ADV_FAST_INTERVAL2_MAX
#endif

// #ifdef  OMW_SVC_ERR_CHK
#define OMW_SVC_SET_STARTED_FLAG() (omw_svc_started = 1)
#define OMW_SVC_CLR_STARTED_FLAG() (omw_svc_started = 0)
#define OMW_SVC_CHK_STARTED()  ({if (omw_svc_started) return -1;})
#define OMW_SVC_CHK_CLR_STARTED()  ({if (!omw_svc_started) return; OMW_SVC_CLR_STARTED_FLAG();})
// #define OMW_SVC_CHK_ADV_INITD() ({if (omw_svc_adv_inited != OMW_SVC_INIT_MASK) return -2;})

//flag for adv/scan started or not
static uint8_t omw_svc_started;
// #else
// #define OMW_SVC_CHK_STARTED()
// // #define OMW_SVC_CHK_ADV_INITD()
// #endif

#ifdef CONFIG_BT_CENTRAL
uint8_t omw_cur_mode;
#endif

uint8_t tx_enabled;
uint8_t omw_svc_num;
struct bt_le_conn_param ble_conn_param;				//zhq  note: 

// omw_svc_info_t * g_main_svc;

//BT_GAP_ADV_FAST_INT_MIN_2
// uint16_t omw_adv_intlv_min;
//BT_GAP_ADV_FAST_INT_MAX_2
// uint16_t omw_adv_intlv_max;
// uint8_t  omw_adv_type;
// uint8_t  omw_adv_filter;

void * omw_sevice_list[OMW_SVC_MAX_NUM];


void dummy() {}
void (* omw_svc_spec_cnnt_cb)() = &dummy;
void (* omw_svc_spec_dcnt_cb)() = &dummy;


__WEAK void hc_app_connected_cb(uint32_t conn_handle, uint16_t cintlv, uint16_t cintlv_min, uint16_t cintlv_max)
{
}

__WEAK void hc_app_disconnected_cb(uint32_t conn_handle, uint8_t reason)
{
}

__WEAK void hc_app_rx_process_cb(const uint8_t * buf, uint16_t len)
{
}


#ifdef OMW_BLE_HOST_V0
#ifdef OMW_BLE_V0_2_0
#ifdef CONFIG_BT_CENTRAL
uint8_t scan_type;
struct bt_hci_cp_le_create_conn  g_scan_param =
{
    BT_GAP_SCAN_FAST_INTERVAL,
    BT_GAP_SCAN_FAST_WINDOW,
    BT_LE_ADV_FP_NO_FILTER,
    {BT_ADDR_LE_PUBLIC, {{0}}},
    BT_ADDR_LE_PUBLIC,
    BT_GAP_INIT_CONN_INT_MIN,
    BT_GAP_INIT_CONN_INT_MAX,
    0,
    500,
    0,
    0
};
#endif
#endif

uint8_t omw_adv_data_sz;
uint8_t omw_sc_rsp_data_sz;
const void * omw_adv_data;
const void * omw_sc_rsp_data;

static uint8_t omw_svc_inited;
// struct bt_conn *default_conn = NULL;

struct bt_hci_cp_le_set_adv_param  g_adv_param =
{
    OMW_DEFT_ADV_INTLV_MIN,
    OMW_DEFT_ADV_INTLV_MAX,
    #ifndef OMW_BLE_EN_BEACON
    BT_HCI_ADV_IND,
    #else
    BT_HCI_ADV_NONCONN_IND,
    #endif
    BT_ADDR_LE_PUBLIC,
    {0},
    0x07,
    BT_LE_ADV_FP_NO_FILTER
};

static void connected(struct bt_conn *conn, uint8_t err)
{
    if (err)
    {
       // printf("Connection failed (err 0x%02x)\n", err);
    }
    else
    {
        omw_svc_spec_cnnt_cb();

        hc_app_connected_cb((uint32_t)conn, conn->le.interval, conn->le.interval_min, conn->le.interval_max);

        OMW_SVC_CLR_STARTED_FLAG();
    }
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
    tx_enabled = 0;

    omw_svc_spec_dcnt_cb();

    hc_app_disconnected_cb((uint32_t)conn, reason);

    #ifndef CONFIG_BT_CENTRAL
    omw_svc_start_adv();
    #endif
}

static struct bt_conn_cb conn_callbacks = {
        .connected = connected,
        .disconnected = disconnected,
};

void bt_ready(int err)
{
    if (err)
    {
        //printf("Bluetooth init failed (err %d)\n", err);
        return;
    }

    //printf("Bluetooth initialized!\n");

    #ifdef OMW_BLE_V0_2_0
    #ifdef CONFIG_BT_GATT_CLIENT
    bt_att_init();
    #endif

    bt_gatt_init();
    #endif

    bt_gatt_service_init(omw_svc_num, (const struct bt_gatt_service_static**)omw_sevice_list);

    bt_conn_cb_register(&conn_callbacks);

    omw_svc_inited = 1;

    #ifdef CONFIG_BT_CENTRAL
    if (omw_cur_mode == 0)
    #endif
        err = omw_svc_start_adv();
    #ifdef CONFIG_BT_CENTRAL
    else if (omw_cur_mode == 1)
        err = omw_svc_start_scan();
    else
        err = omw_svc_start_scan_and_conn();
    #endif

    if (err)
    {
        //printf("Advertising failed to start (err %d)\n", err);
        return;
    }

    //printf("Advertising successfully started!\n");
}

#endif

#ifdef OMW_BLE_HOST_V2
#endif


int omw_svc_updata_cnnt_param(uint32_t handle, uint16_t cnt_intvl_min, uint16_t cnt_intvl_max, uint16_t lt, uint16_t  cnt_to)
{
    struct bt_conn *conn = (struct bt_conn *)handle;
    struct bt_le_conn_param param;

    param.interval_min = cnt_intvl_min;
    param.interval_max = cnt_intvl_max;
    param.latency = lt;
    param.timeout = cnt_to;
	
	ble_conn_param.interval_min =   param.interval_min;					//zhq  note: 
	ble_conn_param.interval_max =  param.interval_max;					//zhq  note: 
	ble_conn_param.latency =   param.latency;										//zhq  note: 
	ble_conn_param.timeout =  param.timeout ;									//zhq  note: 	

    return bt_conn_le_param_update(conn, &param);
}

void omw_set_adv_data(void * padv_data, uint8_t len)
{
    #ifdef OMW_BLE_HOST_V0
    omw_adv_data_sz = len;
    omw_adv_data = padv_data;
    #endif
}

void omw_set_scan_rsp_data(void * pscr_data, uint8_t len)
{
    #ifdef OMW_BLE_HOST_V0
    omw_sc_rsp_data_sz = len;
    omw_sc_rsp_data = pscr_data;
    #endif
}

void omw_svc_add_base_svc(const void * p_svc)
{
    for (int i = 0; i < omw_svc_num; i++){
        if (omw_sevice_list[i] == p_svc) return;
    }

    omw_sevice_list[omw_svc_num++] = (void *)p_svc;
}

int omw_svc_add_svc(const omw_svc_info_t * p_svc_info)
{
    OMW_SVC_CHK_STARTED();

    // #ifdef  OMW_SVC_ERR_CHK
    if (omw_svc_num >= OMW_SVC_MAX_NUM)  return -2;
    // #endif

    omw_svc_add_base_svc(p_svc_info->svc_data_addr);

    return 0;
}

void omw_svc_set_adv_intvl(uint16_t min, uint16_t max)
{
    #ifdef OMW_BLE_HOST_V0
    g_adv_param.min_interval = min;
    g_adv_param.max_interval = max;
    #endif
}

void omw_svc_set_adv_type(uint8_t type)
{
    #ifdef OMW_BLE_HOST_V0
    g_adv_param.type = type;
    #endif
}

void omw_svc_set_adv_addr(uint8_t addr_type, bt_addr_le_t * dir_addr_info)
{
    #ifdef OMW_BLE_HOST_V0
    g_adv_param.own_addr_type = addr_type;
    if (NULL != dir_addr_info) g_adv_param.direct_addr = *dir_addr_info;
    #endif
}

void omw_svc_set_adv_chl_map(uint8_t cm)
{
    #ifdef OMW_BLE_HOST_V0
    g_adv_param.channel_map = cm;
    #endif
}

void omw_svc_set_adv_filter_plc(uint8_t fplc)
{
    #ifdef OMW_BLE_HOST_V0
    g_adv_param.filter_policy = fplc;
    #endif
}

int omw_svc_start_svc_adv(const omw_svc_info_t * p_svc_info)
{
    #ifdef OMW_BLE_HOST_V0
    omw_adv_data = p_svc_info->svc_adv_data_addr;
    omw_adv_data_sz = p_svc_info->svc_adv_data_len;

    omw_sc_rsp_data = p_svc_info->svc_scan_rsp_data_addr;
    omw_sc_rsp_data_sz = p_svc_info->svc_scan_rsp_data_len;
    #endif

    return omw_svc_start_adv();
}

int omw_svc_start_adv()
{
    OMW_SVC_CHK_STARTED();

    #ifdef OMW_BLE_HOST_V0
    if (omw_svc_inited)
    {
        // #ifdef  OMW_SVC_ERR_CHK
        OMW_SVC_SET_STARTED_FLAG();
        // #endif
        (void)hci_send_cmd_le_set_adv_param(g_adv_param.min_interval, g_adv_param.max_interval, g_adv_param.type, g_adv_param.own_addr_type, &g_adv_param.direct_addr, g_adv_param.channel_map, g_adv_param.filter_policy);
        (void)hci_send_cmd_le_set_adv_data(omw_adv_data, omw_adv_data_sz);
        (void)hci_send_cmd_le_set_scan_rsp_data(omw_sc_rsp_data, omw_sc_rsp_data_sz);
        (void)hci_send_cmd_le_set_adv_enable(true);
    }
    #endif

    #ifdef CONFIG_BT_CENTRAL
    omw_cur_mode = 0;
    #endif

    return 0;
}

void omw_svc_stop_adv()
{
    // #ifdef  OMW_SVC_ERR_CHK
    OMW_SVC_CHK_CLR_STARTED();
    // #endif

    #ifdef OMW_BLE_HOST_V0
    (void)hci_send_cmd_le_set_adv_enable(false);
    #endif
}

void omw_svc_disconnect(uint32_t handle)
{
    #ifdef OMW_BLE_HOST_V0
    bt_hci_disconnect(((struct bt_conn *)handle)->handle, 0x13);  //BT_ERR_REMOTE_USER_TERM_CONN
    #endif
}

int omw_svc_get_last_rssi(uint32_t handle)
{
    #ifdef OMW_BLE_HOST_V0
    struct ll_conn_set *conn;

    conn = ll_conn_set_get(((struct bt_conn *)handle)->handle);

    return conn->rssi_latest;
    #endif
}

// void omw_svc_set_tx_pwr(int8_t pwr)
// {

// }

#ifdef CONFIG_BT_CENTRAL
void omw_svc_set_scan_type(uint8_t sctp)
{
    #ifdef OMW_BLE_V0_2_0
    scan_type = sctp;
    #endif
}

void omw_svc_set_scan_addr(bt_addr_le_t * peer_addr_info, uint8_t own_addr_type)
{
    #ifdef OMW_BLE_V0_2_0
    g_scan_param.own_addr_type = own_addr_type;
    g_scan_param.peer_addr = *peer_addr_info;
    #endif
}

void omw_svc_set_scan_intvl_win(uint16_t scan_interval, uint16_t scan_window)
{
    #ifdef OMW_BLE_V0_2_0
    g_scan_param.scan_interval = scan_interval;
    g_scan_param.scan_window = scan_window;
    #endif
}

void omw_svc_set_scan_filt_pol(uint8_t filter_policy)
{
    #ifdef OMW_BLE_V0_2_0
    g_scan_param.filter_policy = filter_policy;
    #endif
}

void omw_svc_set_scan_conn_param(uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout,
    uint16_t min_ce_len, uint16_t max_ce_len)
{
    #ifdef OMW_BLE_V0_2_0
    g_scan_param.conn_interval_min = conn_interval_min;
    g_scan_param.conn_interval_max = conn_interval_max;
    g_scan_param.conn_latency = conn_latency;
    g_scan_param.supervision_timeout = supervision_timeout;
    g_scan_param.min_ce_len = min_ce_len;
    g_scan_param.max_ce_len = max_ce_len;
    #endif
}

int omw_svc_start_scan()
{
    OMW_SVC_CHK_STARTED();

    if (omw_svc_inited)
    {
        #ifdef OMW_BLE_V0_2_0
        (void)hci_send_cmd_le_set_scan_param(scan_type, g_scan_param.scan_interval, g_scan_param.scan_window, g_scan_param.own_addr_type, g_scan_param.filter_policy);
        (void)hci_send_cmd_le_set_scan_enable(1, 1);
        #endif

        OMW_SVC_SET_STARTED_FLAG();
    }

    omw_cur_mode = 1;

    return 0;
}

int omw_svc_start_scan_and_conn()
{
    OMW_SVC_CHK_STARTED();

    if (omw_svc_inited)
    {
        #ifdef OMW_BLE_V0_2_0
        (void)hci_send_cmd_le_create_conn(g_scan_param.scan_interval, g_scan_param.scan_window, g_scan_param.filter_policy, &g_scan_param.peer_addr, g_scan_param.own_addr_type,
                                    g_scan_param.conn_interval_min, g_scan_param.conn_interval_max, g_scan_param.conn_latency,
                                    g_scan_param.supervision_timeout,
                                    g_scan_param.min_ce_len, g_scan_param.max_ce_len);
        #endif

        OMW_SVC_SET_STARTED_FLAG();
    }

    omw_cur_mode = 2;

    return 0;
}

void omw_svc_stop_scan()
{
    // #ifdef  OMW_SVC_ERR_CHK
    OMW_SVC_CHK_CLR_STARTED();
    // #endif

    #ifdef OMW_BLE_V0_2_0
    hci_send_cmd_le_create_conn_cancel();
    #endif
}

#ifdef OMW_BLE_V0_2_0
static struct bt_gatt_discover_params  discover_params;
static struct bt_gatt_subscribe_params subscribe_params;

static omw_svc_disc_svc_cb app_disc_cb;
static omw_notify_cb       app_ntf_cb;

static uint8_t notify_func(struct bt_conn *conn,
			   struct bt_gatt_subscribe_params *params,
			   const void *data, uint16_t length)
{
	if (!data) {
		// printf("[UNSUBSCRIBED]\n");
		params->value_handle = 0U;
		return BT_GATT_ITER_STOP;
	}

    app_ntf_cb((uint32_t)conn, data, length);

	// printf("[NOTIFICATION] data %p length %u\n", data, length);

	return BT_GATT_ITER_CONTINUE;
}

static uint8_t discover_func(struct bt_conn *conn,
			     const struct bt_gatt_attr *attr,
			     struct bt_gatt_discover_params *params)
{
	if (!attr) {
		// printf("Discover complete\n");
		(void)memset(params, 0, sizeof(*params));
		return BT_GATT_ITER_STOP;
	}

    app_disc_cb((uint32_t)conn, attr->handle, attr->uuid);

	return BT_GATT_ITER_STOP;
}
#endif

int omw_svc_disc_svc(uint32_t cn_hdl, uint16_t st_hld, uint16_t ed_hld, struct bt_uuid * uuid, uint8_t type, omw_svc_disc_svc_cb dc_cb)
{
    #ifdef OMW_BLE_V0_2_0
    discover_params.uuid         = uuid;
    discover_params.func         = discover_func;
    discover_params.start_handle = st_hld;
    discover_params.end_handle   = ed_hld;
    discover_params.type         = type;

    app_disc_cb = dc_cb;

    return bt_gatt_discover((struct bt_conn *)cn_hdl, &discover_params);
    #endif
}

int omw_svc_subscribe(uint32_t cn_hdl, uint16_t val_hdl, uint16_t ccc_hdl, uint16_t ntf_val, omw_notify_cb ntf_cb)
{
    #ifdef OMW_BLE_V0_2_0
    subscribe_params.value_handle = val_hdl;
    subscribe_params.notify       = notify_func;
    subscribe_params.value        = ntf_val;
    subscribe_params.ccc_handle   = ccc_hdl;

    app_ntf_cb = ntf_cb;

    return bt_gatt_subscribe((struct bt_conn *)cn_hdl, &subscribe_params);
    #endif
}

struct bt_gatt_write_params  wt_param;
int omw_svc_write(uint32_t cn_hdl, uint16_t wt_hdl, void * data, uint16_t len, uint8_t sign, omw_write_rsp_cb rsp_cb)
{
    #ifdef OMW_BLE_V0_2_0
    if (rsp_cb != NULL)
    {//write without response
        memset(&wt_param, 0, sizeof(wt_param));

        wt_param.func   = rsp_cb;
        wt_param.handle = wt_hdl;
        wt_param.data   = data;
        wt_param.length = len;

        return bt_gatt_write((struct bt_conn *)cn_hdl, &wt_param);
    }
    else
    {
        return bt_gatt_write_without_response((struct bt_conn *)cn_hdl, wt_hdl, data, len, sign);
    }
    #endif
}

struct bt_gatt_read_params rd_param;
int omw_svc_read(uint32_t cn_hdl, struct bt_uuid * uuid)
{
    #ifdef OMW_BLE_V0_2_0
    memset(&rd_param, 0, sizeof(rd_param));
    rd_param.by_uuid.uuid = uuid;

    return bt_gatt_read((struct bt_conn *)cn_hdl, &rd_param);
    #endif
}
#endif