/*!
 * \file deque08.c
 * \brief
 *    This file provides double ended queue capability based on a ring buffer
 *
 * Author: Christos Choutouridis AEM: 8997
 * email : <cchoutou@ece.auth.gr>
 *
 */
#include "deque08.h"


/*
 *  ============= Private Queue API =============
 */
static iterator_t _preInc(deque08_t *q, iterator_t* it) {
   return (++*it >= q->capacity) ? *it=0 : *it;
}

static iterator_t _preDec(deque08_t *q, iterator_t* it) {
   return (--*it < 0) ? *it=q->capacity-1 : *it;
}

static iterator_t _postInc(deque08_t *q, iterator_t* it) {
   iterator_t ret = *it;
   if (++*it >= q->capacity) *it=0;
   return ret;
}

static iterator_t _postDec(deque08_t *q, iterator_t* it) {
   iterator_t ret = *it;
   if (--*it < 0) *it=q->capacity-1;
   return ret;
}
/*
 *  ============= Public Queue API =============
 */

/*
 * Link and Glue functions
 */
void deque08_link_buffer (deque08_t *q, byte_t* buf) {
   q->m = buf;
}

/*
 * Set functions
 */
inline void deque08_set_capacity (deque08_t *q, size_t capacity) {
   q->capacity = capacity;
}

/*
 * User Functions
 */


/*!
 * \brief
 *    Check if deque is full
 * \param   q     Which deque to check
 * \return
 *    \arg  0     Not full
 *    \arg  1     Full
 */
int deque08_is_full (deque08_t *q) {
   return (q->items == q->capacity) ? 1:0;
}

/*!
 * \brief
 *    Check if deque is empty
 * \param   q     Which deque to check
 * \return
 *    \arg  0     Not empty
 *    \arg  1     Empty
 */
int deque08_is_empty (deque08_t *q) {
   return (q->items) ? 0:1;
}

/*!
 * \brief
 *    Return the number of items on deque
 * \param   q     Which deque to check
 */
int  deque08_size (deque08_t *q) {
   return q->items;
}

/*!
 * \brief
 *    Discard all items in deque
 * \param   q     Which deque to check
 */
void  deque08_flush (deque08_t *q) {
   deque08_init(q);
}



/*!
 * \brief
 *    Initialize the queue
 * \param   queue    Which queue to init
 */
void deque08_init (deque08_t *q) {
   q->f = 0;
   q->r = -1;
   q->items =0;
}

/*!
  * \brief
  *   This function push a byte in front of deque.
  * \param  q  Pointer to deque to use
  * \param  b  byte to push
  * \return
  *   \arg  0  Full queue
  *   \arg  1  Done
 */
int deque08_push_front (deque08_t *q, byte_t b) {
   if (deque08_is_full (q) == 1)  //full queue
      return 0;
   q->m [_preDec (q, &q->f)] = b;
   ++q->items;
   return 1;
}

/*!
  * \brief
  *   This function pops a byte from the front of the deque.
  * \param  q  Pointer to deque to use
  * \param  b  Pointer to byte to return
  * \return
  *   \arg  0  Empty queue
  *   \arg  1  Done
 */
int deque08_pop_front (deque08_t *q, byte_t *b) {
   if (deque08_is_empty (q) == 1)  //empty queue
      return 0;
   *b = q->m [_postInc (q, &q->f)];
   --q->items;
   return 1;
}

/*!
  * \brief
  *   This function push a byte in the back of deque.
  * \param  q  Pointer to deque to use
  * \param  b  byte to push
  * \return
  *   \arg  0  Full queue
  *   \arg  1  Done
 */
int deque08_push_back (deque08_t *q, byte_t b) {
   if (deque08_is_full (q) == 1)  //full queue
      return 0;
   q->m [_preInc (q, &q->r)] = b;
   ++q->items;
   return 1;
}

/*!
  * \brief
  *   This function pops a byte from the back of the deque.
  * \param  q  Pointer to deque to use
  * \param  b  Pointer to byte to return
  * \return
  *   \arg  0  Empty queue
  *   \arg  1  Done
 */
int deque08_pop_back (deque08_t *q, byte_t *b) {
   if (deque08_is_empty (q) == 1)  //empty queue
      return 0;
   *b = q->m [_postDec (q, &q->r)];
   --q->items;
   return 1;
}

/*!
  * \brief
  *   This function gives the last item in the back of deque.
  * \param  q  Pointer to deque to use
  * \param  b  Pointer to byte to return
  * \return
  *   \arg  0  Empty queue
  *   \arg  1  Done
 */
int deque08_back (deque08_t *q, byte_t *b) {
   if (deque08_is_empty (q) == 1)  //empty queue
      return 0;
   *b = q->m [q->r];
   return 1;
}

/*!
  * \brief
  *   This function gives the first item in the front of deque.
  * \param  q  Pointer to deque to use
  * \param  b  Pointer to byte to return
  * \return
  *   \arg  0  Empty queue
  *   \arg  1  Done
 */
int deque08_front (deque08_t *q, byte_t *b) {
   if (deque08_is_empty (q) == 1)  //empty queue
      return 0;
   *b = q->m [q->f];
   return 1;
}
