/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */

#include "log_queue.h"
#include "log_common.h"
#include "log_print.h"

void XFreeLogNode(LogNode** node)
{
    ONE_ACT_WARN_LOG(node == NULL, return, "[input] log node pointer is null.");
    ONE_ACT_WARN_LOG(*node == NULL, return, "[input] log node is null.");

    LogNode* tmp = (LogNode*)*node;
    XFREE(tmp->stNodeData);
    XFREE(tmp);
    *node = NULL;
}

LogRt LogQueueInit(LogQueue* queue, uint32_t deviceId)
{
    ONE_ACT_WARN_LOG(queue == NULL, return ARGV_NULL, "[input] queue is null.");

    queue->deviceId = deviceId;
    queue->uiCount = 0;
    queue->uiSize = 0;
    queue->stHead = NULL;
    queue->stRear = NULL;
    return SUCCESS;
}

// not free log_queue
LogRt LogQueueFree(LogQueue* queue, void (*freeNode)(LogNode**))
{
    ONE_ACT_NO_LOG(queue == NULL, return ARGV_NULL);
    ONE_ACT_WARN_LOG(freeNode == NULL, return ARGV_NULL, "[input] node free function is null");

    LogNode* tmp = NULL;
    int32_t num = (int32_t)queue->uiCount;
    for (int32_t i = 0; i < num; i++) {
        LogRt ret = LogQueueDequeue(queue, &tmp);
        if (ret == QUEUE_IS_NULL) {
            break;
        }
        freeNode(&tmp);
    }

    return SUCCESS;
}

LogRt LogQueueEnqueue(LogQueue* queue, LogNode* node)
{
    ONE_ACT_WARN_LOG(queue == NULL, return ARGV_NULL, "[input] queue is null.");
    ONE_ACT_WARN_LOG(node == NULL, return ARGV_NULL, "[input] log node is null.");
    ONE_ACT_WARN_LOG(node->uiNodeDataLen == 0, return ARGV_NULL, "[input] log node is empty.");

    // queue would be more than max_size, but node max_count
    if (LogQueueFull(queue) != SUCCESS) {
        SELF_LOG_INFO("queue is full.");
        return QUEUE_IS_FULL;
    }

    if (LogQueueNULL(queue) != SUCCESS) {
        queue->stHead = node;
        queue->stRear = node;
        queue->uiCount = 1;
        queue->uiSize = node->uiNodeDataLen;
    } else {
        queue->stRear->next = node; // firstly, join the node to list
        queue->stRear = node;       // secondly, mv stRear to listRear
        queue->uiCount++;
        queue->uiSize += node->uiNodeDataLen;
    }

    return SUCCESS;
}

LogRt LogQueueDequeue(LogQueue* queue, LogNode** node)
{
    ONE_ACT_WARN_LOG(queue == NULL, return ARGV_NULL, "[input] queue is null.");
    ONE_ACT_WARN_LOG(node == NULL, return ARGV_NULL, "[input] log node is null.");

    if (LogQueueNULL(queue) != SUCCESS) {
        return QUEUE_IS_NULL;
    }

    *node = queue->stHead; // get head
    if (queue->uiCount == 1) {
        (void)LogQueueInit(queue, queue->deviceId);
    } else {
        LogNode* tmp = queue->stHead;
        queue->uiCount--;
        queue->uiSize -= tmp->uiNodeDataLen;
        queue->stHead = tmp->next;
        tmp->next = NULL;
    }

    return SUCCESS;
}

LogRt LogQueueFull(const LogQueue* queue)
{
    ONE_ACT_WARN_LOG(queue == NULL, return ARGV_NULL, "[input] queue is null.");

    if ((queue->uiCount >= MAX_QUEUE_COUNT) || (queue->uiSize >= MAX_QUEUE_SIZE)) {
        return QUEUE_IS_FULL;
    }

    return SUCCESS;
}

LogRt LogQueueNULL(const LogQueue* queue)
{
    ONE_ACT_WARN_LOG(queue == NULL, return ARGV_NULL, "[input] queue is null.");

    if ((queue->uiCount == 0) || (queue->uiSize == 0) || ((queue->stHead == NULL) && (queue->stRear == NULL))) {
        return QUEUE_IS_NULL;
    }

    return SUCCESS;
}