/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/
/*************************************************************************/
/* module:         XLT Decoder Stack                                     */
/* file:           XLTUtilStack.c                                        */
/* target system:  all                                                   */
/* target OS:      all                                                   */
/*************************************************************************/


/**
 * A simple array-based stack implementation.
 */

/*************************************************************************/
/* Definitions                                                           */
/*************************************************************************/

#include "xltdeccom.h"
#include "xltutilstack.h"

#include <smlerr.h>

#include <libmem.h>

struct ArrayStack_s;
typedef struct ArrayStack_s *ArrayStackPtr_t, ArrayStack_t;
struct ArrayStack_s
{
    /* public */
    Ret_t (*top)(const XltUtilStackPtr_t, XltUtilStackItem_t *);
    Ret_t (*pop)(XltUtilStackPtr_t, XltUtilStackItem_t *);
    Ret_t (*push)(XltUtilStackPtr_t, const XltUtilStackItem_t);
    Ret_t (*destroy)(XltUtilStackPtr_t);

    /* private */
    Long_t topidx;          // index of the top of the stack 
    Long_t size;            // size of the stack (multiple of chunksize)
    Long_t chunksize;       // size of memory chunks allocated at a time
    XltUtilStackItem_t *array;     // the stack itself
};

static Ret_t _top(const XltUtilStackPtr_t, XltUtilStackItem_t *);
static Ret_t _pop(XltUtilStackPtr_t, XltUtilStackItem_t *);
static Ret_t _push(XltUtilStackPtr_t, const XltUtilStackItem_t);
static Ret_t _destroy(XltUtilStackPtr_t);

/*************************************************************************/
/* External Functions                                                    */
/*************************************************************************/

Ret_t
xltUtilCreateStack(XltUtilStackPtr_t *ppStack, const Long_t size)
{
    ArrayStackPtr_t pStack;

    if (size <= 0)
        return SML_ERR_WRONG_PARAM;
        if ((pStack = (ArrayStackPtr_t)smlLibMalloc(sizeof(ArrayStack_t))) == NULL) {
 		*ppStack = NULL;
           return SML_ERR_NOT_ENOUGH_SPACE;
 	}

    pStack->top = _top;
    pStack->pop = _pop;
    pStack->push = _push;
    pStack->destroy = _destroy;
    pStack->topidx = -1;
    pStack->size = size;
    pStack->chunksize = size;
    pStack->array = NULL;
    if ((pStack->array = (XltUtilStackItem_t*)smlLibMalloc(size * sizeof(XltUtilStackItem_t))) == NULL) {
 		*ppStack = NULL;
 		smlLibFree(pStack);
        return SML_ERR_NOT_ENOUGH_SPACE;
 	}

    *ppStack = (XltUtilStackPtr_t)pStack;
	
	

    return SML_ERR_OK;
}

/*************************************************************************/
/* Internal Functions                                                    */
/*************************************************************************/

static Ret_t
_top(const XltUtilStackPtr_t pStack, XltUtilStackItem_t *itemPtr)
{
    ArrayStackPtr_t pStackPriv = (ArrayStackPtr_t)pStack; 

    if (pStackPriv->topidx == -1)
        return SML_ERR_WRONG_USAGE;

    *itemPtr = pStackPriv->array[pStackPriv->topidx];

    return SML_ERR_OK;
}

static Ret_t
_pop(XltUtilStackPtr_t pStack, XltUtilStackItem_t *itemPtr)
{
    ArrayStackPtr_t pStackPriv = (ArrayStackPtr_t)pStack; 
    XltUtilStackItem_t item;

    if (pStackPriv->topidx == -1)
        return SML_ERR_WRONG_USAGE;

    item = pStackPriv->array[pStackPriv->topidx]; 
    pStackPriv->topidx--;

    if ((pStackPriv->topidx >= 0) && 
            (pStackPriv->topidx < pStackPriv->size - pStackPriv->chunksize)) {
        Long_t newsize;
        XltUtilStackItem_t *newarray;

        newsize = pStackPriv->size - pStackPriv->chunksize;
        if ((newarray = (XltUtilStackItem_t*)smlLibRealloc(pStackPriv->array,
                        newsize * sizeof(XltUtilStackItem_t))) != NULL) {
            pStackPriv->size = newsize;
            pStackPriv->array = newarray;
        } else {
            return SML_ERR_NOT_ENOUGH_SPACE;
        }
    }

    *itemPtr = item;

    return SML_ERR_OK;
}

static Ret_t
_push(XltUtilStackPtr_t pStack, const XltUtilStackItem_t item)
{
    ArrayStackPtr_t pStackPriv = (ArrayStackPtr_t)pStack; 

    if (pStackPriv->topidx == pStackPriv->size - 1) {
        Long_t newsize;
        XltUtilStackItem_t *newarray;

        newsize = pStackPriv->size + pStackPriv->chunksize;
        if ((newarray = (XltUtilStackItem_t*)smlLibRealloc(pStackPriv->array,
                        newsize * sizeof(XltUtilStackItem_t))) != NULL) {
            pStackPriv->size = newsize;
            pStackPriv->array = newarray;
        } else {
            return SML_ERR_NOT_ENOUGH_SPACE;
        }
    }

    pStackPriv->topidx++;
    pStackPriv->array[pStackPriv->topidx] = item;

    return SML_ERR_OK;
}

static Ret_t
_destroy(XltUtilStackPtr_t pStack)
{
    ArrayStackPtr_t pStackPriv; 

    if (pStack == NULL)
        return SML_ERR_OK;

    pStackPriv = (ArrayStackPtr_t)pStack; 

    smlLibFree(pStackPriv->array);
    smlLibFree(pStackPriv);
    return SML_ERR_OK;
}
