/*
 *****************************************************************************
 *                                                                           *
 *                 IMPINJ CONFIDENTIAL AND PROPRIETARY                       *
 *                                                                           *
 * This source code is the sole property of Impinj, Inc.  Reproduction or    *
 * utilization of this source code in whole or in part is forbidden without  *
 * the prior written consent of Impinj, Inc.                                 *
 *                                                                           *
 * (c) Copyright Impinj, Inc. 2009. All rights reserved.                     *
 *                                                                           *
 *****************************************************************************
 */

/*
 *****************************************************************************
 *
 * $Id: sample_list.c 59754 2009-09-08 17:07:45Z dshaheen $
 * 
 * Description:
 *     This file contains the implementation for a simple stack.
 *     
 *
 *****************************************************************************
 */

#include <assert.h>
#include "sample_list.h"

typedef struct listNode
{
    struct listNode*    pNext;
    struct listNode*    pPrevious;
    void*               pValue;
} LIST_NODE;

typedef struct
{
    LIST_NODE* pFront;
    LIST_NODE* pEnd;
} LIST;

/******************************************************************************
 * Name: ListCreate
 *
 * Description:
 *   Creates a new stack.
 ******************************************************************************/
LIST_HANDLE ListCreate(
    void
    )
{
    LIST* pList = (LIST *) malloc(sizeof(LIST));
    if (NULL != pList)
    {
        pList->pFront = pList->pEnd = NULL;
    }

    return (LIST_HANDLE) pList;
} /* ListCreate */

/******************************************************************************
 * Name: ListAddFront
 *
 * Description:
 *   Puts an item onto the front of a list
 ******************************************************************************/
INT32S ListAddFront(
    LIST_HANDLE list,
    void*       pValue
    )
{
    LIST*      pList  = (LIST *) list;
    LIST_NODE* pNode;
    
    assert(INVALID_LIST_HANDLE != list);

    pNode = (LIST_NODE *) malloc(sizeof(LIST_NODE));
    if (NULL != pNode)
    {
        pNode->pNext            = pList->pFront;
        pNode->pPrevious        = NULL;
        pNode->pValue           = pValue;
        if (NULL != pList->pFront)
        {
            pList->pFront->pPrevious = pNode;
        }
        pList->pFront           = pNode;
        if (NULL == pList->pEnd)
        {
            pList->pEnd = pNode;
        }
    }

    return NULL == pNode;
} /* ListAddFront */

/******************************************************************************
 * Name: ListAddEnd
 *
 * Description:
 *   Puts an item onto the end of a list
 ******************************************************************************/
INT32S ListAddEnd(
    LIST_HANDLE list,
    void*       pValue
    )
{
    LIST*      pList  = (LIST *) list;
    LIST_NODE* pNode;
    
    assert(INVALID_LIST_HANDLE != list);

    pNode = (LIST_NODE *) malloc(sizeof(LIST_NODE));
    if (NULL != pNode)
    {
        pNode->pNext            = NULL;
        pNode->pPrevious        = pList->pEnd;
        pNode->pValue           = pValue;
        if (NULL != pList->pEnd)
        {
            pList->pEnd->pNext = pNode;
        }
        pList->pEnd            = pNode;
        if (NULL == pList->pFront)
        {
            pList->pFront = pNode;
        }
    }

    return NULL == pNode;
} /* ListAddEnd */

/******************************************************************************
 * Name: ListRemoveFront
 *
 * Description:
 *   Removes the item from the front of the list
 ******************************************************************************/
void* ListRemoveFront(
    LIST_HANDLE list
    )
{
    LIST*   pList   = (LIST *) list;
    void*   pValue  = NULL;

    assert(INVALID_LIST_HANDLE != list);
    assert(!ListEmpty(list));

    if (NULL != pList->pFront)
    {
        LIST_NODE* pNode = pList->pFront;
        pList->pFront = pNode->pNext;
        if (NULL == pList->pFront)
        {
            pList->pEnd = NULL;
        }
        else
        {
            pList->pFront->pPrevious = NULL;
        }
        pValue = pNode->pValue;
        free(pNode);
    }

    return pValue;
} /* ListRemoveFront */

/******************************************************************************
 * Name: ListRemoveEnd
 *
 * Description:
 *   Removes the item from the front of the list
 ******************************************************************************/
void* ListRemoveEnd(
    LIST_HANDLE list
    )
{
    LIST*   pList   = (LIST *) list;
    void*   pValue  = NULL;

    assert(INVALID_LIST_HANDLE != list);
    assert(!ListEmpty(list));

    if (NULL != pList->pEnd)
    {
        LIST_NODE* pNode = pList->pEnd;
        pList->pEnd = pNode->pPrevious;
        if (NULL == pList->pEnd)
        {
            pList->pFront = NULL;
        }
        else
        {
            pList->pEnd->pNext = NULL;
        }
        pValue = pNode->pValue;
        free(pNode);
    }

    return pValue;
} /* ListRemoveEnd */

/******************************************************************************
 * Name: ListFront
 *
 * Description:
 *   Returns (but doesn't remove) the item at the front of the list
 ******************************************************************************/
void* ListFront(
    LIST_HANDLE list
    )
{
    assert(INVALID_LIST_HANDLE != list);
    assert(!ListEmpty(list));

    return ((LIST *) list)->pFront->pValue;
} /* ListFront */

/******************************************************************************
 * Name: ListEnd
 *
 * Description:
 *   Returns (but doesn't remove) the item at the front of the list
 ******************************************************************************/
void* ListEnd(
    LIST_HANDLE list
    )
{
    assert(INVALID_LIST_HANDLE != list);
    assert(!ListEmpty(list));

    return ((LIST *) list)->pEnd->pValue;
} /* ListEnd */

/******************************************************************************
 * Name: ListEmpty
 *
 * Description:
 *   Determines if the stack is empty
 ******************************************************************************/
int ListEmpty(
    LIST_HANDLE list
    )
{
    assert(INVALID_LIST_HANDLE != list);

    return NULL == ((LIST *) list)->pEnd;
} /* ListEmpty */

/******************************************************************************
 * Name: ListDestroy
 *
 * Description:
 *   Destroys the stack
 ******************************************************************************/
void ListDestroy(
    LIST_HANDLE list
    )
{
    assert(INVALID_LIST_HANDLE != list);

    /* Empty out the stack first                                              */
    while (!ListEmpty(list))
    {
        ListRemoveFront(list);
    }

    free((LIST *) list);
} /* ListDestroy */

