#include "RingBuffer.h"

/* These are just to reduce code redundancy.
 */
#define err_on_full(S, E) {\
  if (self->len >= S->size) {\
    E = TRUE;\
    s_err_print ("Buffer full. Needs to be reallocated.\n"\
                 "    (This is not done automatically. Returning.)");\
    return;\
  }\
}

#define err_seems_full(E) {\
  s_err_print ("Array seems to be full... Returning.");\
  E = TRUE;\
  return;\
}

#define err_on_empty(S, E) {\
  if (s_ring_buffer_is_empty (S)) {\
    s_warn_print ("Ring buffer is empty, nothing to return");\
    E = TRUE;\
    return 0;\
  }\
}


struct SRingBuffer {
  size_t size;   /* The number of elemets in the array */
  size_t len;    /* The "length" of the buffered data */
  
  size_t start;  /* The index of the "first" element in the buffer in the array
                  */
  size_t end;    /* The index of the "last" element in the buffer in the array
                  */
  
  sbyte * array; /* The array that is used to implement the buffer */
}


SRingBuffer *
s_ring_buffer_new (size_t len) {
  SRingBuffer * self = s_malloc (sizeof (SRingBuffer));
  self->array = s_calloc (len, size_t (sbyte));
  
  self->size = size;
  self->start = 0;
  self->end = 0;
  self->len = 0;
  
  return self;
}


void
s_ring_buffer_free (SRingBuffer * self) {
  s_free (self->array);
  s_free (self);
}

sboolean
s_ring_buffer_is_empty (SRingBuffer * self) {
  /* If the data data two pointers are the same and the the length is zero,
   * the array is most likely empty... */
  return ((self->start == self->end) && self->len == 0 );
}

void
s_ring_buffer_push (SRingBuffer * self,
                    sbyte data,
                    sboolean * err) {
  *err = FALSE;
  err_on_full (self, *err);
  /* The buffer should only have three different states so this should do.
   *    (exept there are five states... Idiot...)
   *
   * The first state here is the normal state where the end is after the start.
   *
   * The second state is when the end pointer is at the end of the array.
   *   This has two substates, one where the array is full (the start pointer
   *   is zero and the end pointer points to the last lement of the array), the
   *   second state is when the stat pointer does not point to zero and is thus
   *   free to use so we set the end pointer to zero.
   *
   * The third state is when the array loops back on itself (see headerfile).
   *   This has two substates, one where the next element that should be set is
   *   actially the start element, thus the array is full. The second substates
   *   is when that is not true and we can use that slot.
   */
  if (self->end <= self->size) {
    self->end = self->end + 1;
  } else if (self->end == self->size) {
    if (self->start == 0) {
      err_seems_full (*err);
    } else {
      self->end = 0;
    }
  } else if (self->end < self->start) {
    if ((self->end + 1) == self->start ) {
      err_seems_full (*err);
    } else {
      self->end = self->end + 1;
    }
  } else {
    /* This is an unknown state... some bad shit has gone down if you end up
    * here */
    s_err_print ("Reaching a place that should not be reached. Returning");
    *err = TRUE;
    return;
  }
  self->len = self->len + 1;
  self->array[self->end] = data;
}


void
s_ring_buffer_push_front (SRingBuffer * self,
                          sbyte data,
                          sboolean * err) {
  *err = FALSE;
  err_on_full (self, *err);
  
  /* This is pretty much the same as s_ring_buffer_push (), save for the states
   * beeing in a different order order is different to make it actially work as
   * inteded, I think.
   *
   * LOL.
   */
  if (self->start == 0) {
    if (self->end == self->size) {
      err_seems_full (*err);
    } else {
      self->start = self->size;
    }
  } else if (self->start <= self-end) {
    self->start = self->start - 1;
  } else if (self->start > self->end) {
    if ((self->start - 1) == self->end ) {
      err_seems_full (*err);
    } else {
      self->start = self->start - 1;
    }
  } else {
    s_err_print ("Reaching a place that should not be reached. Returning");
    *err = TRUE;
    return;
  }
  self->len = self->len + 1;
  self->array[self->start] = data;
}

/*
 * When doing poping we do not override the data in the buffer.
 * This to alleviate some processing time form usage of the data structure.
 */
sbyte
s_ring_buffer_pop (SRingBuffer * self, sboolean * err) {
  err_on_empty (self, *err);
  sbyte ret_val = self->array[self->end];
  self->len = self->len - 1;
  self->end = self->end - 1;
  return ret_val;
}


sbyte
s_ring_buffer_pop_front (SRingBuffer * self, sboolean * err) {
  err_on_empty (self, *err);
  *err = FALSE;
  sbyte ret_val = self->array[self->start];
  self->start = self->start + 1;
  self->len = self->len - 1;
  return ret_val;
}


sbyte
s_ring_buffer_peek (SRingBuffer * self, sboolean * err) {
  err_on_empty (self, *err);
  *err = FALSE;
  return self->array[self->end];
}

sbyte
s_ring_buffer_peek_front (SRingBuffer * self, sboolean * err) {
  err_on_empty (self, *err);
  *err = FALSE;
  return self->array[self->start];
}

void
s_ring_buffer_realloc (SRingBuffer * self,
                       size_t len,
                       sboolean * err);


size_t
s_ring_buffer_len (SRingBuffer * self) {
  return self->len;
}


size_t
s_ring_buffer_size (SRingBuffer * self) {
  return self->size;
}


void
s_ring_buffer_for_each (SRingBuffer * self,
                        ForEachFunc func,
                        spointer user_data,
                        sboolean * err) {
  err_on_empty (self, *err);
  
}

