#include "basic.h"
#include "config.h"
#include "stack.h"

#ifdef CONFIG_INCLUDE_GENERIC_STACK

#define CONFIG_STACK_NUM_DESC (10)

static Stack freeStack;

static StackItem freeStackNodes[CONFIG_STACK_NUM_DESC];

static Stack freeStackStore[CONFIG_STACK_NUM_DESC];

__inline__ boolean stackIsEmpty(Stack * pStack)
{
  return ((pStack == NULL) ? 
		  false : 
		  (pStack->cursor == 0)
		  );
}

__inline__ boolean stackIsFull(Stack * pStack)
{
  return ((pStack == NULL) ? 
		  false : 
		  ((pStack->top - pStack->cursor) < 0)
		  );
}

int stackInit(void)
{
  int i;

  // initialize a local stack to allocate the stack nodes :-)

  for(i=0;i<CONFIG_STACK_NUM_DESC;i++)
    freeStackNodes[i] = &(freeStackStore[i]);

  freeStack.pData = (StackItem *)(&freeStackNodes);
  freeStack.top = (CONFIG_STACK_NUM_DESC - 1);
  freeStack.cursor = CONFIG_STACK_NUM_DESC;

  return 0;
}

static pStack allocStack(void)
{
  pStack pNewStack;
  
  if (stackPop(&freeStack, (StackItem *)(&pNewStack)) == 0)
    return pNewStack;
  else
    return NULL;
}

Stack * stackCreate(StackItem * pStackItems, int stackSize, boolean isEmpty)
{
  pStack pNewStack;

  pNewStack = allocStack();

  if (pNewStack != NULL) {
    pNewStack->pData = pStackItems;
    pNewStack->top = (stackSize - 1);
    pNewStack->cursor = ((isEmpty == true) ? 0 : stackSize);
    }

  return pNewStack;
}

int stackReturn(Stack * pRecycleStack)
{
  int retStat = -1;

  if ((pRecycleStack != NULL) && (stackIsFull(&freeStack) == false)) {
    stackPush(&freeStack, pRecycleStack);
    retStat = 0;
    }

  return retStat;
}

int stackPop(Stack * pStack, StackItem * pPopItem)
{
  int retStat = -1;

  if ((pStack != NULL) && (stackIsEmpty(pStack) == false)) {
    pStack->cursor--;
    *pPopItem = pStack->pData[pStack->cursor];
    retStat = 0;
    }

  return retStat;
}

int stackPush(Stack * pStack, StackItem pushItem)
{
  int retStat = -1;

  if ((pStack != NULL) && (stackIsFull(pStack) == false)) {
	pStack->pData[pStack->cursor] = pushItem;
	pStack->cursor++;
	retStat = 0;
	}

  return retStat;
}


#endif /* CONFIG_INCLUDE_GENERIC_STACK */
