//
// Fifo class definition
//

#include "fifo.h"

//#include<iostream>
//using namespace std;

fifo::fifo(long length)
{
  // allocate for new vector
  capacity = length;
  data = new MY_TYPE[length];

  // set to be empty
  clear();
}

fifo::~fifo()
{
  // clean up data
  delete [] data;
}

void fifo::clear()
{
  // set to be empty
  startInd = 0;
  endInd = 0;
  isFull = 0;
}

long fifo::append(MY_TYPE *newdata, long length, int overwrite)
{
  // append data to the fifo, returning amount appended
  long toappend = length;
  long appended = 0;
  long space = 0;

  // append until done, full overwriting, until done
  while (appended < length && !(isFull && !overwrite))
  {
    // see how much space we have
    if (!overwrite && startInd > endInd)
    {
      // can only write up to startInd
      space = startInd - endInd;
    }
    else
    {
      // can write up to the end of buffer
      space = capacity - endInd;
    }

    // see if the amount to append is less than the space
    if (toappend > space)
    {
      // can only append space amount
      toappend = space;
    }

    // append that amount
    memcpy(&data[endInd],&newdata[appended],toappend*sizeof(MY_TYPE));

    // See if crossed the start
    if ((startInd > endInd) && (endInd+toappend >= startInd))
    {
      // we are full
      isFull = 1;
    }

    // update values
    appended += toappend;
    endInd += toappend;    
    toappend = length-appended;

    // See if we must wrap around
    if (endInd == capacity)
    {
      // we are at the end of the buffer, so wrap
      endInd = 0;
    }

    // see if did not cross, but are still full
    if (startInd == endInd)
    {
      // we filled the buffer
      isFull = 1;
    }

    // if we are full, then start and end must be equal
    if (isFull)
    {
      // set start to be end
      startInd = endInd;
    }    
  }

  // done, return the amount appended
  return appended;
}


long fifo::consume(MY_TYPE *newdata, long length)
{
  // fill newdata with values from the fifo
  long consumed = 0;
  long toconsume = length;
  long space = 0;

  // consume while there is data and we have not filled the newdata
  while ((consumed < length) && !(!isFull && startInd==endInd))
  {
    // see how much we can consume
    if (endInd > startInd)
    {
      // can consume up to the endInd
      space = endInd - startInd;
    }
    else
    {
      // can consume up to end of buffer
      space = capacity - startInd;
    }

    // see if have less space than needed
    if (space < toconsume)
    {
      // Only consume amount needed
      toconsume = space;
    }

    // consume it
    memcpy(&newdata[consumed],&data[startInd],toconsume*sizeof(MY_TYPE));

    // see if no longer full
    if (toconsume > 0 && isFull)
    {
      // no longer full
      isFull = 0;
    }

    // update values
    consumed += toconsume;
    startInd += toconsume;
    toconsume = length - consumed;
    
    // see if at end and must loop
    if (startInd == capacity)
    {
      // loop to beginning
      startInd = 0;
    }

  }

  // done, return the amount consumed
  return consumed;
}
