// small icon view (positional view, not list)

#include "ctlspriv.h"
#include "listview.h"

int ListView_SItemHitTest(LV* plv, int x, int y, UINT* pflags, int *piSubItem)
{

    int iHit;
    UINT flags;
    POINT pt;
    RECT rcState;
    RECT rcLabel;
    RECT rcIcon;

    if (piSubItem)
        *piSubItem = 0;

    // Map window-relative coordinates to view-relative coords...
    //
    pt.x = x + plv->ptOrigin.x;
    pt.y = y + plv->ptOrigin.y;

    // If we find an uncomputed item, recompute them all now...
    //
    if (plv->rcView.left == RECOMPUTE)
        ListView_Recompute(plv);

    flags = 0;

    if (ListView_IsOwnerData( plv ))
    {
        int cSlots;
        POINT ptWnd;
        LISTITEM item;
        int iWidth = 0, iHeight = 0;

        cSlots = ListView_GetSlotCount( plv, TRUE, &iWidth, &iHeight );
        iHit = ListView_CalcHitSlot( plv, pt, cSlots, iWidth, iHeight );
        ListView_SGetRectsOwnerData( plv, iHit, &rcIcon, &rcLabel, &item, FALSE );
        ptWnd.x = x;
        ptWnd.y = y;

        if (PtInRect(&rcIcon, ptWnd))
        {
            flags = LVHT_ONITEMICON;
        }
        else if (PtInRect(&rcLabel, ptWnd))
        {
            flags = LVHT_ONITEMLABEL;
        }
    }
    else
    {
        for (iHit = 0; iHit < ListView_Count(plv); iHit++)
        {
            LISTITEM* pitem = ListView_FastGetZItemPtr(plv, iHit);
            POINT ptItem;

            ptItem.x = pitem->pt.x;
            ptItem.y = pitem->pt.y;

            rcIcon.top    = ptItem.y;
            rcIcon.bottom = ptItem.y + plv->cyItem;

            rcLabel.top    = rcIcon.top;
            rcLabel.bottom = rcIcon.bottom;

            // Quick, easy rejection test...
            //
            if (pt.y < rcIcon.top || pt.y >= rcIcon.bottom)
                continue;

            rcIcon.left   = ptItem.x;
            rcIcon.right  = ptItem.x + plv->cxSmIcon;
            
            rcState.bottom = rcIcon.bottom;
            rcState.right = rcIcon.left;
            rcState.left = rcState.right - (plv->cxState + LV_ICONTOSTATEOFFSET(plv));
            rcState.top = rcState.bottom - plv->cyState;

            rcLabel.left   = rcIcon.right;
            rcLabel.right  = rcLabel.left + pitem->cxSingleLabel;

            if (PtInRect(&rcIcon, pt))
            {
                flags = LVHT_ONITEMICON;
            } else if (PtInRect(&rcLabel, pt))
            {
                flags = LVHT_ONITEMLABEL;
            } else if (PtInRect(&rcState, pt)) 
            {
                flags = LVHT_ONITEMSTATEICON;
            }
            
            if (flags)
                break;
        }
    }

    if (flags == 0)
    {
        flags = LVHT_NOWHERE;
        iHit = -1;
    }
    else
    {
      if (!ListView_IsOwnerData( plv ))
          iHit = DPA_GetPtrIndex(plv->hdpa, (void*)ListView_FastGetZItemPtr(plv, iHit));
    }

    *pflags = flags;
    return iHit;
}


void ListView_SGetRectsOwnerData( LV* plv,
        int iItem,
        RECT* prcIcon,
        RECT* prcLabel,
        LISTITEM* pitem,
        BOOL fUsepitem )
{
    RECT rcIcon;
    RECT rcLabel;
    int cSlots;

    // calculate itemx, itemy, itemsSingleLabel from iItem
    cSlots = ListView_GetSlotCount( plv, TRUE, NULL, NULL );
    pitem->iWorkArea = 0;               // OwnerData doesn't support workareas
    ListView_SetIconPos( plv, pitem, iItem, cSlots );

    // calculate lable sizes
    // Note the rect we return should be the min of the size returned and the slot size...
    ListView_IRecomputeLabelSize( plv, pitem, iItem, NULL, fUsepitem );

    rcIcon.left   = pitem->pt.x - plv->ptOrigin.x;
    rcIcon.right  = rcIcon.left + plv->cxSmIcon;
    rcIcon.top    = pitem->pt.y - plv->ptOrigin.y;
    rcIcon.bottom = rcIcon.top + plv->cyItem;
    *prcIcon = rcIcon;

    rcLabel.left   = rcIcon.right;
    if (pitem->cxSingleLabel < (plv->cxItem - plv->cxSmIcon))
        rcLabel.right  = rcLabel.left + pitem->cxSingleLabel;
    else
        rcLabel.right  = rcLabel.left + plv->cxItem - plv->cxSmIcon;
    rcLabel.top    = rcIcon.top;
    rcLabel.bottom = rcIcon.bottom;
    *prcLabel = rcLabel;
}


void ListView_SGetRects(LV* plv, LISTITEM* pitem, RECT* prcIcon, RECT* prcLabel, LPRECT prcBounds)
{

    ASSERT( !ListView_IsOwnerData( plv ));

    if (pitem->pt.x == RECOMPUTE) 
    {
        ListView_Recompute(plv);
    }

    prcIcon->left   = pitem->pt.x - plv->ptOrigin.x;
    prcIcon->right  = prcIcon->left + plv->cxSmIcon;
    prcIcon->top    = pitem->pt.y - plv->ptOrigin.y;
    prcIcon->bottom = prcIcon->top + plv->cyItem;

    prcLabel->left   = prcIcon->right;
    prcLabel->right  = prcLabel->left + pitem->cxSingleLabel;
    prcLabel->top    = prcIcon->top;
    prcLabel->bottom = prcIcon->bottom;
}

// Return the index of the first item >= *pszLookup.
//
int ListView_DoLookupString(LV* plv, LPCTSTR pszLookup, UINT flags, int iStart, int j)
{
    int i;
    BOOL fExact;
    int k;
    LISTITEM* pitem;
    LISTITEM* pitemLast = NULL;

    ASSERT( !ListView_IsOwnerData( plv ));

    fExact = FALSE;
    i = iStart;
    while ((i >= iStart) && (i < j))
    {
        int result;
        k = (i + j) / 2;
        pitem = ListView_FastGetItemPtr(plv, k);
        
        if (pitem == pitemLast)
            break;
        pitemLast = pitem;
        
        result = ListView_CompareString(plv, 
                k, pszLookup, flags, 0);

#ifdef MAINWIN
        // IEUNIX - Mainwin's lstrcmp is not compatable with WIN32.
        if(result < 0)
            result = -1;
        else if(result > 0)
            result = 1;
#endif

        if (plv->ci.style & LVS_SORTDESCENDING)
            result = -result;

        switch (result)
        {
        case 0:
            fExact = TRUE;
            // fall through
        case 1:
            j = k;
            break;
        case -1:
            i = k + 1;
            break;
        }
    }
    // For substrings, return index only if exact match was found.
    //
    if (!(flags & (LVFI_SUBSTRING | LVFI_PARTIAL)) && 
        !fExact)
        return -1;

    if (i < 0)
        i = 0;
    
    if ((!(flags & LVFI_NEARESTXY)) &&
        ListView_CompareString(plv, i, pszLookup, flags, 1)) {
        i = -1;
    }
    return i;
}

int ListView_LookupString(LV* plv, LPCTSTR pszLookup, UINT flags, int iStart)
{
    int iret;
    
    if (!pszLookup)
        return 0;
    
    iret = ListView_DoLookupString(plv, pszLookup, flags, iStart, ListView_Count(plv));
    if (iret == -1 && (flags & LVFI_WRAP)) {
        iret = ListView_DoLookupString(plv, pszLookup, flags, 0, iStart);
    }
    
    return iret;
}