//=========kk=============
#include "com_api.h"

#define APP2MID "ipc:///tmp/app2mid.ipc"
#define PLAT2MID "ipc:///tmp/plat2mid.ipc"
#define MAGIC "magic12"


typedef struct {
    int n;//nanomsg socket
    int s;//nanomsg recieve fd
}nanomsg_info_t;

typedef struct {
    nanomsg_info_t ba;
    struct ev_io watcher;
    ipc_cb* cb;
    ipc_type type;
    int isconnect;
}Bloop_ctrl_t;

Bloop_ctrl_t Bloop_ctrl;
Bloop_ctrl_t Mloop_ctrl;

struct ev_loop* gloop = NULL;
pthread_t g_pTh = NULL;




static void watcher_cb (struct ev_loop *loop ,struct ev_io *w, int revents)
{

    printf("watcher_cb !! \r\n\r\n");
    void *user_data = ev_userdata(loop);
    Bloop_ctrl_t *loop_ctrl = (Bloop_ctrl_t *)w->data;
    uint8_t *dat = NULL;
    uint32_t bytes = nn_recv(loop_ctrl->ba.n, &dat, NN_MSG, NN_DONTWAIT);
    if (bytes <= 0) {
        return;
    }
    printf("watcher_cb:%s recived\r\n\r\n", (char *)dat);
    //for test ipc connect or not
    if (loop_ctrl->isconnect == 0 ){
        loop_ctrl->isconnect =1;
        if (strncmp(dat,MAGIC, strlen(MAGIC)) == 0){
            kk_ipc_send(loop_ctrl->type, dat, bytes);
            nn_freemsg(dat);
            return;
        }
    }
    
	if (loop_ctrl->cb != NULL){
		loop_ctrl->cb((void *)dat, bytes);
	}
    nn_freemsg(dat);
}


void __loop_init(Bloop_ctrl_t *loop_ctrl, struct ev_loop* loop)
{
    
    loop_ctrl->watcher.data = loop_ctrl;
    ev_io_init (&(loop_ctrl->watcher), watcher_cb, loop_ctrl->ba.s, EV_READ);
    ev_io_start (loop, &(loop_ctrl->watcher));
}


int __nanomsg_init(Bloop_ctrl_t *loop_ctrl, ipc_type type)
{
    loop_ctrl->ba.n = nn_socket(AF_SP, NN_PAIR);
	printf("__nanomsg_init loop_ctrl->ba.n=%d \r\n",loop_ctrl->ba.n);
    if (loop_ctrl->ba.n < 0) {
        return -1;
    }

	switch (type) {
        case IPC_APP2MID:{
            if (nn_connect(loop_ctrl->ba.n, APP2MID) < 0) {
		        return -1;
		    }
        }
        break;
		case IPC_PLAT2MID: {
            if (nn_connect(loop_ctrl->ba.n, PLAT2MID) < 0) {
		        return -1;
		    }
        }
        break;
		case IPC_MID2APP: {
            if (nn_bind(loop_ctrl->ba.n, APP2MID) < 0) {
		        return -1;
		    }
        }
        break;
		case IPC_MID2PLAT: {
            if (nn_bind(loop_ctrl->ba.n, PLAT2MID) < 0) {
		        return -1;
		    }
        }
        break;
        default: {
        }
        break;
    } 
   
    size_t size = sizeof(size_t);
    if (nn_getsockopt(loop_ctrl->ba.n, NN_SOL_SOCKET, NN_RCVFD, (char *)&loop_ctrl->ba.s, &size) < 0) {
        return -1;
    }
    return 0;
}


/*=================================
*  TODO: only one methd pair
*
*
==================================*/
void loop_thread(void *arg){
    printf("loop_thread start!\r\n");
    ev_run (gloop, 0);
	
}

int kk_ipc_init(ipc_type type, ipc_cb cb)
{

    Bloop_ctrl_t* loop_ctrl;
    if (IPC_MID2PLAT == type){
         loop_ctrl = &Mloop_ctrl;
    }else {
         loop_ctrl = &Bloop_ctrl;
    }

    if(loop_ctrl->cb != NULL){
        printf("middleware to platform ipc has been inited!\r\n");
		return -1;
        
    }
    
    if (__nanomsg_init(loop_ctrl, type) < 0) {
        printf("nanomsg init failed\r\n");
        return -1;
    }


    if (gloop == NULL){
        gloop = ev_loop_new(EVBACKEND_EPOLL);
        if (NULL == gloop) {
            printf("create loop failed\r\n");
            return -1;
        }
        
    }
    __loop_init(loop_ctrl, gloop);

	if (g_pTh ==NULL && 0 != pthread_create(&g_pTh, NULL, loop_thread, NULL)) {
        printf("create pthread failed\r\n");
        return -1;
    }

    loop_ctrl->cb = cb;
    loop_ctrl->type =  type;
    return 0;
	
}

int kk_ipc_dinit(ipc_type type)
{
    Bloop_ctrl_t* loop_ctrl;
    if (Bloop_ctrl.type == type){
        loop_ctrl = &Bloop_ctrl;
    }else if (Mloop_ctrl.type == type){
        loop_ctrl = &Mloop_ctrl;
    }else{
        printf("kk_ipc_dinit failed, no ipc need destroy!\r\n");
        return -1;
    }
    
    if (loop_ctrl->ba.n > -1){
		nn_shutdown(loop_ctrl->ba.n, 0);
	}

	ev_io_stop(gloop, &loop_ctrl->watcher);
    loop_ctrl->cb = NULL;
    loop_ctrl->type = IPC_UNDEF;
    
    if (Bloop_ctrl.cb ==NULL && Mloop_ctrl.cb ==NULL){
        ev_break(gloop,EVBREAK_ALL);
        pthread_exit(g_pTh);
        ev_loop_destroy(gloop);
        gloop = NULL;
        g_pTh = NULL;
    }
    
	return 0;

}

int kk_ipc_send(ipc_type type, void* data, int len)
{
	if (data != NULL){

		void* buf = nn_allocmsg(len, 0);
		memcpy(buf, data, len);
        if (type == IPC_MID2PLAT){
            nn_send(Mloop_ctrl.ba.n, &buf, NN_MSG, NN_DONTWAIT);
        }else{
            nn_send(Bloop_ctrl.ba.n, &buf, NN_MSG, NN_DONTWAIT);
        }
		
	}

	return 0;

}

int kk_ipc_isconnect(ipc_type type){
    Bloop_ctrl_t* loop_ctrl;
    
    if (IPC_MID2PLAT == type){
         loop_ctrl = &Mloop_ctrl;
    }else {
         loop_ctrl = &Bloop_ctrl;
    }

    if (loop_ctrl->isconnect == 1){
        return 1;
    }else{
        
        for(int i =0; i<20;i++){
            kk_ipc_send(type, MAGIC, strlen(MAGIC)+1);
            usleep(500000);
            if (loop_ctrl->isconnect == 1){
                break;
            }
        }
        return loop_ctrl->isconnect;
    }
}

