//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1997.
//
//  File:       C L I S T . H 
//
//  Contents:   Very simple templatized CList. Yes, we could import and use
//              the STL stuff, but that's a real pain for this one class.
//
//  Notes:      
//
//  Author:     jeffspr   9 Dec 1999
//
//----------------------------------------------------------------------------

#ifndef _CLIST_H_
#define _CLIST_H_

#pragma once

// T is the type stored in the list
// K is a type used to search for elements of type T
template<class T, class K> class CList
{
    struct TNode
    {
        TNode * pNext;
        TNode * pPrev;
        T Data;
    };

public:
    inline CList() { m_pRootNode = NULL; m_pCurrentNode = NULL; m_pLastNode = NULL; m_iElements = 0; };
    inline ~CList();
    inline BOOL FAdd(T pNew);
    inline BOOL FDelete(K keyDelete);
    inline BOOL FFirst(T * pItem);
    inline BOOL FNext(T * pItem);
    inline VOID Flush();
    inline int GetCount() { return m_iElements; };
    inline BOOL FFind(K key, T * pItem);

protected:
    inline BOOL FInternalDelete(TNode * pItem);
    virtual BOOL FCompare(T pNode, K key) = 0;
    inline BOOL FInternalFind(K key, TNode ** ppItem);

protected:
    TNode * m_pRootNode;
    TNode * m_pCurrentNode;
    TNode * m_pLastNode;

    int     m_iElements;
};

template <class T, class K> BOOL CList< T, K >::FInternalDelete(TNode * pItem)
{
    Assert(pItem);

    if (pItem->pPrev)
    {
        pItem->pPrev->pNext = pItem->pNext;
    }

    if (pItem->pNext)
    {
        pItem->pNext->pPrev = pItem->pPrev;
    }

    if (m_pRootNode == pItem)
    {
        m_pRootNode = pItem->pNext;
    }

    if (m_pLastNode == pItem)
    {
        m_pLastNode = pItem->pPrev;
    }

    if (m_pCurrentNode == pItem)
    {
        m_pCurrentNode = pItem->pNext;
    }

    delete pItem->Data;
    delete pItem;
    m_iElements--;

    return TRUE;
}

template <class T, class K> CList< T, K >::~CList()
{
    m_pCurrentNode = m_pRootNode;

    while (m_pCurrentNode)
    {
        TNode *pNextNode = m_pCurrentNode->pNext;

        delete m_pCurrentNode;
        m_pCurrentNode = pNextNode;
        m_iElements--;
    }
}

template <class T, class K> BOOL CList< T, K >::FFirst( T * pItem )
{
    m_pCurrentNode = m_pRootNode;
    return FNext(pItem);
}

template <class T, class K> BOOL CList< T, K >::FNext( T * pItem )
{
    BOOL fReturn = FALSE;

    if (m_pCurrentNode)
    {
        *pItem = m_pCurrentNode->Data;
        m_pCurrentNode = m_pCurrentNode->pNext;
        fReturn = TRUE;
    }

    return fReturn;
}

template <class T, class K> BOOL CList< T, K >::FAdd( T ItemToAdd )
{
    TNode * pNewNode = new TNode;
    if (!pNewNode)
    {
        return FALSE;
    }
    else
    {
        pNewNode->Data = ItemToAdd;
        pNewNode->pNext = NULL;
        if (m_pLastNode)
        {
            m_pLastNode->pNext = pNewNode;
            pNewNode->pPrev = m_pLastNode;
        }
        else
        {
            pNewNode->pPrev = NULL;
        }

        m_pLastNode = pNewNode;

        if (!m_pRootNode)
            m_pRootNode = m_pLastNode;

        m_iElements++;
    }

    return TRUE;
}

template <class T, class K> VOID CList< T, K >::Flush()
{
    TNode * pLast = m_pLastNode;

    while (pLast)
    {
        FInternalDelete(pLast);
        pLast = m_pLastNode;
    }

    Assert(m_iElements == 0);
}

template <class T, class K> BOOL CList< T, K >::FDelete(K key)
{
    BOOL    fReturn = FALSE;
    BOOL    fFound  = FALSE;
    TNode * pNode   = NULL;

    fFound = FInternalFind(key, &pNode);
    if (fFound)
    {
        fReturn = FInternalDelete(pNode);
    }

    return fReturn;
}


template <class T, class K> BOOL CList< T, K >::FFind(K key, T * pItem)
{
    BOOL    fReturn     = FALSE;
    TNode * pSearch     = NULL;

    fReturn = FInternalFind(key, &pSearch);
    if (fReturn)
    {
        Assert(pSearch);

        if (pItem)
        {
            *pItem = pSearch->Data;
        }
    }

    return fReturn;
}

template <class T, class K> BOOL CList< T, K >::FInternalFind(K Key, TNode ** ppNode)
{
    BOOL    fReturn     = FALSE;
    BOOL    fFound      = FALSE;
    TNode * pSearch     = NULL;

    pSearch = m_pRootNode;
    while (!fFound && pSearch)
    {
        if (FCompare(pSearch->Data, Key))
        {
            fFound = TRUE;
        }
        else
        {
            pSearch = pSearch->pNext;
        }
    }

    if (fFound)
    {
        fReturn = TRUE;
        if (ppNode)
        {
            *ppNode = pSearch;
        }
    }

    return fReturn;
}

#endif // _CLIST_H_