/*#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <limits.h>
#include "Common.h"
#include "StringUtil.h"
#include "Config.h"
#include "Log.h"
*/
#include "DataStructure.h"

int InitLinkedList(struct LINKEDLISTINFO *pListInfo)
{
    //pListInfo->sDataMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_init(&pListInfo->sDataMutex, NULL);
    pthread_mutex_lock(&pListInfo->sDataMutex);
    pListInfo->pHeadNode = NULL;
    pListInfo->pCurrentNode = NULL;
    pListInfo->nNodeCount = 0;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int LinkedListAddNodeToHead(struct LINKEDLISTINFO *pListInfo, void *pData, struct LINKEDLISTNODE **ppNode)
{
    struct LINKEDLISTNODE *pNewNode;
    int nResult;

    pNewNode = NULL;
    pthread_mutex_lock(&pListInfo->sDataMutex);
    nResult = SafeMemoryAlloc((void **)&pNewNode, sizeof(struct LINKEDLISTNODE));
    //pNewNode = SafeAlloc(pNewNode, sizeof(struct LINKEDLISTNODE));
    pNewNode->pNodeData = pData;
    pNewNode->pNextNode = pListInfo->pHeadNode;
    pListInfo->pHeadNode = pNewNode;
    *ppNode = pNewNode;
    pListInfo->nNodeCount++;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int LinkedListMoveToHead(struct LINKEDLISTINFO *pListInfo, struct LINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    pListInfo->pCurrentNode = pListInfo->pHeadNode;
    *ppNode = pListInfo->pCurrentNode;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int LinkedListMoveToNext(struct LINKEDLISTINFO *pListInfo, struct LINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    pListInfo->pCurrentNode = pListInfo->pCurrentNode->pNextNode;
    *ppNode = pListInfo->pCurrentNode;

    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int LinkedListGetCurrentNode(struct LINKEDLISTINFO *pListInfo, struct LINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    *ppNode = pListInfo->pCurrentNode;

    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int LinkedListRemoveHeadNode(struct LINKEDLISTINFO *pListInfo, struct LINKEDLISTNODE **ppNode)
{

    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pHeadNode == NULL)
    {
        *ppNode = NULL;
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    *ppNode = pListInfo->pHeadNode;

    pListInfo->pHeadNode = pListInfo->pHeadNode->pNextNode;
    pListInfo->nNodeCount--;

    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int LinkedListNodeExist(struct LINKEDLISTINFO *pListInfo, int *bNodeExist)
{

    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pHeadNode == NULL)
    {
        *bNodeExist = false;
    }
    else
    {
        *bNodeExist = true;
    }

    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}


int InitDoubleLinkedList(struct DOUBLELINKEDLISTINFO *pListInfo)
{
    //pListInfo->sDataMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_init(&pListInfo->sDataMutex, NULL);
    pthread_mutex_lock(&pListInfo->sDataMutex);
    pListInfo->pHeadNode = NULL;
    pListInfo->pTailNode = NULL;
    pListInfo->pCurrentNode = NULL;
    pListInfo->nNodeCount = 0;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int DoubleLinkedListAddNodeToHead(struct DOUBLELINKEDLISTINFO *pListInfo, void *pData, struct DOUBLELINKEDLISTNODE **ppNode)
{
    struct DOUBLELINKEDLISTNODE *pNewNode;
    int nResult;

    pNewNode = NULL;
    pthread_mutex_lock(&pListInfo->sDataMutex);
    nResult = SafeMemoryAlloc((void **)&pNewNode, sizeof(struct DOUBLELINKEDLISTNODE));
    //pNewNode = SafeAlloc(pNewNode, sizeof(struct DOUBLELINKEDLISTNODE));
    pNewNode->pNodeData = pData;
    pNewNode->pNextNode = pListInfo->pHeadNode;
    pNewNode->pPrevNode = NULL;
    if (pListInfo->pHeadNode != NULL)
    {
        pListInfo->pHeadNode->pPrevNode = pNewNode;
    }
    pListInfo->pHeadNode = pNewNode;
    if (pListInfo->pTailNode == NULL)
    {
        pListInfo->pTailNode = pNewNode;
    }
    *ppNode = pNewNode;
    pListInfo->nNodeCount++;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int DoubleLinkedListAddNodeToTail(struct DOUBLELINKEDLISTINFO *pListInfo, void *pData, struct DOUBLELINKEDLISTNODE **ppNode)
{
    struct DOUBLELINKEDLISTNODE *pNewNode;
    int nResult;

    pNewNode = NULL;
    pthread_mutex_lock(&pListInfo->sDataMutex);
    nResult = SafeMemoryAlloc((void **)&pNewNode, sizeof(struct DOUBLELINKEDLISTNODE));
    //pNewNode = SafeAlloc(pNewNode, sizeof(struct DOUBLELINKEDLISTNODE));
    pNewNode->pNodeData = pData;
    pNewNode->pNextNode = NULL;
    pNewNode->pPrevNode = pListInfo->pTailNode;
    if (pListInfo->pTailNode != NULL)
    {
        pListInfo->pTailNode->pNextNode = pNewNode;
    }
    pListInfo->pTailNode = pNewNode;
    if (pListInfo->pHeadNode == NULL)
    {
        pListInfo->pHeadNode = pNewNode;
    }
    *ppNode = pNewNode;
    pListInfo->nNodeCount++;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int DoubleLinkedListMoveToHead(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{
    int nResult;

    nResult = DS_ERR_SUCCESS;
    pthread_mutex_lock(&pListInfo->sDataMutex);
    pListInfo->pCurrentNode = pListInfo->pHeadNode;
    *ppNode = pListInfo->pCurrentNode;
    if (pListInfo->pCurrentNode == NULL)
    {
        nResult = DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return nResult;
}

int DoubleLinkedListMoveToTail(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{
    int nResult;

    nResult = DS_ERR_SUCCESS;
    pthread_mutex_lock(&pListInfo->sDataMutex);
    pListInfo->pCurrentNode = pListInfo->pTailNode;
    *ppNode = pListInfo->pCurrentNode;
    if (pListInfo->pCurrentNode == NULL)
    {
        nResult = DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return nResult;
}

int DoubleLinkedListMoveToNext(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pListInfo->pCurrentNode = pListInfo->pCurrentNode->pNextNode;
    *ppNode = pListInfo->pCurrentNode;

    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int DoubleLinkedListMoveToPrev(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pListInfo->pCurrentNode = pListInfo->pCurrentNode->pPrevNode;
    *ppNode = pListInfo->pCurrentNode;

    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int DoubleLinkedListGetCurrentNode(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    *ppNode = pListInfo->pCurrentNode;

    if (pListInfo->pCurrentNode == NULL)
    {
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int DoubleLinkedListRemoveHeadNode(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{

    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pHeadNode == NULL)
    {
        *ppNode = NULL;
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    *ppNode = pListInfo->pHeadNode;

    pListInfo->pHeadNode = pListInfo->pHeadNode->pNextNode;

    if (pListInfo->pHeadNode == NULL)
    {
        pListInfo->pTailNode = NULL;
    }
    else
    {
        pListInfo->pHeadNode->pPrevNode = NULL;
    }

    (*ppNode)->pPrevNode = NULL;
    (*ppNode)->pNextNode = NULL;
    pListInfo->nNodeCount--;
    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int DoubleLinkedListRemoveTailNode(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{

    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pTailNode == NULL)
    {
        *ppNode = NULL;
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }
    *ppNode = pListInfo->pTailNode;
    pListInfo->pTailNode = pListInfo->pTailNode->pPrevNode;

    if (pListInfo->pTailNode == NULL)
    {
        pListInfo->pHeadNode = NULL;
    }
    else
    {
        pListInfo->pTailNode->pNextNode = NULL;
    }
    (*ppNode)->pPrevNode = NULL;
    (*ppNode)->pNextNode = NULL;
    pListInfo->nNodeCount--;

    pthread_mutex_unlock(&pListInfo->sDataMutex);

    return DS_ERR_SUCCESS;
}

int DoubleLinkedListNodeExist(struct DOUBLELINKEDLISTINFO *pListInfo, int *bNodeExist)
{

    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pHeadNode == NULL)
    {
        *bNodeExist = false;
    }
    else
    {
        *bNodeExist = true;
    }

    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;
}

int DoubleLinkedListRemoveCurrentNode(struct DOUBLELINKEDLISTINFO *pListInfo, struct DOUBLELINKEDLISTNODE **ppNode)
{
    pthread_mutex_lock(&pListInfo->sDataMutex);
    if (pListInfo->pCurrentNode == NULL)
    {
        WriteTraceLog(LogType_ErrorOut, LogLevel_Error, __FILE__, __LINE__, __FUNCTION__, "Current node is not set");
        pthread_mutex_unlock(&pListInfo->sDataMutex);
        return DS_ERR_EMPTY_NODE;
    }

    pListInfo->nNodeCount--;
    if (pListInfo->pHeadNode == pListInfo->pCurrentNode && pListInfo->pTailNode == pListInfo->pCurrentNode)
    {
        *ppNode = pListInfo->pCurrentNode;
        pListInfo->pHeadNode = NULL;
        pListInfo->pTailNode = NULL;
        pListInfo->pCurrentNode = NULL;
    }
    else
    {
        *ppNode = pListInfo->pCurrentNode;
        if (pListInfo->pCurrentNode == pListInfo->pHeadNode)
        {
            pListInfo->pHeadNode = pListInfo->pHeadNode->pNextNode;
        }
        if (pListInfo->pCurrentNode == pListInfo->pTailNode)
        {
            pListInfo->pTailNode = pListInfo->pTailNode->pPrevNode;
        }
        if (pListInfo->pCurrentNode->pPrevNode != NULL)
        {
            pListInfo->pCurrentNode->pPrevNode->pNextNode = pListInfo->pCurrentNode->pNextNode;
        }
        if (pListInfo->pCurrentNode->pNextNode != NULL)
        {
            pListInfo->pCurrentNode->pNextNode->pPrevNode = pListInfo->pCurrentNode->pPrevNode;
        }
        pListInfo->pCurrentNode = pListInfo->pCurrentNode->pNextNode;

/*
        if (pListInfo->pCurrentNode == NULL)
        {
            pthread_mutex_unlock(&pListInfo->sDataMutex);
            return DS_ERR_EMPTY_NODE;
        }
*/
    }
    pthread_mutex_unlock(&pListInfo->sDataMutex);
    return DS_ERR_SUCCESS;

}

int DoubleLinkedListClear(struct DOUBLELINKEDLISTINFO *pListInfo)
{
    struct DOUBLELINKEDLISTNODE *pNode;
    bool bNodeExist;

    DoubleLinkedListMoveToHead(pListInfo, &pNode);
    DoubleLinkedListNodeExist(pListInfo, &bNodeExist);
    while (bNodeExist)
    {
        DoubleLinkedListRemoveCurrentNode(pListInfo, &pNode);
        DoubleLinkedListNodeExist(pListInfo, &bNodeExist);
        SafeFree(&pNode->pNodeData);
        SafeFree(&pNode);
    }
    return DS_ERR_SUCCESS;
}
