/*
 * Window properties
 *
 * Copyright 1995, 1996 Alexandre Julliard
 */

#include <string.h>
#include "win.h"
#include "heap.h"
#include "stddebug.h"
#include "debug.h"


typedef struct tagPROPERTY
{
    struct tagPROPERTY *next;     /* Next property in window list */
    HANDLE32            handle;   /* User's data */
    LPSTR               string;   /* Property string (or atom) */
} PROPERTY;


/***********************************************************************
 *           PROP_FindProp
 */
static PROPERTY *PROP_FindProp( HWND32 hwnd, LPCSTR str )
{
    ATOM atom;
    PROPERTY *prop;
    WND *pWnd = WIN_FindWndPtr( hwnd );

    if (!pWnd) return NULL;
    if (HIWORD(str))
    {
        atom = GlobalFindAtom32A( str );
        for (prop = pWnd->pProp; prop; prop = prop->next)
        {
            if (HIWORD(prop->string))
            {
                if (!lstrcmpi32A( prop->string, str )) return prop;
            }
            else if (LOWORD(prop->string) == atom) return prop;
        }
    }
    else  /* atom */
    {
        atom = LOWORD(str);
        for (prop = pWnd->pProp; (prop); prop = prop->next)
        {
            if (HIWORD(prop->string))
            {
                if (GlobalFindAtom32A( prop->string ) == atom) return prop;
            }
            else if (LOWORD(prop->string) == atom) return prop;
        }
    }
    return NULL;
}


/***********************************************************************
 *           GetProp16   (USER.25)
 */
HANDLE16 WINAPI GetProp16( HWND16 hwnd, LPCSTR str )
{
    return (HANDLE16)GetProp32A( hwnd, str );
}


/***********************************************************************
 *           GetProp32A   (USER32.280)
 */
HANDLE32 WINAPI GetProp32A( HWND32 hwnd, LPCSTR str )
{
    PROPERTY *prop = PROP_FindProp( hwnd, str );

    if (HIWORD(str))
        dprintf_prop( stddeb, "GetProp(%08x,'%s'): returning %08x\n",
                      hwnd, str, prop ? prop->handle : 0 );
    else
        dprintf_prop( stddeb, "GetProp(%08x,#%04x): returning %08x\n",
                      hwnd, LOWORD(str), prop ? prop->handle : 0 );

    return prop ? prop->handle : 0;
}


/***********************************************************************
 *           GetProp32W   (USER32.281)
 */
HANDLE32 WINAPI GetProp32W( HWND32 hwnd, LPCWSTR str )
{
    LPSTR strA;
    HANDLE32 ret;

    if (!HIWORD(str)) return GetProp32A( hwnd, (LPCSTR)(UINT32)LOWORD(str) );
    strA = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
    ret = GetProp32A( hwnd, strA );
    HeapFree( GetProcessHeap(), 0, strA );
    return ret;
}


/***********************************************************************
 *           SetProp16   (USER.26)
 */
BOOL16 WINAPI SetProp16( HWND16 hwnd, LPCSTR str, HANDLE16 handle )
{
    return (BOOL16)SetProp32A( hwnd, str, handle );
}


/***********************************************************************
 *           SetProp32A   (USER32.496)
 */
BOOL32 WINAPI SetProp32A( HWND32 hwnd, LPCSTR str, HANDLE32 handle )
{
    PROPERTY *prop;

    if (HIWORD(str))
        dprintf_prop( stddeb, "SetProp: %04x '%s' %08x\n", hwnd, str, handle );
    else
        dprintf_prop( stddeb, "SetProp: %04x #%04x %08x\n",
                      hwnd, LOWORD(str), handle );

    if (!(prop = PROP_FindProp( hwnd, str )))
    {
        /* We need to create it */
        WND *pWnd = WIN_FindWndPtr( hwnd );
        if (!pWnd) return FALSE;
        if (!(prop = HeapAlloc( SystemHeap, 0, sizeof(*prop) ))) return FALSE;
        if (!(prop->string = SEGPTR_STRDUP(str)))
        {
            HeapFree( SystemHeap, 0, prop );
            return FALSE;
        }
        prop->next  = pWnd->pProp;
        pWnd->pProp = prop;
    }
    prop->handle = handle;
    return TRUE;
}


/***********************************************************************
 *           SetProp32W   (USER32.497)
 */
BOOL32 WINAPI SetProp32W( HWND32 hwnd, LPCWSTR str, HANDLE32 handle )
{
    BOOL32 ret;
    LPSTR strA;

    if (!HIWORD(str))
        return SetProp32A( hwnd, (LPCSTR)(UINT32)LOWORD(str), handle );
    strA = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
    ret = SetProp32A( hwnd, strA, handle );
    HeapFree( GetProcessHeap(), 0, strA );
    return ret;
}


/***********************************************************************
 *           RemoveProp16   (USER.24)
 */
HANDLE16 WINAPI RemoveProp16( HWND16 hwnd, LPCSTR str )
{
    return (HANDLE16)RemoveProp32A( hwnd, str );
}


/***********************************************************************
 *           RemoveProp32A   (USER32.441)
 */
HANDLE32 WINAPI RemoveProp32A( HWND32 hwnd, LPCSTR str )
{
    ATOM atom;
    HANDLE32 handle;
    PROPERTY **pprop, *prop;
    WND *pWnd = WIN_FindWndPtr( hwnd );

    if (HIWORD(str))
      dprintf_prop( stddeb, "RemoveProp: %04x '%s'\n", hwnd, str );
    else
      dprintf_prop( stddeb, "RemoveProp: %04x #%04x\n", hwnd, LOWORD(str));


    if (!pWnd) return NULL;
    if (HIWORD(str))
    {
        atom = GlobalFindAtom32A( str );
        for (pprop=(PROPERTY**)&pWnd->pProp; (*pprop); pprop = &(*pprop)->next)
        {
            if (HIWORD((*pprop)->string))
            {
                if (!lstrcmpi32A( (*pprop)->string, str )) break;
            }
            else if (LOWORD((*pprop)->string) == atom) break;
        }
    }
    else  /* atom */
    {
        atom = LOWORD(str);
        for (pprop=(PROPERTY**)&pWnd->pProp; (*pprop); pprop = &(*pprop)->next)
        {
            if (HIWORD((*pprop)->string))
            {
                if (GlobalFindAtom32A( (*pprop)->string ) == atom) break;
            }
            else if (LOWORD((*pprop)->string) == atom) break;
        }
    }
    if (!*pprop) return 0;
    prop   = *pprop;
    handle = prop->handle;
    *pprop = prop->next;
    SEGPTR_FREE(prop->string);
    HeapFree( SystemHeap, 0, prop );
    return handle;
}


/***********************************************************************
 *           RemoveProp32W   (USER32.442)
 */
HANDLE32 WINAPI RemoveProp32W( HWND32 hwnd, LPCWSTR str )
{
    LPSTR strA;
    HANDLE32 ret;

    if (!HIWORD(str))
        return RemoveProp32A( hwnd, (LPCSTR)(UINT32)LOWORD(str) );
    strA = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
    ret = RemoveProp32A( hwnd, strA );
    HeapFree( GetProcessHeap(), 0, strA );
    return ret;
}


/***********************************************************************
 *           PROPERTY_RemoveWindowProps
 *
 * Remove all properties of a window.
 */
void PROPERTY_RemoveWindowProps( WND *pWnd )
{
    PROPERTY *prop, *next;

    for (prop = pWnd->pProp; (prop); prop = next)
    {
        next = prop->next;
        SEGPTR_FREE( prop->string );
        HeapFree( SystemHeap, 0, prop );
    }
    pWnd->pProp = NULL;
}


/***********************************************************************
 *           EnumProps16   (USER.27)
 */
INT16 WINAPI EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
{
    PROPERTY *prop, *next;
    WND *pWnd;
    INT16 ret = -1;

    dprintf_prop( stddeb, "EnumProps: %04x %08x\n", hwnd, (UINT32)func );
    if (!(pWnd = WIN_FindWndPtr( hwnd ))) return -1;
    for (prop = pWnd->pProp; (prop); prop = next)
    {
        /* Already get the next in case the callback */
        /* function removes the current property.    */
        next = prop->next;

        dprintf_prop( stddeb, "  Callback: handle=%08x str='%s'\n",
                      prop->handle, prop->string );
        ret = func( hwnd, SEGPTR_GET(prop->string), prop->handle );
        if (!ret) break;
    }
    return ret;
}


/***********************************************************************
 *           EnumProps32A   (USER32.185)
 */
INT32 WINAPI EnumProps32A( HWND32 hwnd, PROPENUMPROC32A func )
{
    return EnumPropsEx32A( hwnd, (PROPENUMPROCEX32A)func, 0 );
}


/***********************************************************************
 *           EnumProps32W   (USER32.188)
 */
INT32 WINAPI EnumProps32W( HWND32 hwnd, PROPENUMPROC32W func )
{
    return EnumPropsEx32W( hwnd, (PROPENUMPROCEX32W)func, 0 );
}


/***********************************************************************
 *           EnumPropsEx32A   (USER32.186)
 */
INT32 WINAPI EnumPropsEx32A(HWND32 hwnd, PROPENUMPROCEX32A func, LPARAM lParam)
{
    PROPERTY *prop, *next;
    WND *pWnd;
    INT32 ret = -1;

    dprintf_prop( stddeb, "EnumPropsEx32A: %04x %08x %08lx\n",
                  hwnd, (UINT32)func, lParam );
    if (!(pWnd = WIN_FindWndPtr( hwnd ))) return -1;
    for (prop = pWnd->pProp; (prop); prop = next)
    {
        /* Already get the next in case the callback */
        /* function removes the current property.    */
        next = prop->next;

        dprintf_prop( stddeb, "  Callback: handle=%08x str='%s'\n",
                      prop->handle, prop->string );
        ret = func( hwnd, prop->string, prop->handle, lParam );
        if (!ret) break;
    }
    return ret;
}


/***********************************************************************
 *           EnumPropsEx32W   (USER32.187)
 */
INT32 WINAPI EnumPropsEx32W(HWND32 hwnd, PROPENUMPROCEX32W func, LPARAM lParam)
{
    PROPERTY *prop, *next;
    WND *pWnd;
    INT32 ret = -1;

    dprintf_prop( stddeb, "EnumPropsEx32W: %04x %08x %08lx\n",
                  hwnd, (UINT32)func, lParam );
    if (!(pWnd = WIN_FindWndPtr( hwnd ))) return -1;
    for (prop = pWnd->pProp; (prop); prop = next)
    {
        /* Already get the next in case the callback */
        /* function removes the current property.    */
        next = prop->next;

        dprintf_prop( stddeb, "  Callback: handle=%08x str='%s'\n",
                      prop->handle, prop->string );
        if (HIWORD(prop->string))
        {
            LPWSTR str = HEAP_strdupAtoW( GetProcessHeap(), 0, prop->string );
            ret = func( hwnd, str, prop->handle, lParam );
            HeapFree( GetProcessHeap(), 0, str );
        }
        else
            ret = func( hwnd, (LPCWSTR)(UINT32)LOWORD( prop->string ),
                        prop->handle, lParam );
        if (!ret) break;
    }
    return ret;
}
