//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1996.
//
//  File:	layoutui.cxx
//
//  Contents:	UI implementation on Docfile Layout Tool
//
//  Classes:    CLayoutApp	
//
//  Functions:	
//
//  History:	23-Mar-96	SusiA	Created
//
//----------------------------------------------------------------------------

#include "layoutui.hxx"

// Constants for File Addition dialogs
#define MAX_FILES_BUFFER        2048
#define MAX_TITLE_LEN           256
#define MAX_FILTER_LEN          256
#define MAX_PREFIX_LEN          5

#define WIDTH                   500
#define HEIGHT                  300

#define NULL_TERM               TEXT('\0')
#define BACKSLASH               TEXT("\\")

#define MALLOC(x)               LocalAlloc( LMEM_FIXED , x );
#define FREE(x)                 LocalFree( x );
#define JumpOnFail(sc)          if( FAILED(sc) ) goto Err;

#ifdef UNICODE
#define STRING_LEN(x)           Laylstrlen(x)
#define CopyString(dst, src)    Laylstrcpy(dst, src)
#define CatString(dst, src)     Laylstrcat(dst, src)
#else
#define STRING_LEN(x)           lstrlen(x)
#define CopyString(dst, src)    lstrcpy(dst, src)
#define CatString(dst, src)     lstrcat(dst, src)
#endif

// Since the LayoutDlgProc must be static for the Callback,
// we need a way to reference the member variables inside of
// LayoutDlgProc
static CLayoutApp *pStaticThis;

#ifdef STRICT
static WNDPROC lpfnwpListBoxProc = NULL;
static WNDPROC lpfnwpButtonProc  = NULL;
#define SUBCLASS_WNDPROC  WNDPROC
#else
static FARPROC lpfnwpListBoxProc = NULL;
static FARPROC lpfnwpButtonProc  = NULL;
#define SUBCLASS_WNDPROC  FARPROC
#endif

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::CLayoutApp public
//
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


CLayoutApp::CLayoutApp(HINSTANCE hInst)
{
    m_hInst        = hInst;
    m_hwndMain     = hwndNil;
    
    pStaticThis    = this;
    m_bOptimizing  = FALSE;    
    m_bCancelled   = FALSE;
    
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::InitApp public
//
//  Synopsis:	Initialize the application
//
//  Returns:	TRUE is sucessful, FALSE is FAILED
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

BOOL CLayoutApp::InitApp(void)
{
    
    if( !InitWindow() )
    {
        DisplayMessage(NULL, 
                    IDS_MAIN_WINDOW_FAIL,
                    IDS_MAIN_WINDOW_FAIL_TITLE, 
                    MB_ICONSTOP);
        return FALSE;
    }

    return TRUE;
}


//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::DoAppMessageLoop public
//
//  Synopsis:	Main window message loop
//
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


INT CLayoutApp::DoAppMessageLoop(void)
{
    MSG msg;
    HACCEL hAccel;

    hAccel = LoadAccelerators( m_hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1) );

    while (GetMessage (&msg, NULL, 0, 0))
          {
          if (m_hwndMain == 0 || !IsDialogMessage (m_hwndMain, &msg))
               {
               TranslateMessage (&msg) ;
               DispatchMessage  (&msg) ;
               }
          }
    
    return msg.wParam;
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::InitWindow public
//
//  Synopsis:	Initialize the main window
//
//  Returns:	TRUE is sucessful, FALSE is FAILED
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

BOOL CLayoutApp::InitWindow (void)
{
    m_hwndMain = CreateDialog(  m_hInst,
                 MAKEINTRESOURCE(IDD_MAIN),
                 NULL,
                 (DLGPROC)LayoutDlgProc);

    if( m_hwndMain == NULL )
        return FALSE;

    EnableButtons();
    DragAcceptFiles(m_hwndMain, TRUE);

    return TRUE;
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::InitApp public
//
//  Synopsis:	Application Callback function
//
//  Returns:	TRUE is message was handled.  FALSE otherwise
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


BOOL CALLBACK CLayoutApp::ListBoxWndProc(
    HWND hWnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
{   
    switch (uMsg)
    {
    case WM_SETCURSOR:
        if( (HWND)wParam == pStaticThis->m_hwndMain )
            SetCursor(LoadCursor(NULL, (pStaticThis->m_bCancelled ? IDC_WAIT : IDC_ARROW)));

        return bMsgHandled;
    }

    return CallWindowProc(lpfnwpListBoxProc, hWnd, uMsg, wParam, lParam);
}


BOOL CALLBACK CLayoutApp::ButtonWndProc(
    HWND hWnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
{   
    switch (uMsg)
    {
    case WM_SETCURSOR:
        if( (HWND)wParam == pStaticThis->m_hwndMain )
            SetCursor(LoadCursor(NULL, (pStaticThis->m_bCancelled ? IDC_WAIT : IDC_ARROW)));

        return bMsgHandled;
    }

    return CallWindowProc(lpfnwpButtonProc, hWnd, uMsg, wParam, lParam);
}


BOOL CALLBACK CLayoutApp::LayoutDlgProc(
    HWND hDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
{   
    SCODE sc          = S_OK;
    WORD  wId         = LOWORD((DWORD)wParam);
    WORD  wNotifyCode = HIWORD((DWORD)wParam);
    DWORD thrdid;
    static HANDLE hthread;

    switch (uMsg)
    {
    case WM_INITDIALOG:
        pStaticThis->m_hwndBtnAdd      = GetDlgItem( hDlg, IDC_BTN_ADD );
        pStaticThis->m_hwndBtnRemove   = GetDlgItem( hDlg, IDC_BTN_REMOVE );
        pStaticThis->m_hwndBtnOptimize = GetDlgItem( hDlg, IDC_BTN_OPTIMIZE );
        pStaticThis->m_hwndListFiles   = GetDlgItem( hDlg, IDC_LIST_FILES );
        pStaticThis->m_hwndStaticFiles = GetDlgItem( hDlg, IDC_STATIC_FILES );

        lpfnwpListBoxProc = (SUBCLASS_WNDPROC)SetWindowLong(
            pStaticThis->m_hwndListFiles,
            GWL_WNDPROC,
            (LONG)(WNDPROC)MakeProcInstance(
                (FARPROC)ListBoxWndProc,
                pStaticThis->m_hInst
                )
            );

        lpfnwpButtonProc = (SUBCLASS_WNDPROC)SetWindowLong(
            pStaticThis->m_hwndBtnAdd,
            GWL_WNDPROC,
            (LONG)(WNDPROC)MakeProcInstance(
                (FARPROC)ButtonWndProc,
                pStaticThis->m_hInst
                )
            );

        lpfnwpButtonProc = (SUBCLASS_WNDPROC)SetWindowLong(
            pStaticThis->m_hwndBtnRemove,
            GWL_WNDPROC,
            (LONG)(WNDPROC)MakeProcInstance(
                (FARPROC)ButtonWndProc,
                pStaticThis->m_hInst
                )
            );

        lpfnwpButtonProc = (SUBCLASS_WNDPROC)SetWindowLong(
            pStaticThis->m_hwndBtnOptimize,
            GWL_WNDPROC,
            (LONG)(WNDPROC)MakeProcInstance(
                (FARPROC)ButtonWndProc,
                pStaticThis->m_hInst
                )
            );

	// resize dialog and center it on the screen
	{
		RECT rcScreen;
		GetWindowRect(GetDesktopWindow(), &rcScreen);

		SetWindowPos(
			hDlg,
			HWND_TOP,
			(rcScreen.right - rcScreen.left - WIDTH) / 2,
			(rcScreen.bottom - rcScreen.top - HEIGHT) / 2,
			WIDTH,
			HEIGHT,
			SWP_SHOWWINDOW);
	}
        return TRUE;

    case WM_SIZE:
		pStaticThis->ReSizeWindow(lParam);
		return bMsgHandled;

    case WM_GETMINMAXINFO:
	{
	LPMINMAXINFO lpminmax = (LPMINMAXINFO) lParam;

	lpminmax->ptMinTrackSize.x = gdxWndMin;
	lpminmax->ptMinTrackSize.y = gdyWndMin;
	}
	return bMsgHandled;

    case WM_CLOSE:
        DestroyWindow(hDlg);
        PostQuitMessage(0);
        return bMsgHandled;

    case WM_DROPFILES:
        {
            TCHAR atcFileName[MAX_PATH];
            HDROP hdrop  = (HDROP)wParam;
            INT   nFiles = DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
            INT   i;

            for( i=0; i < nFiles; i++ )
            {
                if( DragQueryFile(hdrop, i, atcFileName, MAX_PATH) != 0 )
                    pStaticThis->AddFileToListBox(atcFileName);
            }
            DragFinish(hdrop);
            pStaticThis->EnableButtons();
        }
        return bMsgHandled;

    case WM_SETCURSOR:
        if( (HWND)wParam == pStaticThis->m_hwndMain )
            SetCursor(LoadCursor(NULL, (pStaticThis->m_bCancelled ? IDC_WAIT : IDC_ARROW)));

        return bMsgHandled;

    case WM_COMMAND:
        switch( wId )
	{ 
	case IDC_BTN_ADD:
            pStaticThis->AddFiles();
            return bMsgHandled;

	case IDC_BTN_REMOVE:
            pStaticThis->RemoveFiles();
            return bMsgHandled;

	case IDC_BTN_OPTIMIZE:
            
            if (pStaticThis->m_bOptimizing)  //Cancel Button click
            {   
                pStaticThis->m_bCancelled = TRUE;
                
                //SetCursor(LoadCursor(NULL, IDC_WAIT));
                
                return bMsgHandled; 
            }
            else                //Optimize Button Click
            {
                
                pStaticThis->m_bOptimizing = TRUE;
                pStaticThis->SetActionButton( IDS_CANCEL );
                hthread = CreateThread(NULL,0,
                            (LPTHREAD_START_ROUTINE) &(pStaticThis->OptimizeFiles),
			     NULL, 0, &thrdid);
                
                return bMsgHandled;

            }

        case IDC_LIST_FILES:
            switch( wNotifyCode )
            {
            case LBN_SELCHANGE:
                pStaticThis->EnableButtons();
                return bMsgHandled;
            
            default:
                break;
            }

        default:
            break;
        }

        break;

    }

    return bMsgNotHandled;
}    

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::ReSizeWindow public
//
//  Synopsis:	Handle resizing the main dialog
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


VOID CLayoutApp::ReSizeWindow (LPARAM lParam)
{
	int nW = LOWORD(lParam);
	int nH = HIWORD(lParam);

	int nBorder  = 10;
        int nButtonH = 25;
	int nButtonW = 100;
	int nStaticH = 15;

        int nListY = nBorder + nStaticH;
        int nListW = nW - 3 * nBorder - nButtonW;
        int nListH = nH - nListY - nBorder;

        int nButtonX = 2 * nBorder + nListW;

        MoveWindow(m_hwndStaticFiles, nBorder,  nBorder, nListW, nStaticH, TRUE);
        MoveWindow(m_hwndListFiles  , nBorder,  nListY,  nListW, nH - nButtonH - nBorder, TRUE);

        MoveWindow(m_hwndBtnAdd     , nButtonX, nListY, nButtonW, nButtonH, TRUE);
        MoveWindow(m_hwndBtnRemove  , nButtonX, nListY + 3 * nBorder, nButtonW, nButtonH, TRUE);
        MoveWindow(m_hwndBtnOptimize, nButtonX, nListY + nListH - nButtonH, nButtonW, nButtonH, TRUE);
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::AddFiles public
//
//  Synopsis:	Add and display selected files to the dialog window
//
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


VOID CLayoutApp::AddFiles (void)
{
    TCHAR atcFile[MAX_FILES_BUFFER];
    TCHAR atcTitle[MAX_TITLE_LEN];
    TCHAR atcFilter[MAX_FILTER_LEN];

    
    OPENFILENAME ofn;
    FillMemory( (LPVOID)&ofn, sizeof(ofn), 0 );

    ofn.lStructSize = sizeof( ofn );
    ofn.hwndOwner = m_hwndMain;
    ofn.hInstance = m_hInst;

    FormFilterString( atcFilter, MAX_FILTER_LEN );
    ofn.lpstrFilter = atcFilter;

    ofn.lpstrCustomFilter = NULL;
    ofn.nFilterIndex = 0;

    *atcFile = NULL_TERM;
    ofn.lpstrFile = atcFile;
    ofn.nMaxFile = MAX_FILES_BUFFER;

    ofn.lpstrFileTitle = NULL;
    ofn.lpstrInitialDir = NULL;

    LoadString( m_hInst, IDS_ADDFILES_TITLE, atcTitle, MAX_TITLE_LEN );
    ofn.lpstrTitle = atcTitle;

    ofn.Flags = OFN_ALLOWMULTISELECT |
                OFN_HIDEREADONLY     |
                OFN_EXPLORER         |
                OFN_FILEMUSTEXIST    |
                OFN_PATHMUSTEXIST;

    if( !GetOpenFileName( &ofn ) )
    {
        DWORD dw = CommDlgExtendedError();
        
        if( dw == FNERR_BUFFERTOOSMALL )
            DisplayMessage( m_hwndMain,
                            IDS_ADDFILES_BUFFERTOOSMALL,
                            IDS_ADDFILES_BUFFERTOOSMALL_TITLE,
                            0);
        return;
    }

    WriteFilesToList( atcFile );
    EnableButtons();
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::FormFilterString public
//
//  Synopsis:	Specifies which files (with which extension are to be displayed
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

VOID CLayoutApp::FormFilterString( TCHAR *patcFilter, INT nMaxLen )
{
    int nLen;
    UINT uStrID;

    //NOTE:  the string resources must be in sequence
    uStrID = IDS_FILTER_BEGIN+1;

    // this is an internal function and so we aren't checking for
    // enough room in the string buffer, patcFilter
    while( uStrID != IDS_FILTER_END )
    {
        LoadString( m_hInst, uStrID++, patcFilter, nMaxLen );
        nLen = STRING_LEN( patcFilter );
        nMaxLen -= nLen + 1;
        patcFilter += nLen;
        *patcFilter++ = NULL_TERM;
    }

    *patcFilter = NULL_TERM;
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::WriteFilesToList public
//
//  Synopsis:   Gets and writes the files, complete with path, to the File List
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

VOID CLayoutApp::WriteFilesToList( TCHAR *patcFilesList )
{
    TCHAR *patcDir;
    TCHAR atcFile[MAX_PATH];
    BOOL bOneFile = TRUE;

    patcDir = patcFilesList;
    while( *patcFilesList++ != NULL_TERM )
        ;

    while( *patcFilesList != NULL_TERM )
    {
        bOneFile = FALSE;
        CopyString( atcFile, patcDir );
        CatString( atcFile, BACKSLASH );
        CatString( atcFile, patcFilesList );
        AddFileToListBox( atcFile );
        while( *patcFilesList++ != NULL_TERM )
            ;
    }

    // if only one file was selected, 
    // the filename isn't separated by it's path, 
    // but is one complete filename
    if( bOneFile )
        AddFileToListBox( patcDir );
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::AddFileToListBox public
//
//  Synopsis:   displays the file to the dialog list box
//
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

VOID CLayoutApp::AddFileToListBox( TCHAR *patcFile )
{
    
    // add the file iff the file is not already displayed
    if (LB_ERR == SendMessage(m_hwndListFiles, 
                            LB_FINDSTRING, 
                            (WPARAM)0, 
                            (LPARAM)(LPCTSTR)patcFile))
    {
        SendMessage(m_hwndListFiles,
                    LB_ADDSTRING,
                    (WPARAM)0,
                    (LPARAM)(LPCTSTR)patcFile);
    }

    SetListBoxExtent();
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::RemoveFileFromListBox public
//
//  Synopsis:   remove the displayed the file from the dialog list box
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

VOID CLayoutApp::RemoveFileFromListBox( INT nIndex )
{
    SendMessage(m_hwndListFiles, 
                LB_DELETESTRING, 
                (WPARAM)nIndex, 
                (LPARAM)0);

    SetListBoxExtent();
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::SetListBoxExtent public
//
//  Synopsis:   Handles making a horizontal scroll bar if necessary
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

VOID CLayoutApp::SetListBoxExtent( void )
{
    INT i;
    INT nExtent = 0;
    INT nItems  =  SendMessage( m_hwndListFiles,
                                LB_GETCOUNT, 
                                (WPARAM)0, 
                                (LPARAM)0);
    TCHAR atcFile[MAX_PATH];
    HDC hdc = NULL;
    SIZE size;

    
    if( nItems == 0 )
        goto lSetListBoxExtent_Exit;

    if( (hdc = GetDC(m_hwndMain)) == NULL)
        goto lSetListBoxExtent_Exit;

    for( i=0; i < nItems; i++ )
    {
        SendMessage(m_hwndListFiles, 
                    LB_GETTEXT, 
                    (WPARAM)i, 
                    (LPARAM)(LPCTSTR)atcFile);
        

        GetTextExtentPoint32(
            hdc,
            atcFile,
            STRING_LEN(atcFile),
            &size);

        nExtent = max(nExtent, (INT)size.cx);
    }

lSetListBoxExtent_Exit:

    if( hdc )
        ReleaseDC( m_hwndMain, hdc );

    //BUGBUG: can scroll too far now? make it 0.8 * nExtent or so?
    SendMessage(m_hwndListFiles, 
                LB_SETHORIZONTALEXTENT, 
                (WPARAM)nExtent, 
                (LPARAM)0);
}
//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::RemoveFiles public
//
//  Synopsis:   remove one or more files from displayed list
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


VOID CLayoutApp::RemoveFiles (void)
{
    INT  i;
    INT *pnSelItems;;
    INT  nSelItems = SendMessage(  m_hwndListFiles,
                                   LB_GETSELCOUNT, 
                                   (WPARAM)0, 
                                   (LPARAM)0);

    if( nSelItems == 0 )
        return;

    pnSelItems = (LPINT) MALLOC( sizeof(INT)*nSelItems );

    if( !pnSelItems )
        return;

    SendMessage(m_hwndListFiles, 
                LB_GETSELITEMS, 
                (WPARAM)nSelItems, 
                (LPARAM)(LPINT)pnSelItems);

    // start from bottom of list to keep the indices correct
    for( i=nSelItems; --i >= 0; )
        RemoveFileFromListBox( pnSelItems[i] );

    FREE( pnSelItems );

    EnableButtons();
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::DisplayMessage public
//
//  Synopsis:   message box general routine with no file names
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

INT CLayoutApp::DisplayMessage(HWND hWnd,
                               UINT uMessageID,
                               UINT uTitleID,
                               UINT uFlags)
{
    TCHAR atcMessage[MAX_PATH];
    TCHAR atcTitle[MAX_PATH];

    LoadString(m_hInst, uMessageID, atcMessage, MAX_PATH);
    LoadString(m_hInst, uTitleID, atcTitle, MAX_PATH);

    if( hWnd )
	SetForegroundWindow(hWnd);

    return MessageBox(hWnd, atcMessage, atcTitle, uFlags);
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::DisplayMessageWithFileName public
//
//  Synopsis:   message box general routine with 1 file name
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

INT CLayoutApp::DisplayMessageWithFileName(HWND hWnd,
                               UINT uMessageIDBefore,
                               UINT uMessageIDAfter,
                               UINT uTitleID,
                               UINT uFlags,
                               TCHAR *patcFileName)
{
    TCHAR atcMessageBefore[MAX_PATH];
    TCHAR atcMessageAfter[MAX_PATH];
    TCHAR atcTitle[MAX_PATH];
    TCHAR atcFileErrorMsg[MAX_PATH*2];


    LoadString(m_hInst, uMessageIDBefore, atcMessageBefore, MAX_PATH);
    LoadString(m_hInst, uMessageIDAfter, atcMessageAfter, MAX_PATH);
    LoadString(m_hInst, uTitleID, atcTitle, MAX_PATH);

    CopyString(atcFileErrorMsg, atcMessageBefore);
    CatString(atcFileErrorMsg, patcFileName);
    CatString(atcFileErrorMsg, atcMessageAfter);

    if( hWnd )
	SetForegroundWindow(hWnd);

    return MessageBox(hWnd, atcFileErrorMsg, atcTitle, uFlags);
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::DisplayMessageWithTwoFileNames public
//
//  Synopsis:   message box general routine with 2 file names
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

INT CLayoutApp::DisplayMessageWithTwoFileNames(HWND hWnd,
                               UINT uMessageID,
                               UINT uTitleID,
                               UINT uFlags,
                               TCHAR *patcFirstFileName,
                               TCHAR *patcLastFileName)
{
    TCHAR atcMessage[MAX_PATH];
    TCHAR atcTitle[MAX_PATH];
    TCHAR atcFileErrorMsg[MAX_PATH*2];


    LoadString(m_hInst, uMessageID, atcMessage, MAX_PATH);
    LoadString(m_hInst, uTitleID, atcTitle, MAX_PATH);

    CopyString(atcFileErrorMsg, patcFirstFileName);
    CatString(atcFileErrorMsg, atcMessage);
    CatString(atcFileErrorMsg, patcLastFileName); 

    if( hWnd )
	SetForegroundWindow(hWnd);

    return MessageBox(hWnd, atcFileErrorMsg, atcTitle, uFlags);
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::EnableButtons public
//
//  Synopsis:   Updates the buttons.  Optimize turns to Cancel 
//              during optimize function.
//              Remove is greyed if no files are displayed
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

VOID CLayoutApp::EnableButtons( BOOL bShowOptimizeBtn )
{
    INT nItems    = SendMessage(  m_hwndListFiles,
                                  LB_GETCOUNT, 
                                  (WPARAM)0, 
                                  (LPARAM)0);
    INT nSelItems = SendMessage(  m_hwndListFiles,
                                  LB_GETSELCOUNT, 
                                  (WPARAM)0, 
                                  (LPARAM)0);

    EnableWindow( m_hwndBtnAdd,      TRUE          );
    EnableWindow( m_hwndBtnRemove,   nSelItems > 0 );
    EnableWindow( m_hwndBtnOptimize, nItems > 0 && bShowOptimizeBtn );
}
//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::OptimizeFiles public
//
//  Synopsis:   Static function to call the optimizeFiles worker routine
//
//  Returns:	Appropriate status code
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

DWORD CLayoutApp::OptimizeFiles (void *args)
{
    SCODE sc;

    sc = CoInitialize(NULL);
    
    sc = pStaticThis->OptimizeFilesWorker();
    
    CoUninitialize();

    pStaticThis->HandleOptimizeReturnCode(sc);

                pStaticThis->m_bCancelled = FALSE;

                pStaticThis->SetActionButton( IDS_OPTIMIZE );
                pStaticThis->m_bOptimizing = FALSE;
                
                //SetCursor(LoadCursor(NULL, IDC_ARROW));
                    
    return 0;

    
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::OptimizeFilesWorker public
//
//  Synopsis:   Optimize all the displayed files.  Make temp files,
//              optimize to temp file, then rename temp back to original file.
//
//  Returns:	Appropriate status code
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

SCODE CLayoutApp::OptimizeFilesWorker (void)
{
    INT   i, j;
    SCODE sc = S_OK;
    HRESULT  hr;
    
    TCHAR atcFileName[MAX_PATH];
    TCHAR atcTempPath[MAX_PATH];
    TCHAR atcTempFile[MAX_PATH];
    TCHAR atcPrefix[MAX_PREFIX_LEN];
    TCHAR **ppatcTempFiles = NULL;
    INT   *pintErrorFlag = NULL;
    INT   nItems = SendMessage( m_hwndListFiles,
                                LB_GETCOUNT, 
                                (WPARAM)0, 
                                (LPARAM)0 );

    if( nItems == 0 )
        return S_OK;

    ppatcTempFiles = (TCHAR **) MALLOC( sizeof(TCHAR *) * nItems );
    FillMemory( (LPVOID)ppatcTempFiles, sizeof(TCHAR *) * nItems, 0 );
    
    if( !ppatcTempFiles )
        return STG_E_INSUFFICIENTMEMORY;

    pintErrorFlag = (INT *) MALLOC( sizeof(INT) * nItems );
    FillMemory( (LPVOID)pintErrorFlag, sizeof(INT) * nItems, 0 );
    
    if( !pintErrorFlag )
    {
        sc = STG_E_INSUFFICIENTMEMORY;
        JumpOnFail(sc);
    }
    
    
    if( GetTempPath( MAX_PATH, atcTempPath ) == 0 )
    {   
         sc = GetLastError();
         JumpOnFail(sc);
    }

    LoadString( m_hInst, IDS_TEMPFILE_PREFIX, atcPrefix, MAX_PREFIX_LEN );

    for( i=0; i < nItems; i++ )
    {
        
        // handle Cancel pressed and cleanup
        if (m_bCancelled)
        {   
            m_bCancelled = FALSE;

            for( j=0; j < i ; j++ )
                DeleteFile(ppatcTempFiles[j]);
         
            sc = STG_E_NONEOPTIMIZED;
            JumpOnFail(sc);
        }

        if( GetTempFileName( atcTempPath, atcPrefix, (UINT)0, atcTempFile ) == 0 )
        {
            sc = GetLastError();
            JumpOnFail(sc);
        }

        ppatcTempFiles[i] =
            (TCHAR *) MALLOC( (STRING_LEN(atcTempFile) + 1) * sizeof(TCHAR) );

        if( !ppatcTempFiles[i] )
        {
            sc = STG_E_INSUFFICIENTMEMORY;
            JumpOnFail(sc);
        }

        CopyString( ppatcTempFiles[i], atcTempFile );
    }

     
    for( i=0; i < nItems; i++ )
    {
        // handle Cancel pressed and cleanup
        if (m_bCancelled)
        {   
            m_bCancelled = FALSE;

            for( j=i; j < nItems ; j++ )
            {
                DeleteFile(ppatcTempFiles[j]);
                pintErrorFlag[j] = 1;    
            }
            sc = STG_E_NONEOPTIMIZED;
                
            for( j=nItems; --j >= 0; )
            {
                if (pintErrorFlag[j])
                {
                    RemoveFileFromListBox(j);
                }
                else 
                {
                    sc = S_OK;
                }
        
            }
            EnableButtons();
            goto Err;
        }
        
        SendMessage( m_hwndListFiles, 
                     LB_GETTEXT, 
                     (WPARAM)i, 
                     (LPARAM)(LPINT)atcFileName );

        sc = DoOptimizeFile( atcFileName, ppatcTempFiles[i] );

#if DBG==1
        //check that files are identical here.
       if ((SUCCEEDED(sc)) && (!IdenticalFiles( atcFileName, ppatcTempFiles[i])))
       {   
           sc = STG_E_DOCFILECORRUPT;
           
       }
#endif
              
        if (!SUCCEEDED(sc))
        {    
            // This file could not be optimized.  Display Error message  
            switch( sc )
            {
            // the file is read only
            case STG_E_ACCESSDENIED:
    
                DisplayMessageWithFileName(m_hwndMain, 
                        IDS_FILE_BEFORE,
                        IDS_FILE_AFTER_READ_ONLY,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        atcFileName);
                break;

            // the file is not in a legal docfile format.
            case STG_E_FILEALREADYEXISTS:
        
                DisplayMessageWithFileName(m_hwndMain, 
                        IDS_FILE_BEFORE,
                        IDS_FILE_AFTER_NOTDOCFILE,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        atcFileName);
                break;

            default:
                DisplayMessageWithFileName(m_hwndMain, 
                        IDS_FILE_BEFORE,
                        IDS_OPTIMIZE_ERROR,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        atcFileName);       
                break;
            }
            
            pintErrorFlag[i] = 1;
            DeleteFile( ppatcTempFiles[i] );
            continue;    
        }
        
        
        //remove the (unoptimized) original file        
        hr = DeleteFile( atcFileName );
        if (!hr)
        {   
            sc = GetLastError();

            DisplayMessageWithFileName(m_hwndMain, 
                        IDS_FILE_BEFORE,
                        IDS_DELETE_ERROR,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        atcFileName);   
                
            DisplayMessageWithTwoFileNames(m_hwndMain, 
                        IDS_RENAME_MESSAGE,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        atcFileName,
                        ppatcTempFiles[i]);   

            SendMessage( m_hwndListFiles, 
                     LB_DELETESTRING, 
                     (WPARAM)i, 
                     (LPARAM)0);

            SendMessage( m_hwndListFiles, 
                     LB_INSERTSTRING, 
                     (WPARAM)i, 
                     (LPARAM)(LPINT)ppatcTempFiles[i] );
            
            continue;
        }
            
        // rename the optimized file to the original file name    
        hr = MoveFile( ppatcTempFiles[i], atcFileName );
        
        if (!hr)
        {   
            sc = GetLastError();

            DisplayMessageWithFileName(m_hwndMain, 
                        IDS_FILE_BEFORE,
                        IDS_RENAME_ERROR,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        ppatcTempFiles[i]);   
                
            DisplayMessageWithTwoFileNames(m_hwndMain, 
                        IDS_RENAME_MESSAGE,
                        IDS_OPTIMIZE_FAILED_TITLE,
                        0,
                        atcFileName,
                        ppatcTempFiles[i]);   

            SendMessage( m_hwndListFiles, 
                        LB_DELETESTRING, 
                        (WPARAM)i, 
                        (LPARAM)0);

            SendMessage( m_hwndListFiles, 
                        LB_INSERTSTRING, 
                        (WPARAM)i, 
                        (LPARAM)(LPINT)ppatcTempFiles[i] );
                
            continue;
        }
          
        DeleteFile( ppatcTempFiles[i] );
    }    

    // remove files from list box that could not be optimized
    //bSuccess is set if at least one file was sucessfully optimized.
    sc = STG_E_NONEOPTIMIZED;
    
    for( i=nItems; --i >= 0; )
    {
        if (pintErrorFlag[i])
        {
            RemoveFileFromListBox(i);
        }
        else 
        {
            sc = S_OK;
        }
        
    }
    EnableButtons();
Err:

    if ( pintErrorFlag )
        FREE( pintErrorFlag);

    if( ppatcTempFiles )
    {
        for( i=0; i < nItems; i++ )
        {
            if( ppatcTempFiles[i] )
                FREE( ppatcTempFiles[i] );
        }
    
        FREE( ppatcTempFiles );
    }
    return sc;
    
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::DoOptimizeFile public
//
//  Synopsis:   Monitor and relayout docfile to temp file.
//
//  Returns:	Appropriate status code
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------

SCODE CLayoutApp::DoOptimizeFile( TCHAR *patcFileName, TCHAR *patcTempFile )
{
    IStorage        *pStg       = NULL;
    ILayoutStorage  *pLayoutStg = NULL;
    IUnknown        *punkApp    = NULL;
    IPersistStorage *pPersist   = NULL;
    IOleObject      *pObj       = NULL;
    COleClientSite  *pSite      = NULL;
    SCODE            sc         = S_OK;
    STATSTG          stat;
    OLECHAR          awcNewFileName[MAX_PATH];


    sc = StgOpenLayoutDocfile
            (TCharToOleChar(patcFileName, awcNewFileName, MAX_PATH),
             STGM_DIRECT |
             STGM_READWRITE | 
             STGM_SHARE_EXCLUSIVE, 
             NULL,
             &pStg);

 
    JumpOnFail(sc);

    sc = pStg->QueryInterface( IID_ILayoutStorage, (void**) &pLayoutStg );
    JumpOnFail(sc);
    pStg->Release();

    // begin monitoring
    sc = pLayoutStg->BeginMonitor();
    JumpOnFail(sc);

    sc = pStg->Stat(&stat, STATFLAG_NONAME);
    JumpOnFail(sc);
   
    // open the application type of the input storage
    sc = CoCreateInstance( stat.clsid, 
                           NULL,
                           (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER),
                           IID_IUnknown,
                           (void**) &punkApp );
    JumpOnFail(sc);
  
    // load the document through the IPersistStorage Interface
    sc = punkApp->QueryInterface( IID_IPersistStorage, (void**) &pPersist );
    JumpOnFail(sc);
    punkApp->Release();


    sc = pPersist->Load( pStg );
    JumpOnFail(sc);

    sc = punkApp->QueryInterface( IID_IOleObject, (void**) &pObj );
    JumpOnFail(sc);
    punkApp->Release();

    // Open as a client
    pSite = new COleClientSite;
    pSite->m_patcFile = patcFileName;
    
    sc = pObj->DoVerb(OLEIVERB_OPEN, NULL, (IOleClientSite*) pSite, 0, NULL, NULL);
    JumpOnFail(sc);

    pObj->Close( OLECLOSE_NOSAVE );
    
    // end monitoring and relayout
    if( pLayoutStg )
    {
        sc = pLayoutStg->EndMonitor();
        JumpOnFail(sc);
    
        sc = pLayoutStg->ReLayoutDocfile(
            TCharToOleChar(patcTempFile, awcNewFileName, MAX_PATH) );
        JumpOnFail(sc);
    }

Err:

    if( pStg )
        pStg->Release();

    if( punkApp )
        punkApp->Release();

    if( pSite )
        pSite->Release();

    return sc;
  }
//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::HandleOptimizeReturnCode public
//
//  Synopsis:   message box general routine to display apprpriate message 
//              based on the Optimize returned SCODE
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


VOID CLayoutApp::HandleOptimizeReturnCode( SCODE sc )
{
    switch( sc )
    {
    case S_OK:
        DisplayMessage(m_hwndMain, IDS_OPTIMIZE_SUCCESS, IDS_OPTIMIZE_SUCCESS_TITLE, 0);
        break;

    case STG_E_FILENOTFOUND:
    case STG_E_INSUFFICIENTMEMORY:
        DisplayMessage(m_hwndMain, IDS_OPTIMIZE_OUTOFMEM, IDS_OPTIMIZE_OUTOFMEM_TITLE, 0);
        break;
    
    case STG_E_PATHNOTFOUND:
        DisplayMessage(m_hwndMain, IDS_OPTIMIZE_NOPATH, IDS_OPTIMIZE_NOPATH_TITLE, 0);
        break;
    case STG_E_NONEOPTIMIZED:
        // already displayed errors for why each file could not be optimized.
        break;

    default:
        DisplayMessage(m_hwndMain, IDS_OPTIMIZE_FAILED, IDS_OPTIMIZE_FAILED_TITLE, 0);
        break;
    }
}

//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::TCharToOleChar public
//
//  Synopsis:   helper function for UNICODE/ANSI TCHAR to OLEchar conversion
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


OLECHAR *CLayoutApp::TCharToOleChar(TCHAR *patcSrc, OLECHAR *pawcDst, INT nDstLen)
{
#ifdef UNICODE
    
    // this is already UNICODE
    return patcSrc;

#else

    UINT uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;

    *pawcDst = NULL_TERM;

    // convert to UNICODE
    MultiByteToWideChar(
        uCodePage,
        0,
        patcSrc,
        -1,
        pawcDst,
        nDstLen-1 );

    return pawcDst;

#endif
}
//+---------------------------------------------------------------------------
//
//  Member:	CLayoutApp::SetActionButton public
//
//  Synopsis:   change the text of the button
//
//  History:	03-April-96	SusiA	Created
//
//----------------------------------------------------------------------------


VOID CLayoutApp::SetActionButton( UINT uID )
{
    TCHAR atcText[MAX_PATH];

    LoadString( m_hInst, uID, atcText, MAX_PATH );

    SetWindowText( m_hwndBtnOptimize, atcText );

    UpdateWindow( m_hwndMain );
}