#include "timer.h"
#include "uv.h"
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include "bmser_log.h"
#include <stdlib.h>


typedef struct bs_timer_pri_s bs_timer_pri_s;
struct bs_timer_pri_s{
  int timeout_ms;
  int repeat; 
  int active;
  void *arg;
  bs_timer_cb timer_cb;
};

struct bs_timer_s {
  int unused;
  void *ctmer;
  void *reseved;
  bs_timer_pri_s pri; 
};


static void __timer_single(union sigval Parameters)
{
    bs_timer_t timer = (bs_timer_t )Parameters.sival_ptr;
    if(timer->pri.timer_cb != NULL){
        timer->pri.timer_cb(timer->pri.arg);
    }
    if(timer->pri.repeat == 0){
        timer_single_stop(timer);
    }
    return ;
}

/**
 * @brief   单实例的定时器
 *          每个定时器新开启一个新的线程；
 *          当定时处理任务中有阻塞操作时；或者定时器处理任务需要临时添加与删除的情况下使用； 
 *          ！！！！定时器不再使用时，请使用close操作!!!!!!!!
 * 
 * @param timeout_cb      回调函数
 * @param timeout         超时时间 
 * @param repeat          是否重复操作
 * @param arg             参数
 * @return        返回的单实例定时器; NULL: 失败；
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
bs_timer_t  timer_single_init(bs_timer_cb timeout_cb, uint32_t timeout, uint32_t repeat, void *arg)
{
    int ret = 0;
    bs_timer_t timer = NULL;
    struct sigevent SignalEvent;
    
    timer = (bs_timer_t )malloc(sizeof(bs_timer_t));
    timer->ctmer = malloc(sizeof(timer_t));
    if((timer == NULL)||(timer->ctmer == NULL)){
        return NULL;
    }
    
    timer->pri.arg = arg;
    timer->pri.repeat = repeat;
    timer->pri.timeout_ms = timeout;
    timer->pri.timer_cb = timeout_cb;
    SignalEvent.sigev_notify = SIGEV_THREAD;
    SignalEvent.sigev_notify_function = __timer_single;
    SignalEvent.sigev_value.sival_ptr = timer;
    SignalEvent.sigev_notify_attributes = NULL;
#if 0
    if (sigaction(SIGRTMIN, &SignalEvent, NULL) == -1) {
        printf("sigaction");
        return NULL;
    }
#endif
    ret = timer_create(CLOCK_MONOTONIC, &SignalEvent, timer->ctmer);
    if(ret != 0){
        free(timer);
        timer = NULL;
    }
    return timer;
}

/**
 * @brief 暂停定时器，可以根据期望后面可以任然开启
 * 
 * @param timer_single 
 * @return int 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_single_stop(bs_timer_t timer_single)
{
    bs_timer_t timer = timer_single;
    if(timer_single == NULL){
        return -1;
    }
    struct itimerspec stop_time;  
    stop_time.it_value.tv_sec = 0;        // 超时时间设置为0  
    stop_time.it_value.tv_nsec = 0;      
    stop_time.it_interval.tv_sec = 0;     // 间隔时间设置为0  
    stop_time.it_interval.tv_nsec = 0;      
    // 使用 timer_settime 函数停止定时器
    timer_t* ctimer = timer->ctmer;
    if (timer_settime((timer_t)(*ctimer), 0, &stop_time, NULL) == -1) {
        // 处理错误  
        return -1;
    }
    return 0;
}

/**
 * @brief 启动定时器
 * 
 * @param timer_single 
 * @return int 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_single_start(bs_timer_t timer_single)
{
    bs_timer_t timer = timer_single;
    if(timer_single == NULL){
        return -1;
    }
    bs_timer_pri_s *pri = &timer_single->pri;
    struct itimerspec tmr_set = {0};
    {
        tmr_set.it_value.tv_sec = pri->timeout_ms / 1000;
        tmr_set.it_value.tv_nsec = (pri->timeout_ms % 1000) * 1000000;
    }

    if (pri->repeat){
        tmr_set.it_interval.tv_sec = pri->timeout_ms / 1000;
        tmr_set.it_interval.tv_nsec = (pri->timeout_ms % 1000) * 1000000;
    }
    else{
        tmr_set.it_interval.tv_sec = 0;
        tmr_set.it_interval.tv_nsec = 0;
    }
    // 使用 timer_settime 函数停止定时器  
    timer_t* ctimer = timer->ctmer;
    if (timer_settime(*ctimer, 0, &tmr_set, NULL) == -1) {
        return -1;
    }
    return 0;
}

/**
 * @brief 删除定时器
 * 
 * @param timer_single 
 * @return int     <0 失败 0:正常
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_single_close(bs_timer_t timer_single)
{
    int ret = 0;
    bs_timer_t timer = timer_single;
    if(timer_single == NULL){
        return -1;
    }
    timer_single_stop(timer_single);  
    timer_t* ctimer = timer->ctmer;
    ret = timer_delete((timer_t )*ctimer);
    free(timer_single);

    return ret;
}


#define MAX_TIMER_LIMIT 100
typedef struct _timer_list_pri_s timer_list_pri_t;
struct _timer_list_pri_s{
  int fd;           
  int used_flag;
  int timeout_ms;
  int repeat; 
  int idx;
  void *arg;
  bs_timer_cb timer_cb;
};

struct timer_list_s {
    int epollfd;
    int max_sw_num;
    int used_num;
    void* lock;
    timer_list_pri_t* sw_array[MAX_TIMER_LIMIT];
};

timer_list_pri_t* find_one_empty(timer_list_t tmr);
timer_list_pri_t* find_one_use_idx(timer_list_t tmr, int idx);
timer_list_pri_t* find_one_use_fd(timer_list_t tmr, int fd);
static void* __timer_list_thread(void* tmr);
int __set_timerfd(int timerfd, int msecond);
static void __idle_handle(void* arg);
static int __timer_list_close(timer_list_t tmr);


/**
 * @brief  申请一个定时器，可以对该定时器扩展硬件定时功能，CPU消耗较小,一个timer_list回调在一个线程中
           使用timer fd 实现，消耗了较多系统资源 
           !!!!!使用完成后必须timer_list_close回收资源!!!!
 * 
 * 
 * 
 * @param sw_tmr_num       包含的软件定时器个数
 * @return timer_list_t*   软件定时器的列表指针
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
timer_list_t timer_list_create(int sw_tmr_num)
{
    timer_list_t tmr_sw = NULL;
    pthread_spinlock_t *lock = NULL;
    int i = 0;
    tmr_sw = malloc(sizeof(timer_list_t));
    if(tmr_sw == NULL){
        dy_syslog(LOG_ERR,"timer sw error");
        goto clean_up;
    }
    for(i=0;i<sw_tmr_num;i++){
        tmr_sw->sw_array[i] = malloc(sizeof(timer_list_pri_t));
        if(tmr_sw->sw_array[i] == NULL){
            dy_syslog(LOG_ERR,"timer sw error");
            goto clean_up;
        }
    }
    lock = malloc(sizeof(pthread_spinlock_t));
    if(lock == NULL){        
        dy_syslog(LOG_ERR,"timer sw error");
        goto clean_up;
    }
    tmr_sw->max_sw_num = sw_tmr_num;
    tmr_sw->used_num = 0;
    pthread_spin_init(lock, 0);
    tmr_sw->lock = (void *)lock;
    int epollfd = epoll_create1(EPOLL_CLOEXEC);
    if (epollfd == -1){
        goto clean_up;
    }
    tmr_sw->epollfd = epollfd;
    timer_list_add_one(tmr_sw, __idle_handle, 500, 1, tmr_sw);
    pthread_t thread_id;
    if(0 != pthread_create(&thread_id, NULL, (void*)__timer_list_thread , tmr_sw)){
        goto clean_up;
    }
    pthread_detach(thread_id);
    return tmr_sw;
clean_up:
    if(tmr_sw){
        free(tmr_sw);        
    }
    for(i=0;i<sw_tmr_num;i++){
        if(tmr_sw->sw_array[i] != NULL){
            free(tmr_sw->sw_array[i]);
        }
    }
    pthread_spin_destroy(lock);
    if(lock){
        free((void *)lock);
    }
    return NULL;
}

int __set_timerfd(int timerfd,  int msecond)
{
    struct itimerspec new_value = {};
    new_value.it_value.tv_sec  = msecond/1000;        
    new_value.it_value.tv_nsec = (msecond%1000)*1000000;
    new_value.it_interval.tv_sec  = msecond/1000;          
    new_value.it_interval.tv_nsec = (msecond%1000)*1000000;
    if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1){
        dy_syslog(LOG_ERR, "timerfd_settime");
        return -1;
    }
    return 0;
}

static void __idle_handle(void *arg)
{
    dy_syslog(LOG_DEBUG, "timerfd_settime");
}

static void* __timer_list_thread(void*  tmr)
{    
    #define maxEvents 50
    struct epoll_event events[maxEvents]={0}; 
    timer_list_t tmpTmr = NULL;
    tmpTmr = (timer_list_t)tmr;
    while(1){
        int nfd = epoll_pwait(tmpTmr->epollfd, events, maxEvents, -1, NULL);
        int i = 0;
        for (i = 0; i < nfd; ++i) {
            uint64_t exp = 0;
            timer_list_pri_t* one = (timer_list_pri_t * )events[i].data.ptr;
            int ret = read(one->fd, &exp, sizeof(uint64_t));
            if (ret != sizeof(uint64_t)){
                dy_syslog(LOG_ERR, "read timerfd");
                continue;
            }
            if((one->timer_cb != NULL)&& (one->used_flag > 0))
                one->timer_cb(one->arg);  
            if(one->repeat == 0){
                struct epoll_event ev2;
                epoll_ctl(tmpTmr->epollfd, EPOLL_CTL_DEL, one->fd, &ev2);
            }
        }
        if(tmpTmr->max_sw_num == 0){
            break;
        }
    }
    __timer_list_close(tmpTmr);
    pthread_exit(NULL);
}


timer_list_pri_t *find_one_empty(timer_list_t tmr){
    int i = 0;
    for(i= 0 ; i < tmr->max_sw_num; i++){
        if(tmr->sw_array[i]->used_flag == 0){
            return tmr->sw_array[i];
        }
    }
    return NULL;
}

timer_list_pri_t *find_one_use_fd(timer_list_t tmr, int fd){
    int i = 0;
    for(i= 0 ; i < tmr->max_sw_num; i++){
        if((tmr->sw_array[i]->used_flag == 1)&&(tmr->sw_array[i]->fd == fd)){
            return tmr->sw_array[i];
        }
    }
    return NULL;
}

timer_list_pri_t *find_one_use_idx(timer_list_t tmr, int idx){
    if(idx < tmr->max_sw_num){
        return tmr->sw_array[idx];
    }
    else{
        return NULL;
    }
}


/**
 * @brief  向定时器列表中添加一个定时器任务
 * 
 * @param tmr         定时器列表
 * @param timeout_cb  回调函数
 * @param timeout     超时时间
 * @param repeat      是否重复
 * @param arg         用户参数
 * @return int        > 0 返回当前软件定时器的id;
 *                    其它错误
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_list_add_one(timer_list_t tmr, bs_timer_cb timeout_cb, uint32_t timeout, uint32_t repeat, void *arg)
{   
    int idx = 0;
    if(tmr == NULL){
        return -1;
    }
    pthread_spin_lock(tmr->lock);
    timer_list_pri_t*one = find_one_empty(tmr);
    if(one == NULL){
        pthread_spin_unlock(tmr->lock);
        return -1;
    }
    idx = tmr->used_num;
    one->used_flag = 1;
    tmr->used_num += 1;
    pthread_spin_unlock(tmr->lock);
    
    int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    if (timerfd == -1){
        dy_syslog(LOG_ERR, "timerfd_create");
    }
    struct epoll_event ev;
    __set_timerfd(timerfd, timeout);
    ev.events = EPOLLIN;
    ev.data.ptr = one;

    one->idx = idx;
    one->fd = timerfd;
    one->timeout_ms = timeout;
    one->repeat = repeat;
    one->timer_cb = timeout_cb;
    one->arg = arg;
    epoll_ctl(tmr->epollfd, EPOLL_CTL_ADD, timerfd, &ev);    
    return idx;
}

/**
 * @brief           暂停一个软件定时器
 * 
 * @param tmr       定时器列表
 * @param id        定时器ID
 * @return int      0:成功
 *                  非0:失败
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_list_stop_one(timer_list_t tmr, int idx)
{
    if(tmr == NULL){
        return -1;
    }
    timer_list_pri_t *one = find_one_use_idx(tmr, idx);
    if(one == NULL){
        return 0;
    }
    if(one->used_flag > 0){
        struct epoll_event ev;
        epoll_ctl(tmr->epollfd, EPOLL_CTL_DEL, one->fd, &ev);
    }
    return 0;
}

/**
 * @brief           删除一个定时器
 * 
 * @param tmr       定时器列表
 * @param id        定时器ID
 * @return int 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_list_remove_one(timer_list_t tmr, int idx)
{
    if(tmr == NULL){
        return -1;
    }
    timer_list_pri_t*one = find_one_use_idx(tmr, idx);
    if(one == NULL){
        return 0;
    }
    if(one->used_flag == 0)
        return 0;
    pthread_spin_lock(tmr->lock);
    if(tmr->used_num > 0){
        --tmr->used_num;
        one->used_flag = 0;
        pthread_spin_unlock(tmr->lock);
    }
    else{
        pthread_spin_unlock(tmr->lock);
    }
    struct epoll_event ev;
    epoll_ctl(tmr->epollfd, EPOLL_CTL_DEL, one->fd, &ev); 
    close(one->fd);
    return 0;
}


/**
 * @brief           启动一个定时器
 * 
 * @param tmr       定时器列表
 * @param id        定时器ID
 * @return int      0:成功
 *                  非0:失败  
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_list_start_one(timer_list_t tmr, int idx)
{
    timer_list_pri_t*one = find_one_use_idx(tmr, idx);
    if(one == NULL){
        return -1;
    }
    int timerfd = one->fd;
    int timeout = one->timeout_ms;
    struct epoll_event ev;    
    __set_timerfd(timerfd, timeout);
    ev.events = EPOLLIN;
    ev.data.ptr = one;
    epoll_ctl(tmr->epollfd, EPOLL_CTL_ADD, timerfd, &ev);    
    return 0;
}


static int __timer_list_close(timer_list_t tmr)
{
    int i = 0;
    if(tmr == NULL){
        return 0;
    }
    close(tmr->epollfd);
    for(i = 0 ; i < tmr->max_sw_num; i++){
        timer_list_stop_one(tmr, i);
        timer_list_remove_one(tmr, i);        
    }
    if(tmr->lock){
        free(tmr->lock);
    }
    for(i=0;i<tmr->max_sw_num;i++){
        if(tmr->sw_array[i] != NULL){
            free(tmr->sw_array[i]);
        }
    }    
    free(tmr);

    return 0;
}

/**
 * @brief           !!!!!!关闭一个定时器列表!!!!!!!
 *                  使用定时器的进程退出前必须要调用，否则会导致定时器fd会不断创建
 * 
 * @param tmr 
 * @return int      0:成功
 *                  非0:失败  
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2023-12-11 <td>1.0     <td>dfs     <td>内容
 * </table>
 */
int timer_list_close(timer_list_t tmr)
{
    if(tmr == NULL){
        return 0;
    }
    tmr->used_num = 0;
    return 0;
}









