#ifndef PLATFORM_CPU
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <uthash/utlist.h>
#include <sys/socket.h>
#include <linux/netlink.h>

#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) || defined(PLATFORM_R311)
#include "log.h"
#include "libuv_dbus.h"
#include "boardlink_iot.h"
#else
#include <uvdbus/log.h>
#include <uvdbus/libuv_dbus.h>
#include <uvdbus/boardlink_iot.h>
#endif

#define BL_IOT_PROTO            (30)
#define BL_MSG_BUF_MAX          (1024 * 4)

static int g_nlSock = -1;
static unsigned char g_MsgSendBuf[BL_MSG_BUF_MAX];
static BlMsgCb g_blMsgCb = NULL;

static void __recvMsgThread(void *pParam)
{
    unsigned char msgBuf[BL_MSG_BUF_MAX];
    struct iovec iov = {msgBuf, BL_MSG_BUF_MAX};
    struct nlmsghdr *pMsgHdr;
    struct sockaddr_nl fromAddr;
    struct msghdr msgHdr = {&fromAddr, sizeof(fromAddr), &iov, 1, NULL, 0, 0};;

    memset(&fromAddr, 0, sizeof(fromAddr));
    fromAddr.nl_family  = AF_NETLINK;
    fromAddr.nl_pid     = 0;
    fromAddr.nl_groups  = 0;

    while(TRUE)
    {
        int len = recvmsg(g_nlSock, &msgHdr, 0);

        if(len > 0)
        {
            for(pMsgHdr = (struct nlmsghdr *)msgBuf;
                NLMSG_OK(pMsgHdr, len);
                pMsgHdr = NLMSG_NEXT(pMsgHdr, len))
            {
                if(pMsgHdr->nlmsg_type == NLMSG_DONE)
                {
                    continue;
                }
                else if(pMsgHdr->nlmsg_type == NLMSG_ERROR)
                {
                    continue;
                }
                else
                {
                    PBL_IOT_MSG pMsg = (PBL_IOT_MSG)NLMSG_DATA(pMsgHdr);
                    //LOG_EX(LOG_Debug, "Recv Message: %s\n", NLMSG_DATA(pMsgHdr));
                    print_hex_dump_bytes("Msg", 0, pMsg, BL_IOT_MSG_LEN(pMsg->msglen));
                    if(g_blMsgCb)
                    {
                        g_blMsgCb(pMsg);
                    }
                }
            }
        }

        usleep(1000);
    }
    pthread_detach(pthread_self());
}

static int __nlCreateSocket(void)
{
    struct sockaddr_nl srcAddr;

    g_nlSock = socket(AF_NETLINK, SOCK_RAW, BL_IOT_PROTO);

    if(g_nlSock == -1)
    {
        LOG_EX(LOG_Error, "Create netlink socker error: %s\n", strerror(errno));
        return -ERR_CREATE_SOCKET;
    }

    memset(&srcAddr, 0, sizeof(srcAddr));
    srcAddr.nl_family = AF_NETLINK;
    srcAddr.nl_pid = getpid();
    srcAddr.nl_groups = 0;

    if(bind(g_nlSock, (struct sockaddr*)&srcAddr, sizeof(srcAddr)) < 0)
    {
        LOG_EX(LOG_Error, "Bind netlink socket failed: %s", strerror(errno));
        close(g_nlSock);
        return -ERR_BIND_SOCKET;
    }

    return 0;
}

static int __sendMessage(unsigned char* pData, unsigned int len)
{
    struct iovec iov;
    struct sockaddr_nl dstAddr;
    struct nlmsghdr* pMsgHdr = (struct nlmsghdr*)g_MsgSendBuf;
    struct msghdr msgHdr = {&dstAddr, sizeof(dstAddr), &iov, 1, NULL, 0, 0};

    memset(&dstAddr, 0, sizeof(struct sockaddr_nl));
    dstAddr.nl_family   = AF_NETLINK;
    dstAddr.nl_pid      = 0;
    dstAddr.nl_groups   = 0;

    memset(pMsgHdr, 0, BL_MSG_BUF_MAX);
    pMsgHdr->nlmsg_len      = len;
    pMsgHdr->nlmsg_pid      = getpid();
    pMsgHdr->nlmsg_flags    = 0;
    memcpy(NLMSG_DATA(pMsgHdr), pData, len);

    iov.iov_base    = pMsgHdr;
    iov.iov_len     = NLMSG_SPACE(BL_MSG_BUF_MAX);

    return sendmsg(g_nlSock, &msgHdr, 0);
}

int BL_SendBLMsg(BL_IOT_MSG_TYPE msgType, unsigned char* pData, unsigned int len)
{
    BL_IOT_MSG blMsg;

    memset(&blMsg, 0, sizeof(BL_IOT_MSG));
    blMsg.msgType = msgType;
    blMsg.msglen = len;
    strcpy(blMsg.msgTags, BL_IOT_MSG_TAGS);

    if(pData && len > 0)
    {
        memcpy(blMsg.msgData, pData, len);
    }

    return __sendMessage((unsigned char*)&blMsg, BL_IOT_MSG_LEN(len));
}   

int BL_SendBLMsgTo(BL_IOT_MSG_TYPE msgType, unsigned char* pData, unsigned int len, unsigned char dstMac[ETH_ALEN])
{
    BL_IOT_MSG blMsg;

    memset(&blMsg, 0, sizeof(BL_IOT_MSG));
    blMsg.msgType = msgType;
    blMsg.msglen = len;
    memcpy(blMsg.dstMac, dstMac, ETH_ALEN);
    strcpy(blMsg.msgTags, BL_IOT_MSG_TAGS);

    if(pData && len > 0)
    {
        memcpy(blMsg.msgData, pData, len);
    }

    return __sendMessage((unsigned char*)&blMsg, BL_IOT_MSG_LEN(len));
}

int BL_Init(BlMsgCb cbOnMsg)
{
    int ret = 0;
    uv_thread_t uvRecvThread;

    ret = __nlCreateSocket();

    if(ret != 0)
    {
        return ret;
    }

    g_blMsgCb = cbOnMsg;
   
    uv_thread_create(&uvRecvThread, __recvMsgThread, NULL);

    return 0;
}
#endif
