//------------------------------------------------------------------------------
// File: persist.cpp
//
// Desc: DirectShow sample code
//       - State persistence helper functions used by VMR samples
//
//       This file is #included into another source file for simplicity.
//
// Copyright (c) 1994 - 2002 Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


// Constants
const int CX_DEFAULT = 400;     /* Default window width */
const int CY_DEFAULT = 400;     /* Default window height */


/******************************Public*Routine******************************\
* GetAppKey
*
\**************************************************************************/
HKEY
GetAppKey(
    BOOL fCreate
    )
{
    HKEY hKey = 0;

    if(fCreate)
    {
        if(RegCreateKey(HKEY_CURRENT_USER, cszAppKey, &hKey) == ERROR_SUCCESS)
            return hKey;
    }
    else
    {
        if(RegOpenKey(HKEY_CURRENT_USER, cszAppKey, &hKey) == ERROR_SUCCESS)
            return hKey;
    }

    return NULL;
}


/******************************Public*Routine******************************\
* ProfileStringIn
*
\**************************************************************************/
UINT
ProfileStringIn(
    LPTSTR  szKey,
    LPTSTR  szDefault,
    LPTSTR  szProfileString,
    DWORD   cb
    )
{
    CheckPointer(szKey,0);
    CheckPointer(szDefault,0);
    CheckPointer(szProfileString,0);

    HKEY  hKey;
    DWORD dwType;

    if((hKey = GetAppKey(FALSE)) == 0)
    {
        lstrcpyn(szProfileString, szDefault, cb);
        return lstrlen(szProfileString);
    }

    if((RegQueryValueEx(hKey, szKey, NULL, &dwType, 
                       (LPBYTE)szProfileString, &cb) != ERROR_SUCCESS)
        || dwType != REG_SZ)
    {
        lstrcpyn(szProfileString, szDefault, cb);
        cb = lstrlen(szProfileString);
    }

    RegCloseKey(hKey);
    return cb;
}


/******************************Public*Routine******************************\
* ProfileStringOut
*
\**************************************************************************/
void
ProfileStringOut(
    LPTSTR  szKey,
    LPTSTR  szProfileString
    )
{
    ASSERT(szKey);
    ASSERT(szProfileString);

    HKEY  hKey;

    hKey = GetAppKey(TRUE);
    if (hKey)
    {
        RegSetValueEx(hKey, szKey, 0, REG_SZ, (LPBYTE)szProfileString,
                      sizeof(TCHAR) * (lstrlen(szProfileString)+1));

        RegCloseKey(hKey);
    }
}


/******************************Public*Routine******************************\
 * LoadWindowPos
 *
 * Retrieve the window position information from the registry
 *
\**************************************************************************/

#ifndef SPI_GETWORKAREA
 #define SPI_GETWORKAREA 48  // because NT doesnt have this define yet
#endif

BOOL
LoadWindowPos(
    LPRECT lprc
    )
{
    CheckPointer(lprc,FALSE);
    
    static RECT rcDefault = {0,0,CX_DEFAULT,CY_DEFAULT};
    RECT  rcScreen, rc;
    HKEY  hKey = GetAppKey(FALSE);

    // Read window placement from the registry.
    //
    *lprc = rcDefault;

    if(hKey)
    {
        DWORD cb = sizeof(rc);
        DWORD dwType;

        if(ERROR_SUCCESS == RegQueryValueEx(hKey, cszWindow, NULL, &dwType, (LPBYTE)&rc, &cb)
            && dwType == REG_BINARY && cb == sizeof(RECT))
        {
            *lprc = rc;
        }

        RegCloseKey(hKey);
    }

    // If we fail to get the working area (screen-tray), then assume
    // the screen is 640x480
    //
    if(! SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, FALSE))
    {
        rcScreen.top    = rcScreen.left = 0;
        rcScreen.right  = 640;
        rcScreen.bottom = 480;
    }

    // If the proposed window position is outside the screen,
    // use the default placement
    //
    if(! IntersectRect(&rc, &rcScreen, lprc))
    {
        *lprc = rcDefault;
    }

    return ! IsRectEmpty(lprc);
}


/*****************************Public*Routine******************************\
 * SaveWindowPos
 *
 * Store the window position information in the registry
 *
\**************************************************************************/
BOOL
SaveWindowPos(
    HWND hwnd
    )
{
    WINDOWPLACEMENT wpl;

    HKEY hKey = GetAppKey(TRUE);
    if(!hKey)
    {
        return FALSE;
    }

    // Save the current size and position of the window to the registry
    //
    ZeroMemory(&wpl, sizeof(wpl));
    wpl.length = sizeof(wpl);
    GetWindowPlacement(hwnd, &wpl);

    RegSetValueEx(hKey, cszWindow, 0, REG_BINARY,
                 (LPBYTE)&wpl.rcNormalPosition,
                 sizeof(wpl.rcNormalPosition));

    RegCloseKey(hKey);
    return TRUE;
}


/*****************************Private*Routine******************************\
* GetRecentFiles
*
* Reads at most MAX_RECENT_FILES from the app's registry entry. 
* Returns the number of files actually read.  
* Updates the File menu to show the "recent" files.
*
\**************************************************************************/
int
GetRecentFiles(
    int iLastCount,
    int iMenuPosition   // Menu position of start of MRU list
    )
{
    int     i;
    TCHAR   FileName[MAX_PATH];
    TCHAR   szKey[32];
    HMENU   hSubMenu;

    //
    // Delete the files from the menu
    //
    hSubMenu = GetSubMenu(GetMenu(hwndApp), 0);

    // Delete the separator at the requested position and all the other 
    // recent file entries
    if(iLastCount != 0)
    {
        DeleteMenu(hSubMenu, iMenuPosition, MF_BYPOSITION);

        for(i = 1; i <= iLastCount; i++)
        {
            DeleteMenu(hSubMenu, ID_RECENT_FILE_BASE + i, MF_BYCOMMAND);
        }
    }

    for(i = 1; i <= MAX_RECENT_FILES; i++)
    {
        DWORD   len;
        TCHAR   szMenuName[MAX_PATH + 3];

        wsprintf(szKey, TEXT("File %d\0"), i);

        len = ProfileStringIn(szKey, TEXT(""), FileName, MAX_PATH * sizeof(TCHAR));
        if(len == 0)
        {
            i = i - 1;
            break;
        }

        lstrcpyn(aRecentFiles[i - 1], FileName, NUMELMS(aRecentFiles[i-1]));
        wsprintf(szMenuName, TEXT("&%d %s\0"), i, FileName);

        if(i == 1)
        {
            InsertMenu(hSubMenu, iMenuPosition, MF_SEPARATOR | MF_BYPOSITION, (UINT)-1, NULL);
        }

        InsertMenu(hSubMenu, iMenuPosition + i, MF_STRING | MF_BYPOSITION,
            ID_RECENT_FILE_BASE + i, szMenuName);
    }

    //
    // i is the number of recent files in the array.
    //
    return i;
}


/*****************************Private*Routine******************************\
* SetRecentFiles
*
* Writes the most recent files to the registry.
* Purges the oldest file if necessary.
*
\**************************************************************************/
int
SetRecentFiles(
    TCHAR *FileName,    // File name to add
    int iCount,         // Current count of files
    int iMenuPosition   // Menu position of start of MRU list
    )
{
    TCHAR   FullPathFileName[MAX_PATH];
    TCHAR   *lpFile=0;
    TCHAR   szKey[32];
    int     iCountNew, i;

    //
    // Check for duplicates - we don't allow them
    //
    for(i = 0; i < iCount; i++)
    {
        if(0 == lstrcmpi(FileName, aRecentFiles[i]))
        {
            return iCount;
        }
    }

    //
    // Throw away the oldest entry
    //
    MoveMemory(&aRecentFiles[1], &aRecentFiles[0],
               sizeof(aRecentFiles) - sizeof(aRecentFiles[1]));

    //
    // Copy in the full path of the new file.
    //
    GetFullPathName(FileName, MAX_PATH, FullPathFileName, &lpFile);
    lstrcpyn(aRecentFiles[0], FullPathFileName, NUMELMS(aRecentFiles[0]));

    //
    // Update the count of files, saturate to MAX_RECENT_FILES.
    //
    iCountNew = min(iCount + 1, MAX_RECENT_FILES);

    //
    // Clear the old stuff and the write out the recent files to disk
    //
    for(i = 1; i <= iCountNew; i++)
    {
        wsprintf(szKey, TEXT("File %d\0"), i);
        ProfileStringOut(szKey, aRecentFiles[i - 1]);
    }

    //
    // Update the file menu
    //
    GetRecentFiles(iCount, iMenuPosition);

    return iCountNew;  // the updated count of files.
}


