/* Distributed under the Apache License, Version 2.0.
   See accompanying NOTICE file for details.*/

#ifndef __XPARRAY_H__
#define __XPARRAY_H__


template <typename TYPE>
class CXpArray
{
    protected:

    typedef void (* PFN_MoveCallback)(TYPE* pObject, const INT_PTR nCount);

    static void*        m_pfnMoveCallback;
    TYPE*        m_pData;   
    INT_PTR        m_nElementCount;
    INT_PTR        m_nAllocedCount;
    INT_PTR        m_nGrowBy; 

    public:

    inline CXpArray(const INT_PTR nGrowBy = 10);
    inline CXpArray(const CXpArray& Array);
    virtual ~CXpArray();

    // The following callback can be used to track when an object
    // moves in memory due to a reallocation.  Note that this is called
    // after the object has moved.
    static void SetMoveCallback(void (* pfnMoveCallback)(TYPE* pObject, const INT_PTR nCount));

    inline HRESULT Add(const TYPE& Element, INT_PTR* pNewIndex = NULL);
    inline HRESULT Insert(const INT_PTR nIndex, const TYPE& Element);

    inline HRESULT Remove(const INT_PTR nIndex, const INT_PTR nCount = 1);
    inline void RemoveAll();

    inline INT_PTR GetCount() const;
    inline HRESULT SetCount(const INT_PTR nNewCount);

    inline INT_PTR GetGrowBy() const;
    inline void SetGrowBy(const INT_PTR nGrowBy);

    inline HRESULT PreAlloc(const INT_PTR nCount);
    inline HRESULT FreeExtra();

    inline HRESULT Append(const CXpArray& Array);

    // Similar to basic string functions.  Out
    // of range values are fine.
    HRESULT Mid(CXpArray& Subset, const INT_PTR nFrom, const INT_PTR nCount = -1) const;
    HRESULT Left(CXpArray& Subset, const INT_PTR nCount) const;
    HRESULT Right(CXpArray& Subset, const INT_PTR nCount) const;

    INT_PTR Find(const TYPE& Element,
    const INT_PTR nStart = 0) const;

    INT_PTR Find(const CXpArray& Subset,
    const INT_PTR nStart = 0) const;

    // Use these methods with care, they can return NULL!  Also
    // this is temporary and can change during reallocation.
    TYPE* GetData();
    const TYPE* GetData() const;

    inline TYPE& operator[](const INT_PTR nIndex);
    inline const TYPE& operator[](const INT_PTR nIndex) const;

    inline bool operator==(const CXpArray& Array) const;
    inline bool operator!=(const CXpArray& Array) const
    {
        return(!operator==(Array));
    }
    
    inline HRESULT Copy(const CXpArray& Array);
    inline CXpArray& operator=(const CXpArray& Array) {Copy(Array); return(*this);}
    protected:
    HRESULT Allocate(const INT_PTR nCount, const bool bInitialize = true);

    inline void ConstructElement(const INT_PTR nIndex, const INT_PTR nCount = 1);
    inline void DestructElement(const INT_PTR nIndex, const INT_PTR nCount = 1);
};

template <typename TYPE>
void XpFreePointerArray(CXpArray<TYPE>& Array)
{
    const INT_PTR nCount = Array.GetCount();

    for(INT_PTR i = 0; i < nCount; i ++)
    {
        delete Array[i];
    }

    Array.RemoveAll();  
}
         
#include "xparray.inl"

#endif //__XP_ARRAY_H__
