/*****************************************************************************\
    CFtpList.cpp - Internal list manager

    It is the caller's responsibility to manage any needed serialization.
\*****************************************************************************/

#include "priv.h"
#include "ftplist.h"


/*****************************************************************************\
    FUNCTION: CFtpList::DeleteItemPtr

    Remove the element "pv" from the array.
\*****************************************************************************/

void CFtpList::DeleteItemPtr(LPVOID pv)
{
    int nIndex;

    ASSERT(m_hdpa);
    nIndex = DPA_GetPtrIndex(m_hdpa, pv);
    TraceMsg(TF_FTPLIST, "CFtpList::DeleteItemPtr(pv=%#08lx) this=%#08lx, nIndex=%d", pv, this, nIndex);

    if (-1 != nIndex)
        DPA_DeletePtr(m_hdpa, nIndex);
}


/*****************************************************************************\
    FUNCTION: AppendItem

    Add a new pv to the growing array.
\*****************************************************************************/
HRESULT CFtpList::AppendItem(LPVOID pv)
{
    ASSERT(m_hdpa);
    DPA_AppendPtr(m_hdpa, pv);
    //TraceMsg(TF_FTPLIST, "CFtpList::AppendItem(pv=%#08lx) this=%#08lx", pv, this);

    return S_OK;
}


/*****************************************************************************\
    FUNCTION: InsertSorted

    Add a new pv to the growing array.
\*****************************************************************************/
HRESULT CFtpList::InsertSorted(LPVOID pv, PFNDPACOMPARE pfnCompare, LPARAM lParam)
{
    ASSERT(m_hdpa);
    DPA_SortedInsertPtr(m_hdpa, pv, 0, pfnCompare, lParam, DPAS_INSERTBEFORE, pv);

    return S_OK;
}


/*****************************************************************************\
    FUNCTION: SortedSearch

    DESCRIPTION:
        Search thru the list for the item.
\*****************************************************************************/
int CFtpList::SortedSearch(LPVOID pv, PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT options)
{
    return DPA_Search(m_hdpa, pv, 0, pfnCompare, lParam, options);
}


/*****************************************************************************\
    FUNCTION: Find

    Call back once for each item in the pv list.  Stops when the
    callback returns 0, returning the item that triggered the match.

    The callback typically returns the result of a comparison function.
\*****************************************************************************/
LPVOID CFtpList::Find(PFNDPACOMPARE pfn, LPCVOID pv)
{
    LPVOID pvoid = NULL;
    int nIndex;

    nIndex = DPA_Search(m_hdpa, (LPVOID) pv, 0, pfn, NULL, 0);

    if (-1 != nIndex)
        pvoid = DPA_GetPtr(m_hdpa, nIndex);

    //TraceMsg(TF_FTPLIST, "CFtpList::Find(pfn=%#08lx; pv=%#08lx) this=%#08lx, nIndex=%d, result=%#08lx", pfn, pv, this, nIndex, pvoid);

    return pvoid;
}

/*****************************************************************************\
    CFtpList_Create

    Start up a new pv list, with a recommended initial size and other
    callback info.
\*****************************************************************************/
HRESULT CFtpList_Create(int cpvInit, PFNDPAENUMCALLBACK pfn, UINT nGrow, CFtpList ** ppfl)
{
    HRESULT hres = E_OUTOFMEMORY;
    CFtpList * pfl = new CFtpList(pfn);
    *ppfl = pfl;

    if (pfl)
    {
        pfl->m_hdpa = DPA_Create(nGrow);
       //CFtpList_Create(pfn=%#08lx) this=%#08lx, cpvInit=%d, nGrow=%d", pfn, pfl, cpvInit, nGrow);

        if (EVAL(pfl->m_hdpa))
            hres = S_OK;
        else
        {
            pfl->Release();
            *ppfl = NULL;
        }
    }

    return hres;
}


/****************************************************\
    Constructor
\****************************************************/
CFtpList::CFtpList(PFNDPAENUMCALLBACK pfnDestroy) : m_cRef(1)
{
    DllAddRef();

    // This needs to be allocated in Zero Inited Memory.
    // Assert that all Member Variables are inited to Zero.
    ASSERT(!m_hdpa);

    m_pfnDestroy = pfnDestroy;
    LEAK_ADDREF(LEAK_CFtpList);
}


/****************************************************\
    Destructor
\****************************************************/
CFtpList::~CFtpList()
{
    //TraceMsg(TF_FTPLIST, "CFtpList::~CFtpList() this=%#08lx", this);
    if (m_pfnDestroy)
        DPA_DestroyCallback(m_hdpa, m_pfnDestroy, NULL);
    else
        DPA_Destroy(m_hdpa);

    DllRelease();
    LEAK_DELREF(LEAK_CFtpList);
}


//===========================
// *** IUnknown Interface ***
//===========================

ULONG CFtpList::AddRef()
{
    m_cRef++;
    return m_cRef;
}

ULONG CFtpList::Release()
{
    ASSERT(m_cRef > 0);
    m_cRef--;

    if (m_cRef > 0)
        return m_cRef;

    delete this;
    return 0;
}

HRESULT CFtpList::QueryInterface(REFIID riid, void **ppvObj)
{
    if (IsEqualIID(riid, IID_IUnknown))
    {
        *ppvObj = SAFECAST(this, IUnknown *);
    }
    else
    {
        TraceMsg(TF_FTPQI, "CFtpList::QueryInterface() failed.");
        *ppvObj = NULL;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}