#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/can.h>
#include <linux/can/raw.h>

#include "dy_common.h"
#include "dy_can.h"

static int _do_can_recv(can_cfg_t *can_cfg, struct list_head *recv_list)
{
    can_frame_node_t *node = NULL;
    can_frame_node_t *tmp = NULL;

    if (list_empty(recv_list))
    {
        return 0;
    }

    list_for_each_entry_safe(node, tmp, recv_list, list)
    {
        can_cfg->handle_recv_msg(can_cfg->obj, node);
        list_del(&node->list);
        free(node);
    }

    return 0;
}

static int __handle_frame_loop(can_cfg_t *can_cfg)
{

    struct list_head tmp_recv_list = LIST_HEAD_INIT(tmp_recv_list);

    pthread_mutex_lock(&can_cfg->recv_lock);
    while (can_cfg->received == 0)
    {
        int ret;

        ret = lnxall_condvar_timedwait(&can_cfg->recv_cond, &can_cfg->recv_lock, 5000);
        if (ret && ret != ETIMEDOUT) {
            fprintf(stderr, "Error, cond_timewait(...) has failed: %d\n", ret);
            fflush(stderr);
        }
    }

    if (can_cfg->received)
    {
        int i;
        for (i = 0; i < can_cfg->node_cnt; i++)
        {
            // real received packets
            if (!list_empty(&can_cfg->can_dev[i].rcv_list))
            {
                list_move_tail_list(&can_cfg->can_dev[i].rcv_list, &tmp_recv_list);
            }
        }
        can_cfg->received = 0;
        pthread_mutex_unlock(&can_cfg->recv_lock);

        if (can_cfg->handle_recv_frames == NULL)
        {
            _do_can_recv(can_cfg, &tmp_recv_list);
        }
        else
        {
            can_cfg->handle_recv_frames(can_cfg->obj, &tmp_recv_list);
        }
    }
    else
    {
        pthread_mutex_unlock(&can_cfg->recv_lock);
    }
    return 0;
}

void *handle_frame_loop(void *param)
{
    can_cfg_t *can_cfg = (can_cfg_t *)param;

    while (1)
    {
        __handle_frame_loop(can_cfg);
    }
}
