/************************************************************************
 * AUTHOR: NiuJiuRu
 * FILENAME: swstack.c
 * DESCRIPTION: 内存栈-先进后出
 * NOTE:
 * HISTORY:
 * 1, [2014-01-15] created by NiuJiuRu
 * 2, [2016-08-08] 添加互斥锁, 保障线程安全
 ***********************************************************************/
#include "swapi.h"
#include "swmutex.h"
#include "swmem.h"

// node
struct stk_node
{
    struct stk_data data;
    struct stk_node *next;
};

// stack
struct stk_stack
{
    void *hMem;
    struct stk_node *top;
    int nodesCnt;
    void *hMutex;
};

// 创建一个栈, "hMem"为空时在系统内存中创建, "hMem"不为空时在给定的内存中创建
void *sw_stack_create(void *hMem)
{
    struct stk_stack *newStack = NULL;

    newStack = (struct stk_stack *)(hMem ? sw_mem_alloc(hMem, sizeof(struct stk_stack), __FILE__, __LINE__) : \
                                           malloc(sizeof(struct stk_stack)));
    if(newStack)
    {
        newStack->hMem = hMem;
        newStack->top = NULL;
        newStack->nodesCnt = 0;
        newStack->hMutex = sw_mutex_create();
        if(!newStack->hMutex)
        {
            newStack->hMem ? sw_mem_free(newStack->hMem, newStack, __FILE__, __LINE__) : free(newStack);
            return NULL;
        }
    }

    return newStack;
}

// 数据压栈
bool sw_stack_push(void *hStack, struct stk_data data)
{
    struct stk_stack *theStack = (struct stk_stack *)hStack;
    struct stk_node *newNode = NULL;

    if(theStack)
    {
        newNode = (struct stk_node *)(theStack->hMem ? sw_mem_alloc(theStack->hMem, sizeof(struct stk_node), __FILE__, __LINE__) : \
                                                       malloc(sizeof(struct stk_node)));
        if(newNode)
        {
            newNode->data.addr = data.addr;
            newNode->data.size = data.size;
            newNode->data.freeFun = data.freeFun;
            newNode->data.wParam = data.wParam;
            newNode->data.lParam = data.lParam;

            sw_mutex_lock(theStack->hMutex, WAIT_FOREVER); // lock
            newNode->next = theStack->top;
            theStack->top = newNode;
            theStack->nodesCnt += 1;
            sw_mutex_unlock(theStack->hMutex); // unlock

            return true;
        }
    }

    return false;
}

// 数据弹出栈
// 注意: 如果只弹出数据而不接收结果("result"为空时), 弹出过程中将会自动调用数据压栈时设定的内存释放回调函数
void sw_stack_pop(void *hStack, struct stk_data *result)
{
    struct stk_stack *theStack = (struct stk_stack *)hStack;
    struct stk_node *topNode = NULL;

    if(theStack && theStack->top)
    {
        sw_mutex_lock(theStack->hMutex, WAIT_FOREVER); // lock
        topNode = theStack->top;
        theStack->top = theStack->top->next;
        theStack->nodesCnt -= 1;
        sw_mutex_unlock(theStack->hMutex); // unlock

        if(result)
        {
            result->addr = topNode->data.addr;
            result->size = topNode->data.size;
            result->freeFun = topNode->data.freeFun;
            result->wParam = topNode->data.wParam;
            result->lParam = topNode->data.lParam;
        }
        else
        {
            if(topNode->data.freeFun) topNode->data.freeFun((void *)topNode->data.addr, topNode->data.size);
        }

        theStack->hMem ? sw_mem_free(theStack->hMem, topNode, __FILE__, __LINE__) : free(topNode);
    }
}

// 得到一个栈内当前的数据元个数
int sw_stack_getDataElementsCnt(const void *hStack)
{
    struct stk_stack *theStack = (struct stk_stack *)hStack;
    int num;

    if(theStack)
    {
        sw_mutex_lock(theStack->hMutex, WAIT_FOREVER); // lock
        num = theStack->nodesCnt;
        sw_mutex_unlock(theStack->hMutex); // unlock
    }
    else num = -1;

    return num;
}

// 销毁一个栈, 并在销毁过程中自动调用数据压栈时设定的内存释放回调函数
void sw_stack_destroy(void *hStack)
{
    struct stk_stack *theStack = (struct stk_stack *)hStack;
    struct stk_node *delNode = NULL, *nextNode = NULL;

    if(theStack)
    {
        delNode = theStack->top;
        while(delNode)
        {
            nextNode = delNode->next;
            if(delNode->data.freeFun) delNode->data.freeFun((void *)delNode->data.addr, delNode->data.size);
            theStack->hMem ? sw_mem_free(theStack->hMem, delNode, __FILE__, __LINE__) : free(delNode);
            delNode = nextNode;
        }

        sw_mutex_destroy(theStack->hMutex);

        theStack->hMem ? sw_mem_free(theStack->hMem, theStack, __FILE__, __LINE__) : free(theStack);
    }
}
