#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/types.h> 
#include <sys/ioctl.h> 
#include <errno.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <sys/epoll.h>
#include "dy_utils/dy_common.h"
#include "lnxall_list.h"
#define  MAXEPOLLSIZE 16
typedef struct options
{
    int epollfd;
    struct list_head tm_list;
} options_t;

typedef struct id_bind {
    struct list_head list;
	int fd;
    int lua_id;
} id_bind_t;

static options_t opts;

static int l_init(lua_State* L)
{
    INIT_LIST_HEAD(&opts.tm_list);
    opts.epollfd = epoll_create(MAXEPOLLSIZE);
    if(opts.epollfd <= 0)
    {
        lua_pushboolean(L,0);
        lua_pushstring(L, "Epoll create error");
        return 2;
    }
}

static int l_tick(lua_State* L)
{
    long long value = clock_get_ms();
    lua_pushinteger(L, value);
    return 1;                
}

static int l_epoll(lua_State* L)
{
    int timeout = 10;
    if(lua_isinteger(L, 1)){
        timeout = (int) lua_tointeger(L, 1);
    }

    int i;
    struct epoll_event events[MAXEPOLLSIZE];
    int nfds = epoll_wait(opts.epollfd, events, 1, timeout);
    if(nfds >0 )
    {
        for (i = 0; i < nfds; ++i)
        {
            if (events[i].data.fd)
            {
                my_timer_read(events[i].data.fd);
                lua_pushboolean(L,1);

                id_bind_t *id_bind = NULL;
                id_bind_t *tmp = NULL;
                int lua_id = -1;
                list_for_each_entry_safe(id_bind, tmp, &opts.tm_list, list)
                {
                    if (events[i].data.fd == id_bind->fd) {
                        lua_id = id_bind->lua_id;
                    }
                }
                if(lua_id < 0) {
                    lua_pushboolean(L,0);
                    lua_pushstring(L, "invalid lua_id");
                    return 2;
                }
                lua_pushboolean(L,1);
                lua_pushinteger(L, lua_id);
                return 2;
            }
        }
    }
    return 0;                          
}

static int l_start(lua_State* L)
{
    if (lua_checkstack(L, 2) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, "invalid argument(s) need 2 params");
        return 2;
    }

    int ntop = lua_gettop(L);
    int lua_id = -1;
    int timeout = 0;
    int fd = -1;
    if (ntop < 2 ||
        lua_isinteger(L, 1) == 0 ||
        lua_isinteger(L, 2) == 0)  {
        lua_pushnil(L);
        lua_pushstring(L, "invalid argument(s) ");
        return 2;
    }
    lua_id = (int) lua_tointeger(L, 1);
    timeout = (int) lua_tointeger(L, 2);
    fd = my_timer_create();
    my_timer_set_ms(fd,timeout,-1);
    struct epoll_event ev;
    ev.events = EPOLLIN | EPOLLET;
    ev.data.fd = fd;
    if(epoll_ctl(opts.epollfd,EPOLL_CTL_ADD,fd,&ev))
    {
        lua_pushnil(L);
        lua_pushstring(L, "epoll ctl failed");
        return 2;
    }
    id_bind_t *id_bind = calloc(1, sizeof(id_bind_t));
    id_bind->lua_id = lua_id;
    id_bind->fd = fd;
    list_add_tail(&id_bind->list, &opts.tm_list);
    lua_pushboolean(L,1);
    return 1;
}

static int l_stop(lua_State* L)
{
            // 检查栈
    int ntop = lua_gettop(L);
    int lua_id = -1;
    int fd = -1;
    if (ntop < 1 ||
        lua_isinteger(L, 1) == 0)   {
        lua_pushnil(L);
        lua_pushstring(L, "invalid argument(s) ");
        return 2;
    }
    lua_id = (int) lua_tointeger(L, 1);

    id_bind_t *id_bind = NULL;
    id_bind_t *tmp = NULL;
    list_for_each_entry_safe(id_bind, tmp, &opts.tm_list, list)
    {
        if (lua_id == id_bind->lua_id) {
            list_del(&id_bind->list);
            free(id_bind);
            lua_pushboolean(L,1);
            fd = id_bind->fd;
        }
    }
    if (fd < 0) {
        lua_pushnil(L);
        lua_pushstring(L, "invalid fd ");
        return 2;
    }
    struct epoll_event ev;
    ev.events = EPOLLIN | EPOLLET;
    ev.data.fd = fd;
    if(epoll_ctl(opts.epollfd,EPOLL_CTL_DEL,fd,&ev))
    {
        lua_pushnil(L);
        lua_pushstring(L, "epoll ctl failed");
        return 2;
    }
    my_timer_delete(fd);
    return 0;
}

static int l_sleep(lua_State* L)
{
    // 检查栈
    int ntop = lua_gettop(L);
    if (ntop < 1 ||
        lua_isinteger(L, 1) == 0)   {
        lua_pushnil(L);
        lua_pushstring(L, "invalid argument(s) ");
        return 2;
    }
    int sec = (int) lua_tointeger(L, 1);  
    sleep(sec);
    return 0;                          
}

static int l_msleep(lua_State* L)
{
    // 检查栈
    int ntop = lua_gettop(L);
    if (ntop < 1 ||
        lua_isinteger(L, 1) == 0)   {
        lua_pushnil(L);
        lua_pushstring(L, "invalid argument(s) ");
        return 2;
    }
    int ms = (int) lua_tointeger(L, 1); 
    usleep(ms*1000);
    return 0;                           
}

static const struct luaL_Reg eptimer[] = {
    {"init", l_init},
    {"tick", l_tick},
    {"epoll", l_epoll},
    {"start", l_start},
    {"stop", l_stop},
    {"sleep", l_sleep},
    {"msleep", l_msleep},
    {NULL, NULL},
};
 
//模块注册函数
int luaopen_eptimer(lua_State* lua)
{
    luaL_register(lua, "eptimer", eptimer);
    return 1;
}
