//
// Created by xajhu on 2021/7/1 0001.
//

#include <stdlib.h>
#include "task_manager.h"
#include "common.h"
#include "uthash/utlist.h"
#include "user_errno.h"
#include "zlog_module.h"

typedef struct SYSTEM_EXIT_CONTENT {
    system_exit_cb              cb;
    void                       *pUserData;
    struct SYSTEM_EXIT_CONTENT *next, *prev;
} SYSTEM_EXIT_CONTENT, *PSYSTEM_EXIT_CONTENT;

static uv_loop_t           *g_pMainTaskLoop   = NULL;
static int                  g_taskManagerExit = FALSE;
static int                  g_isSystemExit    = FALSE;
static PSYSTEM_EXIT_CONTENT g_sysExitCtx      = NULL;

uv_loop_t *get_task_manager(void) {
    if (g_pMainTaskLoop == NULL) {
        g_pMainTaskLoop = uv_default_loop();
    }

    return g_pMainTaskLoop;
}

void task_manager_exit() {
    g_taskManagerExit = TRUE;
}

int is_system_cleanup() {
    return g_isSystemExit;
}

static int is_task_exit() {
    return g_taskManagerExit;
}

int task_add_exit_event_handler(system_exit_cb cb, void *userdata) {
    PSYSTEM_EXIT_CONTENT pCtx;
    if (cb != NULL) {
        pCtx = (PSYSTEM_EXIT_CONTENT)malloc(sizeof(SYSTEM_EXIT_CONTENT));

        if (pCtx) {
            pCtx->cb        = cb;
            pCtx->pUserData = userdata;
            LL_APPEND(g_sysExitCtx, pCtx);
            return ERR_SUCCESS;
        }

        return -ERR_MALLOC_MEMORY;
    }

    return ERR_SUCCESS;
}

void task_manager_run() {
    int                  more;
    PSYSTEM_EXIT_CONTENT pCtx, pTmp;

    if (g_pMainTaskLoop == NULL) {
        g_pMainTaskLoop = uv_default_loop();
    }

    while (!is_task_exit()) {
        more = uv_run(g_pMainTaskLoop, UV_RUN_ONCE);

        if (more == FALSE) {
            more = uv_loop_alive(g_pMainTaskLoop);

            if (uv_run(g_pMainTaskLoop, UV_RUN_NOWAIT) != 0) {
                more = TRUE;
            }
        }
    }

    LL_FOREACH_SAFE(g_sysExitCtx, pCtx, pTmp) {
        pCtx->cb(pCtx->pUserData);
        LL_DELETE(g_sysExitCtx, pCtx);
        free(pCtx);
    }

    LOG_MOD(info, ZLOG_MOD_TASK, "Main task exited..............\n");
    g_isSystemExit = TRUE;
}