///////////////////////////////////////////////////////////////////////////////
// Name:        wx/generic/ctrlsub.h
// Purpose:     common functionality of wxItemContainer-derived controls
// Author:      Vadim Zeitlin
// Created:     2007-07-25
// Copyright:   (c) 2007 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

#ifndef _WX_GENERIC_CTRLSUB_H_
#define _WX_GENERIC_CTRLSUB_H_

#include "wx/dynarray.h"

// ----------------------------------------------------------------------------
// wxControlWithItemsGeneric: generic implementation of item client data
// ----------------------------------------------------------------------------

class wxControlWithItemsGeneric : public wxControlWithItemsBase
{
public:
    wxControlWithItemsGeneric() = default;

    virtual void DoInitItemClientData()
    {
        m_itemsClientData.resize(GetCount(), nullptr);
    }

    virtual void DoSetItemClientData(unsigned int n, void *clientData)
    {
        m_itemsClientData[n] = clientData;
    }

    virtual void *DoGetItemClientData(unsigned int n) const
    {
        return m_itemsClientData[n];
    }

    virtual void DoClear() { m_itemsClientData.clear(); }
    virtual void DoDeleteOneItem(unsigned int pos)
    {
        if ( HasClientData() )
            m_itemsClientData.RemoveAt(pos);
    }

protected:
    // preallocate memory for numItems new items: this should be called from
    // the derived classes DoInsertItems() to speed up appending big numbers of
    // items with client data; it is safe to call even if we don't use client
    // data at all and does nothing in this case
    void AllocClientData(unsigned int numItems)
    {
        if ( HasClientData() )
            m_itemsClientData.reserve(m_itemsClientData.size() + numItems);
    }

    // this must be called by derived classes when a new item is added to the
    // control to add storage for the corresponding client data pointer (before
    // inserting many items, call AllocClientData())
    void InsertNewItemClientData(unsigned int pos,
                                 void **clientData,
                                 unsigned int n,
                                 wxClientDataType type)
    {
        if ( InitClientDataIfNeeded(type) )
            m_itemsClientData.Insert(clientData[n], pos);
    }

    // the same as InsertNewItemClientData() but for numItems consecutive items
    // (this can only be used if the control doesn't support sorting as
    // otherwise the items positions wouldn't be consecutive any more)
    void InsertNewItemsClientData(unsigned int pos,
                                  unsigned int numItems,
                                  void **clientData,
                                  wxClientDataType type)
    {
        if ( InitClientDataIfNeeded(type) )
        {
            // it's more efficient to insert everything at once and then update
            // for big number of items to avoid moving the array contents
            // around (which would result in O(N^2) algorithm)
            m_itemsClientData.Insert(nullptr, pos, numItems);

            for ( unsigned int n = 0; n < numItems; ++n, ++pos )
                m_itemsClientData[pos] = clientData[n];
        }
    }


    // vector containing the client data pointers: it is either empty (if
    // client data is not used) or has the same number of elements as the
    // control
    wxArrayPtrVoid m_itemsClientData;

private:
    // initialize client data if needed, return false if we don't have any
    // client data and true otherwise
    bool InitClientDataIfNeeded(wxClientDataType type)
    {
        if ( !HasClientData() )
        {
            if ( type == wxClientData_None )
            {
                // we didn't have the client data before and are not asked to
                // store it now either
                return false;
            }

            // this is the first time client data is used with this control
            DoInitItemClientData();
            SetClientDataType(type);
        }
        //else: we already have client data

        return true;
    }

    wxDECLARE_NO_COPY_CLASS(wxControlWithItemsGeneric);
};

#endif // _WX_GENERIC_CTRLSUB_H_

