/* ---------------------------------------------------------------------
   (c) ED 2003-2006
   Project      : CLIB
   Function     : Generic FIFO based on OBJ
   Module       : GFIFO
   File         : GFIFO.C
   Created      : 21-11-2003
   Modified     : 15-05-2006
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Log

   1.1 15-05-2006 sysalloc.h added
   1.0 27-11-2003 Initial version
   0.0 21-11-2003 Creation

   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This source file is not C++ but rather C. Please use a C-compiler
#endif

#include "ed/inc/gfifo.h"
#include "ed/inc/sysalloc.h"
#include "ed/inc/sys.h"
#include <stddef.h>

/* macros ============================================================== */

#define VER "1.1"
#define ID "GFIFO"
#define CPY "(c) ED 2003-2006"

#define DBG 0

/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */

struct gfifo
{
   char const *sid;
   OBJ_RO *buf;
   size_t n;
   size_t w;
   size_t r;
   unsigned e:1;
   unsigned f:1;
};

/* private data ======================================================== */
/* private functions =================================================== */
/* internal public data ================================================ */
/* internal public functions =========================================== */
/* entry points ======================================================== */
/* public data ========================================================= */

/* ---------------------------------------------------------------------
   gfifo_sver()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *gfifo_sver (void)
{
   return VER;
}

/* ---------------------------------------------------------------------
   gfifo_sid()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *gfifo_sid (void)
{
   return ID " " CPY;
}

/* ---------------------------------------------------------------------
   gfifo_create()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
gfifo_s *gfifo_create (size_t size)
{
   gfifo_s *this = malloc (sizeof *this);
   {
      CLR (this, gfifo_s);

      this->w = 0;
      this->r = 0;
      this->e = 1;
      this->f = 0;

      this->buf = malloc (sizeof *this->buf * size);

      if (this->buf)
      {
         this->n = size;
      }
      else
      {
         gfifo_delete (this);
         this = NULL;
      }
   }
   return this;
}

/* ---------------------------------------------------------------------
   gfifo_delete()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
void gfifo_delete (gfifo_s * this)
{
   if (this)
   {
      OBJ_RW p_obj;

      while (gfifo_get (this, (OBJ_RO *) & p_obj) == 0)
      {
         obj_delete (p_obj);
      }

      free (this->buf);

      free (this);
   }
}

/* ---------------------------------------------------------------------
   gfifo_init()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int gfifo_init (gfifo_s * this, char const *sid)
{
   int err = 0;

   if (this)
   {
      this->sid = sid;
      this->w = 0;
      this->r = 0;
      this->e = 1;
      this->f = 0;
   }
   else
   {
      err = 1;
   }
   return err;
}

/* ---------------------------------------------------------------------
   gfifo_put()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int gfifo_put (gfifo_s * this, OBJ_RO p_obj)
{
   int err = 0;

   if (this)
   {
#if DBG
      printf ("put %s : VP%u '%s'\n"
              ,this->sid
              ,p_obj->vp
              ,p_obj->buf);
#endif
      if (!this->f)
      {
         this->buf[this->w] = p_obj;

         /* gestion des index */
         this->w++;
         if (this->w == this->n)
         {
            this->w = 0;
         }
         this->e = 0;
         this->f = this->r == this->w;
      }
      else
      {
         err = 1;
      }
   }
   else
   {
      err = 1;
   }
   return err;
}

/* ---------------------------------------------------------------------
   gfifo_get()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int gfifo_get (gfifo_s * this, OBJ_RO * p_obj)
{
   int err = 0;

   if (this)
   {
      if (!this->e)
      {
         /* Copie */
         if (p_obj)
         {
            *p_obj = this->buf[this->r];
         }

         /* liberation */
         this->buf[this->r] = NULL;

         /* gestion des index */
         this->r++;
         if (this->r == this->n)
         {
            this->r = 0;
         }
         this->f = 0;
         this->e = this->r == this->w;
#if DBG
         printf ("get %s : VP%u '%s'\n"
                 ,this->sid
                 ,p_obj->vp
                 ,p_obj->buf);
#endif
      }
      else
      {
         err = 1;
      }
   }
   else
   {
      err = 1;
   }
   return err;
}

/* ---------------------------------------------------------------------
   gfifo_empty()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int gfifo_empty (gfifo_s * this)
{
   int e = 0;

   if (this)
   {
      e = this->e;
   }
   return e;
}
