#ifndef _LEPTO_LIST_H_
#define _LEPTO_LIST_H_
//----------------------------------------------------------------------------
///
/// \file   list.h
///
/// \brief  a list of something
///
///         See implementation files for further information
///
/// \date   20151115
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


//---Includes -----------------------------------------------------------------

//---General--------------------------

#include <stdint.h>
#include <stdlib.h>        // malloc, free
#include <string.h>        // memset


//---Defines ------------------------------------------------------------------


#define CLIST_DEFAULT_SIZE (0x0)

//---Definitions---------------------------------------------------------------


template <typename T>
class CList
{
   private:
      //volatile
      T *buffer;
      //volatile
      int startPos;
      // volatile
      int endPos;
      //volatile bool blocked;
      //volatile
      int contentCount;
      int maxCount;
      bool m_volatile;

   public:

      //constexpr
      CList( int size = CLIST_DEFAULT_SIZE );
      ~CList();

      bool isDataAvailable();
      T getValue();
      T getValue(int pos) const;
      const T& operator [] (int pos) const
      {
         return(at(pos));
      }
        T& operator [] (int pos)
        {
           return( buffer[pos] );
        }
        const T &at(int pos) const;
        //T &at(int pos) const;
        const T &front() const
        {
           return( buffer[startPos] );
        }
        T &front()
        {
           return( buffer[startPos] );
        }
        T &operator << (const T &value)
        {
           return( putValue(value) );
        };
        T &operator += (const T value)
        {
           return( putValue(value) );
        };
        T &putValue(const T &value);
        const T *putString(const T *str);
        volatile void *getPtr()
        {
           return( & buffer[startPos] );
        }
        T crossfoot() const;
        /// \brief   set volatile attribute
        ///
        ///          If ringbuffer is volatile it will forgett oldes value when
        ///          new value is added.
        void setVolatile(bool _volatile)
        {
           m_volatile=_volatile;
        }

        T *begin() const
        {
           return( &buffer[startPos] );
        }

        T *end() const
        {
           return( &buffer[endPos] );
        }

        int size() const
        {
           return(contentCount);
        }
        int maxSize() const
        {
           return( maxCount );
        }
        int count() const   //  __attribute__ ( ( obsolete ) )
        {
           return(contentCount);
        }
        void pop_front()
        {
           memcpy(&buffer[0], &buffer[1], contentCount*sizeof(T));
           contentCount--;
        }
        void expand()
        {
           startPos=0;
           endPos = maxCount - 1;
        }

};


template class CList<int>;
template class CList<char>;


template <typename T>
//constexpr
CList<T>::CList( int size /* = CLIST_DEFAULT_SIZE */ )
   :startPos(0)
   ,endPos(0)
   ,contentCount(0)
   ,maxCount( size )
   ,m_volatile(false)
{
   if( ( maxCount * sizeof(T) ) > 0 )
   {
      buffer=(T *)malloc(maxCount*sizeof(T));
      if(!buffer)
      {
         abort();
      }
      memset( (void *)buffer, 0, maxCount*sizeof(T));
   }
   else
   {
      buffer=nullptr;
   }
   //blocked=false;

   return;
}


template <typename T>
CList<T>::~CList()
{
   if(buffer)
      free((void *)buffer);

   buffer=NULL;
   contentCount=0;

   return;
}


template <typename T>
T CList<T>::getValue()
{
   T value{};

   if(contentCount)
   {
      value=buffer[startPos];
      //buffer[startPos]='^';
      startPos++;
      if(startPos>=maxCount)
         startPos=0;
      contentCount--;
   }

   return(value);
}


template <typename T>
const T &CList<T>::at(int pos) const
{
   /*
   T value=(T)0;

   if( (pos >= 0 ) && (pos < contentCount) )
      value=buffer[startPos+pos];

   return(value);
   */
   return(buffer[startPos+pos]);
}
/*
template <typename T>
T &CList<T>::at(int pos) const
{
   return(buffer[startPos+pos]);
}
*/

template <typename T>
T &CList<T>::putValue(const T &value)
{
   //blocked=true;
   /*
   while(!(contentSize<maxSize) && (counter<0x1000) )
   {
      counter++;
   };
   */
   int nowPos=-1;

   if( (contentCount>=maxCount) && m_volatile)
      getValue();

   if(contentCount<maxCount)
   {
      nowPos=endPos;
      buffer[endPos++]=value;
      if(endPos>=maxCount)
         endPos=0;
      contentCount++;
   }
   else
   {
      while(1){};
   }
   //blocked=false;

   return( buffer[nowPos] );
}


//---fin----------------------------------------------------------------------
#endif // ? ! _LEPTO_RING_H_
