#include "priv.h"
#include "resource.h"

#include <mluisupp.h>

struct SUParams {
    LPSOFTDISTINFO  psdi;
    BITBOOL         bRemind : 1;
    BITBOOL         bDetails : 1;
    LONG            cyNoDetails;
    LONG            cxDlg;
    LONG            cyDlg;
};

INT_PTR CALLBACK SoftwareUpdateDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);

SHDOCAPI_(DWORD) SoftwareUpdateMessageBox( HWND hWnd,
                                     LPCWSTR szDistUnit,
                                     DWORD dwFlags,
                                     LPSOFTDISTINFO psdi )
{
    HRESULT hr;
    int iRet = IDIGNORE;
    SOFTDISTINFO    sdi;
    SUParams suparams;
    DWORD dwAdStateNew = SOFTDIST_ADSTATE_NONE;

    if ( psdi == NULL )
    {
        // use a local 
        sdi.cbSize = sizeof(SOFTDISTINFO);
        sdi.dwReserved = 0;
        psdi = &sdi;
    }

    suparams.psdi = psdi;
    suparams.bRemind = TRUE;
    suparams.bDetails = FALSE;

    hr = GetSoftwareUpdateInfo( szDistUnit, psdi );
 
    // we need an HREF to work properly. The title and abstract are negotiable.
    if ( SUCCEEDED(hr) && psdi->szHREF != NULL )
    {
        // see if this is an update the user already knows about.
        // If it is, then skip the dialog.
        if (  (psdi->dwUpdateVersionMS >= psdi->dwInstalledVersionMS ||
                (psdi->dwUpdateVersionMS == psdi->dwInstalledVersionMS &&
                 psdi->dwUpdateVersionLS >= psdi->dwInstalledVersionLS))    && 
              (psdi->dwUpdateVersionMS >= psdi->dwAdvertisedVersionMS ||
                (psdi->dwUpdateVersionMS == psdi->dwAdvertisedVersionMS &&
                 psdi->dwUpdateVersionLS >= psdi->dwAdvertisedVersionLS)) )
        { 
            DWORD idDlg;

            if ( hr == S_OK ) // new version
            {
                // we have a pending update, either on the net, or downloaded
                if ( psdi->dwFlags & SOFTDIST_FLAG_USAGE_PRECACHE )
                {
                    dwAdStateNew = SOFTDIST_ADSTATE_DOWNLOADED;
                    // Show same dialog for downloaded/available states
                    // because users get confused. See IE5 RAID entry 14488
                    idDlg = IDD_SUAVAILABLE;
                }
                else
                {
                    dwAdStateNew = SOFTDIST_ADSTATE_AVAILABLE;
                    idDlg = IDD_SUAVAILABLE;
                }
            }
            else if ( psdi->dwUpdateVersionMS == psdi->dwInstalledVersionMS &&
                      psdi->dwUpdateVersionLS == psdi->dwInstalledVersionLS )
            {
                // if installed version matches advertised, then we autoinstalled already
                dwAdStateNew = SOFTDIST_ADSTATE_INSTALLED;
                idDlg = IDD_SUINSTALLED;
            }
            else
            {
                idDlg = 0;
            }

            // only show the dialog if we've haven't been in this ad state before for
            // this update version
            if ( dwAdStateNew > psdi->dwAdState && idDlg != 0)
            {
                // Sundown: coercion is OK since SoftwareUpdateDlgProc returns true/false
                iRet = (int) DialogBoxParam(MLGetHinst(),
                                            MAKEINTRESOURCE(idDlg),
                                            hWnd,
                                            SoftwareUpdateDlgProc,
                                            (LPARAM)&suparams);
            }
        } // if update is a newer version than advertised

        // If the user doesn't want a reminder and didn't cancel, mark the DU.

        if ( !suparams.bRemind && (iRet == IDNO || iRet == IDYES) )
        {
            SetSoftwareUpdateAdvertisementState( szDistUnit,
                                                dwAdStateNew,
                                                psdi->dwUpdateVersionMS,
                                                psdi->dwUpdateVersionLS );
        } // if we're finished with this ad state for this version
    } // if we got the update info
    else 
        iRet = IDABORT;

    if ( FAILED(hr) || psdi == &sdi )
    {
        if ( psdi->szTitle != NULL )
        {
            CoTaskMemFree( psdi->szTitle );
            psdi->szTitle = NULL;
        }
        if ( psdi->szAbstract != NULL )
        {
            CoTaskMemFree( psdi->szAbstract );
            psdi->szAbstract = NULL;
        };
        if ( psdi->szHREF != NULL )
        {
            CoTaskMemFree( psdi->szHREF );
            psdi->szHREF = NULL;
        }
    }

    return iRet;
}

INT_PTR CALLBACK SoftwareUpdateDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    BOOL        fRet = 0;
    SUParams    *psuparam = (SUParams*)GetWindowLongPtr(hDlg, DWLP_USER);;
    HRESULT     hr = S_OK;
    HWND hwndDetails;

    switch (msg)
    {
    case WM_INITDIALOG:
        int         cchDetails;
        TCHAR       *pszTitle;
        TCHAR       *pszAbstract;
        TCHAR       *pszDetails;
        TCHAR       szFmt[MAX_PATH];

        SetWindowLongPtr(hDlg, DWLP_USER, lParam);
        psuparam = (SUParams*)lParam;

        if (SHRestricted( REST_NOFORGETSOFTWAREUPDATE))
            EnableWindow(GetDlgItem(hDlg, IDC_REMIND), FALSE);

        // Prepare the details from the SOFTDISTINFO
        MLLoadString(IDS_SUDETAILSFMT, szFmt, ARRAYSIZE(szFmt) );
        cchDetails = lstrlen( szFmt );
        if ( psuparam->psdi->szTitle != NULL )
        {
            pszTitle = psuparam->psdi->szTitle;
        }
        else
        {
            pszTitle = NULL;
        }
        if ( psuparam->psdi->szAbstract != NULL )
        {
            pszAbstract = psuparam->psdi->szAbstract;
        }
        else
        {
            pszAbstract = NULL;
        }
        pszDetails = new TCHAR[cchDetails];
        if ( pszDetails != NULL )
        {
            wnsprintf( pszDetails, cchDetails, szFmt, ((pszTitle!=NULL)?pszTitle:TEXT("")),
                                         ((pszAbstract!=NULL)?pszAbstract:TEXT("")) );
            // set the details text
            SetDlgItemText( hDlg, IDC_DETAILSTEXT, pszDetails );
            // initialize the reminder check box
            CheckDlgButton( hDlg, IDC_REMIND, ((psuparam->bRemind)?BST_CHECKED:BST_UNCHECKED) );
            // Hide or show the details
            RECT rectDlg;
            RECT rectDetails;

            GetWindowRect( hDlg, &rectDlg );
            psuparam->cyDlg = rectDlg.bottom - rectDlg.top;
            psuparam->cxDlg = rectDlg.right - rectDlg.left;
            hwndDetails = GetDlgItem( hDlg, IDC_DETAILSTEXT );
            GetWindowRect( hwndDetails, &rectDetails );
            psuparam->cyNoDetails = rectDetails.top - rectDlg.top;
            SetWindowPos( hwndDetails, NULL, 0,0,0,0, SWP_NOMOVE | SWP_HIDEWINDOW | SWP_NOZORDER | SWP_NOSIZE );
            SetWindowPos( hDlg, NULL,
                          0,0,psuparam->cxDlg,psuparam->cyNoDetails,
                          SWP_NOMOVE | SWP_NOZORDER );
        }
        else
            EndDialog( hDlg, IDABORT );


        if ( pszDetails != NULL )
            delete pszDetails;

        fRet = TRUE;
        break;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDYES:
            EndDialog(hDlg, IDYES );
            fRet = TRUE;
            break;
        case IDNO:
            EndDialog(hDlg, IDNO );
            fRet = TRUE;
            break;
        case IDC_REMIND:
            psuparam->bRemind = IsDlgButtonChecked( hDlg, IDC_REMIND ) == BST_CHECKED;
            fRet = TRUE;
            break;
        case IDC_DETAILS:
            {
                TCHAR   szDetails[40];

                // toggle the details
                hwndDetails = GetDlgItem( hDlg, IDC_DETAILSTEXT );
                psuparam->bDetails = !psuparam->bDetails;

                if ( psuparam->bDetails )
                {
                    // show the details
                    // switch button to close text
                    MLLoadString(IDS_SUDETAILSCLOSE, szDetails, ARRAYSIZE(szDetails) );
                    SetDlgItemText( hDlg, IDC_DETAILS, szDetails );
                    SetWindowPos( hDlg, NULL,
                                  0,0,psuparam->cxDlg, psuparam->cyDlg,
                                  SWP_NOMOVE | SWP_NOZORDER );
                    SetWindowPos( hwndDetails, NULL, 0,0,0,0, SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOSIZE );
                }
                else
                {
                    MLLoadString(IDS_SUDETAILSOPEN, szDetails, ARRAYSIZE(szDetails) );
                    SetDlgItemText( hDlg, IDC_DETAILS, szDetails );
                    SetWindowPos( hwndDetails, NULL, 0,0,0,0, SWP_NOMOVE | SWP_HIDEWINDOW | SWP_NOZORDER | SWP_NOSIZE );
                    SetWindowPos( hDlg, NULL,
                                  0,0,psuparam->cxDlg,psuparam->cyNoDetails,
                                  SWP_NOMOVE | SWP_NOZORDER );
                }
            }
            fRet = TRUE;
            break;
        }
        break;

    case WM_CLOSE:
        EndDialog(hDlg, IDNO);
        fRet = TRUE;
        break;

    case WM_DESTROY:
        fRet = TRUE;
        break;

    default:
        fRet = FALSE;
    }

    return fRet;
}
