/*
 * $Id$
 */

/**
 * prtTutorial-Stack.c is part of the Pointer Tutorial for ROBOTC
 *
 * Changelog:
 * - 0.1: Initial release
 *
 * License: You may use this code as you wish, provided you give credit where it's due.
 *
 * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 3.54 AND HIGHER.
 * Xander Soldaat (xander_at_botbench.com)
 * 20 January 2013
 * version 0.1
 */

#define MAX_STACK_SIZE 5                // Maximum number of elements in the Stack

#define isEmpty(X)    (X->size == 0)
#define isFull(X)     (X->size == MAX_STACK_SIZE)

// Individual stack element struct
struct tStackElement
{
  int value;                            // value held by element
} tStackElement;

// Stack struct to hold the elements
struct tStack
{
  tStackElement elements[MAX_STACK_SIZE]; // array of elements
  int size;                               // current size of the stack
} tStack;

//#include "stack-visualiser.h"

tStack myStack;

bool push(tStack *stack, int value);
int pop(tStack *stack);
void initStack(tStack *stack);
void printStack(tStack *stack);


/**
 * Push a new value onto the top of the stack.
 * @param stack the stack to manipulate
 * @param value the value to be pushed onto the stack
 * @return true if a node with this value was pushed succesfully, false if it was not found
 */
bool push(tStack *stack, int value)
{
  if (isFull(stack))
  {
    writeDebugStreamLine("Stack already at max size");
    return false;
  }

  stack->elements[stack->size++].value = value;
  writeDebugStreamLine("push: value: %d, size: %d", value, stack->size);
  return true;
}


/**
 * Pop the last element and return its value
 * @param stack the stack to manipulate
 * @return the value to be popped off the stack
 */
int pop(tStack *stack)
{
  int value;

  if (isEmpty(stack))
  {
    writeDebugStreamLine("Stack empty");
    return 0;
  }

  // Decrement size and pop and value from the stack
  value = stack->elements[--stack->size].value;
  writeDebugStreamLine("pop: value: %d, size: %d", value, stack->size);
  return value;
}


/**
 * Take a sneak peek at the last element and return its value. This does not modify
 * the stack
 * @param stack the stack to manipulate
 * @param value the value to be peeked at
 * @return the value to be peeked at
 */
int peek(tStack *stack)
{
  int value;
  int index = stack->size - 1;
  if (isEmpty(stack))
  {
    writeDebugStreamLine("Stack empty");
    return 0;
  }

  value = stack->elements[index].value;
  writeDebugStreamLine("peek: value: %d, size: %d", value, stack->size);
  return value;
}


/**
 * Initialise the stack
 * @param stack the stack to manipulate
 */
void initStack(tStack *stack)
{
  // reset the size of the stack
  stack->size = 0;
  memset(stack->elements, 0, sizeof(stack->elements));
}


/**
 * Print the contents of the stack
 * @param stack the stack to manipulate
 */
void printStack(tStack *stack)
{
  writeDebugStreamLine("printStack");
  for (int i = 0; i < stack->size; i++)
  {
    writeDebugStreamLine("%d : %d", i, stack->elements[i].value);
  }
}


task main ()
{
  int value = 0;
  initStack(&myStack);

  // Fill our stack
  for (int i = 0; i < MAX_STACK_SIZE; i++)
  {
    push(&myStack, rand() % 100);
  }

  printStack(&myStack);

  // Empty our stack
  for (int i = 0; i < MAX_STACK_SIZE; i++)
  {
    value = pop(&myStack);
  }
}
