/* 
 * File:   cKlinkEnumeratedList.h
 * Author: john
 *
 * Created on 12 April 2011, 9:11 AM
 */

#ifndef CKLINKENUMERATEDLIST_H
#define	CKLINKENUMERATEDLIST_H

#include <stddef.h>
#include <pthread.h>

template <class T>
class cKlinkListNode
{
public:
    T* mObject;
    cKlinkListNode<T> * mNext;
};

template <class T> 
class cKlinkEnumeratedList 
{
public:
    cKlinkEnumeratedList(int limit=0);
    cKlinkEnumeratedList(const cKlinkEnumeratedList& orig);
    virtual ~cKlinkEnumeratedList();
    int insert(T*);
    int insertBack(T*);
    T* first();
    T* getNext();
    void resetEnum();
    int remove(T*);
    void link(cKlinkEnumeratedList<T> *);
    void unlink();
private:
    cKlinkListNode<T> * mHead;
    cKlinkListNode<T> * mCurrEnum;
    cKlinkEnumeratedList<T> * mLinkedList;
    pthread_mutex_t mMutex;
    int mLimit;
    int mObjCount;

};


template <class T> cKlinkEnumeratedList<T>::cKlinkEnumeratedList(int limit) 
{
    mHead = NULL;
    mCurrEnum = mHead;
    mLinkedList = NULL;
    mLimit = limit;
    mObjCount = 0;
    pthread_mutex_init(&mMutex,NULL);
}

template <class T> cKlinkEnumeratedList<T>::cKlinkEnumeratedList(const cKlinkEnumeratedList<T>& orig) 
{
    
}

template <class T>cKlinkEnumeratedList<T>::~cKlinkEnumeratedList() 
{
    cKlinkListNode<T> * d;
    
    pthread_mutex_lock(&mMutex);
    while(mHead)
    {
        d = mHead;
        mHead = mHead->mNext;
        delete d;
    }
    pthread_mutex_unlock(&mMutex);
}

template <class T> int cKlinkEnumeratedList<T>::insert(T* obj)
{
    int stat = 0;
    
    pthread_mutex_lock(&mMutex);
    if(mLimit && mObjCount >= mLimit)
    {
        stat = -1;
    }
    else
    {
        cKlinkListNode<T> * n = new cKlinkListNode<T>();
        n->mObject = obj;
        n->mNext = mHead;
        mHead = n;
        mObjCount++;
    }
   
    pthread_mutex_unlock(&mMutex);
    
    if(mLinkedList)
    {
        mLinkedList->insert(obj);
    }
    
    return stat;
}

template <class T> int cKlinkEnumeratedList<T>::insertBack(T* obj)
{
     int stat = 0;

     pthread_mutex_lock(&mMutex);

     if(mLimit && mObjCount >= mLimit)
     {
         stat = -1;
     }
     else
     {
        
         cKlinkListNode<T> * n = new cKlinkListNode<T>();
         cKlinkListNode<T> * idx = mHead;
         n->mObject = obj;
         if(idx)
         {
             while(idx->mNext)
             {
                 idx = idx->mNext;
             }
             idx->mNext = n;
             n->mNext = NULL;
         }
         else
         {
             mHead = n;
             n->mNext = NULL;
         }
         mObjCount++;
     }
     pthread_mutex_unlock(&mMutex);

     if(mLinkedList)
     {
         mLinkedList->insertBack(obj);
     }
     return stat;
}

template <class T> int cKlinkEnumeratedList<T>::remove(T* obj)
{
    int stat = -1;

    pthread_mutex_lock(&mMutex);
    cKlinkListNode<T> * idx = mHead;
    cKlinkListNode<T> * rem = NULL;
    
    if(idx->mObject == obj)
    {
       mHead = idx->mNext;
       rem = idx;
    }
    else
    {
       while(idx->mNext)
       {
          rem = idx->mNext;
          if(rem->mObject == obj)
          {
             idx->mNext = rem->mNext;
             break;
          }
          idx = idx->mNext;
       }
    }
    
    if(rem)
    {
        if(rem == mCurrEnum)
        {
            mCurrEnum = rem->mNext;
        }
        delete rem;
        stat = 0;
        if(mObjCount)
        {
            mObjCount--;
        }
    }
    pthread_mutex_unlock(&mMutex);
    
    if(mLinkedList)
    {
        mLinkedList->remove(obj);
    }
    
    return stat;
}

template <class T> T* cKlinkEnumeratedList<T>::first()
{
    T* r = NULL;
    pthread_mutex_lock(&mMutex);
    if(mHead)
    {
        r = mHead->mObject; 
       mCurrEnum = mHead->mNext;
    }
    else
    {
        mCurrEnum = mHead;
    }
    pthread_mutex_unlock(&mMutex);
        
    return r;
}

template <class T> T* cKlinkEnumeratedList<T>::getNext()
{
    pthread_mutex_lock(&mMutex);
    T* r = NULL;
    if(mCurrEnum)
    {
        r = mCurrEnum->mObject;
        mCurrEnum = mCurrEnum->mNext;
    }
    else
    {
        r = NULL;
        mCurrEnum = mHead;
    }
    pthread_mutex_unlock(&mMutex);
    return r;
}

template <class T> void cKlinkEnumeratedList<T>::link(cKlinkEnumeratedList<T> *l)
{
    pthread_mutex_lock(&mMutex);
    mLinkedList = l;
    pthread_mutex_unlock(&mMutex);
}

template <class T> void cKlinkEnumeratedList<T>::unlink()
{
    pthread_mutex_lock(&mMutex);
    mLinkedList = NULL;
    pthread_mutex_unlock(&mMutex);
}
#endif	/* CKLINKENUMERATEDLIST_H */

