//
// WinMain.cpp
//
// (c)Copyright 2000 The Caney Group, LLC. All Rights Reserved.
//
// Programmed by Steven J. Eschweiler
//
// Compiled with Microsoft Visual C++ 6.0 Professional
// 

#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <direct.h>
#include "shlobj.h" // Visual C++
#include <vfw.h>
#include <mciavi.h>
#include <mmsystem.h>
#include <digitalv.h>
#include "VideoPlayer.h"
#include "resource.h"
#include "comcthlp.h"
#include "IndotekBackgroundTechnology.h"
#include "Database.h"

// Used within dialog box to space things apart
#define X_SPACER 6
#define Y_SPACER 6
#define FRAMEWIDTH 2

BOOL gbFullscreen = FALSE;
// The maximum number of disks per project
#define MAX_DISKS   1000 // It's high enough...
int PlaylistDiskNumber[MAX_DISKS];
//BOOL bMovieAborted = FALSE;
BOOL bPresentingPlaylist = FALSE;
int PresentingPlaylistIndex;
BOOL bMovieIsPlaying = FALSE;

// Global info but defined here:
HINSTANCE hInst;
HWND hwndMain = NULL;
HWND hwndToolBar = NULL;
HWND hwndStatusBar = NULL;
HWND hwndDialog = NULL;
HWND hwndMovie = NULL;
BOOL bReady = FALSE;
BOOL bAppIsActive = FALSE;
HACCEL hAccel;
BOOL gbTabReady=FALSE;

char CDROM_Path[_MAX_PATH];
char CDROM_Path_Backup[_MAX_PATH];
RECT grcStep1,grcStep2,grcStep3;

// For video playback
#define MOVIE_WIDTH 320
#define MOVIE_HEIGHT 240

// Local Functions
void MenuCheckMark(HMENU hmenu, int id, BOOL bCheck);
void ViewportMenuUncheckTL(HMENU hMenu);
void ViewportMenuUncheckTR(HMENU hMenu);
void ViewportMenuUncheckBL(HMENU hMenu);
void ViewportMenuUncheckBR(HMENU hMenu);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ClientWndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam);
void DisplayErrorText(DWORD dwLastError);
BOOL RunHelp(HWND hwndMain);
HWND ToolBar_Init(HWND hwndParent);
void ToolBar_ShowPlay();
void ToolBar_ShowPause();
BOOL CALLBACK HelpAboutProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK MergeReplaceProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void PromptSave(void);
BOOL CALLBACK DialogProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK TopWndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK BottomWndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MovieWndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam);
BOOL BrowseForCDROM(HWND hwnd,char *FilledWithPath,char *lpName);
BOOL GetUserConfiguration(void);
BOOL SetUserConfiguration(void);
void ConstructTitleBar(void);
void SetPromptSave(BOOL bPromptSave);
void WordforWordFile_Close(void);
void WordforWordFile_Open(char *Pathname);
void WordforWordFile_Save(char *Pathname);
void PlayMovie(void);
BOOL ProcessOperatingSystem(void);
BOOL CALLBACK FullscreenProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK ContinuePlaylistProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

// Local application name and open filename
char szAppName[_MAX_PATH+32] = "Word for Word";

// This is the version of the file format for things we save
#define FILEVERSION 1
BOOL gbPromptSave = FALSE;
char FilenameWFW[_MAX_PATH] = "Untitled.wfw";

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpszCmdLine, int cmdShow)
{
    MSG msg;
    WNDCLASSEX wc;
    RECT rcDesktop;
    int bpp;

    // Get operating system and determine what to do
    if ( !ProcessOperatingSystem() )
        return 0;

    // Save the app instance in a global variable
    hInst = hInstance;

    // Make paths and filenames relative to executable
    char ExePath[_MAX_PATH], ExeDir[_MAX_DIR];
    GetModuleFileName(hInst, ExePath, _MAX_PATH);
    _splitpath(ExePath, NULL, ExeDir, NULL, NULL);
    _chdir(ExeDir);

    // Get the desktop size... must be >= 800x600
    GetWindowRect( GetDesktopWindow(), &rcDesktop );
    if ( (rcDesktop.right-rcDesktop.left)<800 ||
        (rcDesktop.bottom-rcDesktop.top)<600 )
    {
        MessageBox(NULL,"This application requires that your display size is set to 800 x 600 or larger. This application must now exit.",szAppName,MB_OK|MB_ICONERROR);
        return 0;
    }
    // Get Desktop color depth... must be 16,24, or 32 BPP
    bpp = GetDeviceCaps(GetDC(GetDesktopWindow()),BITSPIXEL);
    if (bpp<8)
    {
        MessageBox(NULL,"This application requires that your display color depth is set to 8, 16, 24 or 32 bit High Color or True Color. This application must now exit.",szAppName,MB_OK|MB_ICONERROR);
        return 0;
    }
    else if (bpp<16)
    {
        if (IDNO==MessageBox(NULL,"For the best video quality, your display color depth should be set to 16, 24 or 32 bit High Color or True Color. Would you like to start this application anyway?",szAppName,MB_YESNO|MB_ICONQUESTION))
            return 0;
    }

    // Register main app window class
    wc.cbSize = sizeof(wc);
    wc.lpszClassName = szAppName;
    wc.hInstance = hInstance;
    wc.lpfnWndProc = WndProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON2));
    wc.lpszMenuName = "MAIN";
    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
    wc.style = CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON2));
    RegisterClassEx(&wc);

    // Movie in child window
    wc.lpszClassName = "MovieSmall";
    wc.hInstance = hInstance;
    wc.lpfnWndProc = MovieWndProc;
    //wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hCursor = LoadCursor(NULL, IDC_WAIT);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.lpszMenuName = NULL;
    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
    wc.style = 0;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIconSm = NULL;
    RegisterClassEx(&wc);

    // Movie in mock "fullscreen" window
    wc.lpszClassName = "MovieMockFullscreen";
    wc.hInstance = hInstance;
    wc.lpfnWndProc = MovieWndProc;
    //wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hCursor = LoadCursor(NULL, IDC_WAIT);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.lpszMenuName = NULL;
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.style = 0;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIconSm = NULL;
    RegisterClassEx(&wc);

    // Initialize common controls and keyboard accelerators
    InitCommonControls();
    hAccel = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1));

    // Create Main App Window
    hwndMain = CreateWindowEx(0L,
        szAppName, szAppName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hwndMain, SW_MAXIMIZE);
    UpdateWindow(hwndMain);

    // Now we are safe to contruct the title bar
    ConstructTitleBar();

    // 1. Get user config and load database from CD-ROM drive.
    if (GetUserConfiguration()==FALSE)
    {
        MessageBox(hwndMain,"No database or video files were found in the CD-ROM Drive or the Word for Word software needs to be reconfigured. This program must exit.",szAppName,MB_OK|MB_ICONERROR);
        return 0;
    }

    // 2. Setup interface for database...
    db_SetupInterface();

    // 3. Now set focus on this control
    SetFocus(GetDlgItem(hwndDialog, IDC_TREERESULTLIST));

    // 5. Now specify that the controls are ready for processing.
    gbTabReady=TRUE;

    // Enter the main message loop
    bReady = TRUE;
    while (GetMessage(&msg, NULL, 0U, 0U))
    {
        if (!TranslateAccelerator(hwndMain,hAccel,&msg))
        {
            if (hwndDialog)
            {
                if (!IsDialogMessage(hwndDialog,&msg))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }

            if (bPresentingPlaylist)
            {
                db_SaveCurrentNotes();
                SetFocus(GetDlgItem(hwndDialog, IDC_TREEPLAYLIST));
                for (PresentingPlaylistIndex=0; PresentingPlaylistIndex<db_PlaylistCount(); PresentingPlaylistIndex++)
                {
                    TreeView_SelectItem( GetDlgItem(hwndDialog,IDC_TREEPLAYLIST), TreeView_SetSelectionIndex(GetDlgItem(hwndDialog,IDC_TREEPLAYLIST),PresentingPlaylistIndex) );
                    SetFocus(GetDlgItem(hwndDialog, IDC_TREEPLAYLIST));
                    // Is it really safe to invalidate 
                    // and update control in a dialog box?
                    //InvalidateRect(GetDlgItem(hwndDialog, IDC_EDIT),NULL,TRUE);
                    //UpdateWindow(GetDlgItem(hwndDialog, IDC_EDIT));
                    InvalidateRect(hwndDialog,NULL,TRUE);
                    UpdateWindow(hwndDialog);
                    PlayMovie();
                    if (PresentingPlaylistIndex<db_PlaylistCount()-1)
                    {
                        //if (IDNO==MessageBox(hwndMain,"Would you like to continue with the next clip in the Playlist?",szAppName,MB_YESNO|MB_ICONQUESTION))
                        if (IDNO==DialogBox(hInst,MAKEINTRESOURCE(IDD_MESSAGEBOX_CONTINUEPLAYLIST),hwndDialog,ContinuePlaylistProc))
                            //if (IDNO==MessageBox(hwndMain,"Would you like to continue with the next clip in the Playlist?",szAppName,MB_YESNO|MB_ICONQUESTION))                            
                            break;
                        //Waitfor(
                    }
                }
                bPresentingPlaylist = FALSE;
            }

        }
    }

    return msg.wParam;
}

void
MenuCheckMark(HMENU hmenu, int id, BOOL bCheck)
{
    int iState;
    iState = (bCheck) ? MF_CHECKED : MF_UNCHECKED;
    CheckMenuItem(hmenu, id, iState);
}

LRESULT CALLBACK
WndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam)
{
    char buffer[_MAX_PATH+512];
    static BOOL bExitingApp = FALSE;
    OPENFILENAME ofn;	
    char NewFilenameWFW[_MAX_PATH];
    RECT rcControl,rcControl2, rcDialog,rcLeft,rcMiddle, 
        rcFrame1,rcFrame2,rcScreen;
    int VideoListBoxHeight,GreatestKeyHeight,GreatestKeyWidth,KeyLeft;
    HWND hwndControl,hwndControl2;
    int Width;
    int Height;
    int HeightStatus;
    int HeightTB;
    DWORD dwStyle;
    RECT rWindow,rcStatus;
    int MessageBoxResult;
    BOOL bOpenCancelled,bExitCancelled;
    char drive[_MAX_DRIVE];
    char dir[_MAX_DIR];
    char fname[_MAX_FNAME];
    char ext[_MAX_EXT];

    switch (mMsg)
    {
    case WM_GETMINMAXINFO:
        ((MINMAXINFO *)lParam)->ptMinTrackSize.x = 780;
        ((MINMAXINFO *)lParam)->ptMinTrackSize.y = 500;
        return 0;

    case WM_CREATE:
        {
            // Create toolbar (source resides in toolbar.c).
            hwndToolBar = ToolBar_Init(hwnd);

            // Create status bar (source resides in statbar.c).
            hwndStatusBar = CreateStatusWindow( WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|CCS_BOTTOM|SBARS_SIZEGRIP, "Ready", hwnd, 2);
            // Update status bar to not use borders for the first part...
            Status_SetText(hwndStatusBar, 0, SBT_NOBORDERS, "Ready");

            // Create Dialog
            hwndDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_FILTER), hwnd, (DLGPROC)DialogProc);
            if (hwndDialog==NULL)
            {
                DisplayErrorText(GetLastError());
            }

            // Create Movie Window
            hwndMovie = CreateWindowEx(0,
                "MovieSmall", NULL,
                WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE,
                0, 0, MOVIE_WIDTH, MOVIE_HEIGHT,
                GetDlgItem(hwndDialog, IDC_TVSCREEN), NULL, hInst, NULL);

            return 0;
        }

    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDM_FILE_CLOSE:
                {
                    if (gbPromptSave)
                    {
                        wsprintf(buffer,"%s has changed. Would you like to save it?",FilenameWFW);
                        MessageBoxResult = MessageBox(hwndMain,buffer,"Save changes ?",MB_YESNOCANCEL|MB_ICONQUESTION);
                        if (MessageBoxResult==IDCANCEL)
                        {
                            // Do nothing and do not
                            // close the current file...
                        }
                        else if (MessageBoxResult==IDNO)
                        {
                            WordforWordFile_Close();
                            strcpy(FilenameWFW,"Untitled.wfw");
                            SetPromptSave(FALSE);
                        }
                        else if (MessageBoxResult==IDYES)
                        {
                            // SEND a save message and let it
                            // handle it...
                            SendMessage(hwndMain,WM_COMMAND,MAKEWPARAM(IDM_FILE_SAVEAS,2),0);
                            WordforWordFile_Close();
                            strcpy(FilenameWFW,"Untitled.wfw");
                            SetPromptSave(FALSE);
                        }
                    }
                    else
                    {
                        WordforWordFile_Close();
                        strcpy(FilenameWFW,"Untitled.wfw");
                        SetPromptSave(FALSE);
                    }
                    break;
                }

            case IDM_FILE_OPEN:
                {
                    // First we determine if a save prompt
                    // needs to be displayed
                    //
                    // Then we close the current file
                    //
                    bOpenCancelled = FALSE;
                    if (gbPromptSave)
                    {
                        wsprintf(buffer,"%s has changed. Would you like to save it?",FilenameWFW);
                        MessageBoxResult = MessageBox(hwndMain,buffer,"Save changes ?",MB_YESNOCANCEL|MB_ICONQUESTION);
                        if (MessageBoxResult==IDCANCEL)
                        {
                            // Do nothing and do not
                            // close the current file...
                            bOpenCancelled = TRUE;
                        }
                        else if (MessageBoxResult==IDNO)
                        {
                            WordforWordFile_Close();
                            strcpy(FilenameWFW,"Untitled.wfw");
                            SetPromptSave(FALSE);
                        }
                        else if (MessageBoxResult==IDYES)
                        {
                            // SEND a save message and let it
                            // handle it...
                            SendMessage(hwndMain,WM_COMMAND,MAKEWPARAM(IDM_FILE_SAVEAS,2),0);
                            WordforWordFile_Close();
                            strcpy(FilenameWFW,"Untitled.wfw");
                            SetPromptSave(FALSE);
                        }
                    }
                    else
                    {
                        WordforWordFile_Close();
                        strcpy(FilenameWFW,"Untitled.wfw");
                        SetPromptSave(FALSE);
                    }

                    // Now we open a new file...
                    if (bOpenCancelled==FALSE)
                    {
                        strcpy(NewFilenameWFW,"");
                        ZeroMemory((LPVOID)&ofn,sizeof(ofn));
                        ofn.lStructSize=sizeof(ofn);
                        ofn.hwndOwner=hwnd;
                        ofn.hInstance=hInst;
                        ofn.lpstrFilter=" Word for Word Files (*.wfw; *.pz)\0*.wfw;*.pz\0\0";
                        ofn.lpstrFile=NewFilenameWFW;
                        ofn.nMaxFile=_MAX_PATH;
                        ofn.Flags=OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
                        if (GetOpenFileName(&ofn)!=0)
                        {
                            // Success

                            // We ensure that the file extension is wfw
                            _splitpath(NewFilenameWFW,drive,dir,fname,ext);
                            strcpy(FilenameWFW,drive);
                            strcat(FilenameWFW,dir);
                            strcat(FilenameWFW,fname);
                            strcat(FilenameWFW,".wfw");
                            // OBSOLETE: strcpy(FilenameWFW,NewFilenameWFW);
                            WordforWordFile_Open(FilenameWFW);
                            SetPromptSave(FALSE);
                        }
                    }
                    break;
                }

            case IDM_FILE_SAVEAS:
                {
                    //strcpy(FilenameWFW,"");
                    ZeroMemory((LPVOID)&ofn,sizeof(ofn));
                    ofn.lStructSize=sizeof(ofn);
                    ofn.hwndOwner=hwnd;
                    ofn.hInstance=hInst;
                    ofn.lpstrFilter=" Word for Word Files (*.wfw)\0*.wfw\0\0";
                    ofn.lpstrFile=FilenameWFW;
                    ofn.nMaxFile=_MAX_PATH;
                    ofn.Flags=OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
                    if (GetSaveFileName(&ofn)!=0)
                    {
                        // Add .wfw if it does not already exist.
                        _splitpath(FilenameWFW,drive,dir,fname,ext);
                        strlwr(ext);
                        if (strcmp(ext,".wfw")!=0)
                        {
                            strcpy(FilenameWFW,drive);
                            strcat(FilenameWFW,dir);
                            strcat(FilenameWFW,fname);
                            strcat(FilenameWFW,".wfw");
                        }
                        SetPromptSave(FALSE);
                        // WE FALL THROUGH TO THE SAVE!
                    }
                    else
                        break;
                }
            case IDM_FILE_SAVE:
                {
                    // The above IDM_FILE_SAVEAS could
                    // have fallen through to this
                    // IDM_FILE_SAVE
                    //

                    // When we save we reset gbPromptSave
                    // to FALSE to indicate that this file
                    // has been saved.
                    WordforWordFile_Save(FilenameWFW);
                    SetPromptSave(FALSE);
                    break;
                }

            case IDM_HELP_HELPFILE:
                {
                    if (RunHelp(hwnd)==FALSE)
                    {
                        MessageBox(hwnd,"Can not locate the Word for Word - User's Guide",szAppName,MB_OK|MB_ICONERROR);
                    }
                    break;
                }

            case IDM_HELP_ABOUT:
                {
                    DialogBox(hInst,MAKEINTRESOURCE(IDD_HELPABOUT),hwnd,HelpAboutProc);
                    break;
                }

            case IDM_FILE_EXIT:
                {
                    SendMessage(hwnd, WM_CLOSE, 0, 0) ;
                    break;
                }

            case IDB_PLAY_PLAY:
                {
                    Movie_Stop();
                    ToolBar_ShowPlay();
                    bMovieIsPlaying = FALSE;
                    if (bPresentingPlaylist)
                    {
                        MessageBox(hwndMain,"Playlist playback has terminated.",szAppName,MB_OK|MB_ICONINFORMATION);
                        bPresentingPlaylist = FALSE;
                    }
                    PlayMovie();
                    break;
                }

            case IDB_PLAY_PAUSE:
                {
                    if (ToolBar_IsButtonChecked(hwndToolBar,IDB_PLAY_PAUSE))
                        Movie_Pause();
                    else
                        Movie_Resume();
                    break;
                }

            case IDB_PLAY_STOP:
                {
                    Movie_Stop();
                    ToolBar_ShowPlay();
                    bMovieIsPlaying = FALSE;
                    if (bPresentingPlaylist)
                    {
                        MessageBox(hwndMain,"Playlist playback has terminated.",szAppName,MB_OK|MB_ICONINFORMATION);
                        bPresentingPlaylist = FALSE;
                    }
                    break;
                }

            case IDM_OPTIONS_FULLSCREEN:
                {
                    gbFullscreen = !gbFullscreen;
                    MenuCheckMark(GetMenu(hwndMain),IDM_OPTIONS_FULLSCREEN,gbFullscreen);
                    ToolBar_CheckButton(hwndToolBar,IDM_OPTIONS_FULLSCREEN,gbFullscreen);
                    break;
                }

            default:
                {
                    // A little debug text for now...
                    char NotifyCodeText[256];
                    char WindowHandleText[256];
                    if (HIWORD(wParam)==0)
                        wsprintf(NotifyCodeText,"Menu");
                    else if (HIWORD(wParam)==1)
                        wsprintf(NotifyCodeText,"Accelerator");
                    else
                        wsprintf(NotifyCodeText,"%d",HIWORD(wParam));
                    if ((HWND)lParam==hwndMain)
                        wsprintf(WindowHandleText,"Main App");
                    else if ((HWND)lParam==hwndToolBar)
                        wsprintf(WindowHandleText,"Tool Bar");
                    else
                        wsprintf(WindowHandleText,"App Child");
                    wsprintf(buffer,"wNotifyCode = %s\nwID = %d\nhwndCtl = %s", NotifyCodeText,LOWORD(wParam),WindowHandleText );
                    MessageBox(hwnd,buffer,"Unsupported Command",MB_OK);
                    break;
                }
            }

            return 0;
        }

    case WM_INITMENU:
        {
            MenuCheckMark((HMENU)wParam,IDM_OPTIONS_FULLSCREEN,gbFullscreen);
            return 0;
        }

    case WM_MENUSELECT:
        {
            // Display helpful text in status bar
            typedef struct tagPOPUPSTRING
            {
                HMENU hMenu;
                UINT uiString;
            } POPUPSTRING;
            POPUPSTRING popstr;
            popstr.hMenu = 0;
            popstr.uiString = 0;
            MenuHelp(WM_MENUSELECT, wParam, lParam, GetMenu(hwnd), hInst, hwndStatusBar, (UINT *)&popstr);			
            return 0;
        }

        // We need to trap WM_CLOSE because it will send a WM_SIZE
        // and we need to be prepared for that. So, when you want
        // your app to exit, use SendMessage(hwndMain,WM_CLOSE,0,0);
    case WM_CLOSE:
        {
            Movie_Close();
            bExitCancelled = FALSE;
            if (gbPromptSave)
            {
                wsprintf(buffer,"%s has changed. Would you like to save it?",FilenameWFW);
                MessageBoxResult = MessageBox(hwndMain,buffer,"Save changes ?",MB_YESNOCANCEL|MB_ICONQUESTION);
                if (MessageBoxResult==IDCANCEL)
                {
                    // Do nothing and do not
                    // close the current file...
                    bExitCancelled = TRUE;
                }
                else if (MessageBoxResult==IDYES)
                {
                    // SEND a save message and let it
                    // handle it...
                    SendMessage(hwndMain,WM_COMMAND,MAKEWPARAM(IDM_FILE_SAVEAS,2),0);
                }
            }

            // You could throw up a confirmation screen here
            // to let the user decide whether or not to exit
            // the app. If the user does not want to exit the
            // app, simply return 0.
            if (bExitCancelled == FALSE) // Assume user wants to quit the app
            {
                // Problem occurs here...
                bExitingApp=TRUE;

                // WE MUST REMOVE ALLOCATED ITEMS FROM DATABASE:
                Movie_Stop();
                Movie_Close();
                WordforWordFile_Close();
                gbTabReady=FALSE;
                db_DeleteAllAllocated();
                DestroyWindow(hwnd);
            }
            return 0;
        }

    case WM_DESTROY:
        {
            if (bExitingApp)
            {
                bAppIsActive = FALSE;
                bReady = FALSE;
                PostQuitMessage(0);
            }
            return 0;
        }

    case WM_NOTIFY: 
        {
            switch (((LPNMHDR) lParam)->code)
            { 
            case TTN_NEEDTEXT: 
                { 
                    LPTOOLTIPTEXT lpttt; 
                    lpttt = (LPTOOLTIPTEXT) lParam; 
                    lpttt->hinst = hInst; 
                    lpttt->lpszText = MAKEINTRESOURCE(lpttt->hdr.idFrom);
                    break; 
                } 
                // ... Process other notifications here. 
            default: 
                break; 
            } 
            return 0;
        }

    case WM_SIZE:
        {
            if (wParam==SIZE_MAXHIDE || wParam==SIZE_MINIMIZED)
                bAppIsActive = FALSE;
            else
                bAppIsActive = TRUE;

            Width = LOWORD(lParam);
            Height = HIWORD(lParam);

            // Adjust toolbar size.
            if (IsWindowVisible(hwndToolBar))
            {
                dwStyle = GetWindowLong(hwndToolBar, GWL_STYLE);
                ToolBar_AutoSize(hwndToolBar);
                InvalidateRect(hwndToolBar, NULL, TRUE);
                GetWindowRect(hwndToolBar, &rWindow);
                ScreenToClient(hwnd, (LPPOINT)&rWindow.left);
                ScreenToClient(hwnd, (LPPOINT)&rWindow.right);
                HeightTB = rWindow.bottom - rWindow.top;
            }
            else
            {

                HeightTB = 0;
            }

            // Adjust status bar size.
            if (IsWindowVisible(hwndStatusBar))
            {
                GetWindowRect(hwndStatusBar, &rcStatus);
                HeightStatus = rcStatus.bottom - rcStatus.top;
                MoveWindow(hwndStatusBar, 0, Height - HeightStatus,
                    Width, HeightStatus, TRUE);

                // Example of setting up the status bar:
                //
                //  int aWidths[4];
                //  aWidths[3] = Width-2;
                //  if (wParam!=SIZE_MAXIMIZED)
                //  	aWidths[3] -= 16;
                //  aWidths[2] = aWidths[3] - 100;
                //  aWidths[1] = aWidths[2] - 100;
                //  aWidths[0] = aWidths[1] - 100;
                //  // SB_SETPARTS
                //  Status_SetParts(hwndStatusBar, 4, aWidths);
                int aWidths[3];
                aWidths[2] = Width-2;
                if (wParam!=SIZE_MAXIMIZED)
                    aWidths[2] -= 16;
                aWidths[1] = aWidths[2] - 100;
                aWidths[0] = aWidths[1] - 250;
                // SB_SETPARTS
                Status_SetParts(hwndStatusBar, 3, aWidths);
                Status_SetText(hwndStatusBar, 1, 0, db_GetProjectName());
            }
            else
            {
                HeightStatus = 0;
            }

            if (IsWindowVisible(hwndDialog))
            {
                // Fit the dialog box into the App Client Area
                Height = Height - (HeightStatus + HeightTB);
                MoveWindow(hwndDialog, 0, HeightTB, Width, Height, TRUE);
                GetClientRect(hwndDialog, &rcDialog);

                // Now move TV preview bitmap to upper right corner
                hwndControl = GetDlgItem(hwndDialog, IDC_TVTOP);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, (rcDialog.right-rcControl.right)-(X_SPACER), Y_SPACER, rcControl.right, rcControl.bottom, TRUE);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TVLEFT);
                GetClientRect(hwndControl2, &rcControl2);
                MoveWindow(hwndControl2, (rcDialog.right-rcControl.right)-(X_SPACER), Y_SPACER+rcControl.bottom, rcControl2.right, rcControl2.bottom, TRUE);
                rcScreen.left = ((rcDialog.right-rcControl.right)-(X_SPACER)) + rcControl2.right;
                rcScreen.top = Y_SPACER+rcControl.bottom;
                hwndControl = GetDlgItem(hwndDialog, IDC_TVSCREEN);
                GetClientRect(hwndControl, &rcControl);
                rcScreen.right = rcScreen.left + rcControl.right;
                rcScreen.bottom = rcScreen.top + rcControl.bottom;
                MoveWindow(hwndControl, rcScreen.left, rcScreen.top, rcScreen.right-rcScreen.left, rcScreen.bottom-rcScreen.top, TRUE);
                hwndControl = GetDlgItem(hwndDialog, IDC_TVRIGHT);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcScreen.right, rcScreen.top, rcControl.right, rcControl.bottom, TRUE);
                hwndControl = GetDlgItem(hwndDialog, IDC_TVBOTTOM);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, (rcDialog.right-rcControl.right)-X_SPACER, rcScreen.bottom, rcControl.right, rcControl.bottom, TRUE);

                // Now move TAB control for the text box below 
                // the TV bitmap
                hwndControl = GetDlgItem(hwndDialog, IDC_TVTOP);
                GetClientRect(hwndControl, &rcControl);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TVSCREEN);
                GetClientRect(hwndControl2, &rcControl2);
                rcControl.bottom += rcControl2.bottom;
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TVBOTTOM);
                GetClientRect(hwndControl2, &rcControl2);
                rcControl.bottom += rcControl2.bottom;
                rcControl.bottom += (Y_SPACER*2);
                hwndControl = GetDlgItem(hwndDialog, IDC_TABTEXT);
                MoveWindow(hwndControl, (rcDialog.right-rcControl2.right)-(X_SPACER), rcControl.bottom, rcControl2.right-rcControl2.left, (rcDialog.bottom-rcControl.bottom)-(Y_SPACER), TRUE);

                // Now move edit box into control into client 
                // area of IDC_TABTEXT
                hwndControl2 = GetDlgItem(hwndDialog, IDC_EDIT);
                GetClientRect(hwndControl, &rcControl2);
                TabCtrl_AdjustRect(hwndControl, FALSE, &rcControl2);
                MapWindowPoints(hwndControl,hwndDialog,(LPPOINT)&rcControl2,2);
                //MoveWindow(hwndControl2, rcControl2.left, rcControl2.top, (rcControl2.right-rcControl2.left), (rcControl2.bottom-rcControl2.top), TRUE);
                MoveWindow(hwndControl2, rcControl2.left, rcControl2.top+1, (rcControl2.right-rcControl2.left), (rcControl2.bottom-rcControl2.top)-1, TRUE);

                // Now move IDC_FRAME2 to proper location
                hwndControl = GetDlgItem(hwndDialog, IDC_TVTOP);
                GetClientRect(hwndControl, &rcControl);
                hwndControl = GetDlgItem(hwndDialog, IDC_FRAME2);
                rcFrame2.left = ((rcDialog.right-rcControl.right)-(X_SPACER))-FRAMEWIDTH-X_SPACER;
                rcFrame2.top = -2;
                rcFrame2.right = rcFrame2.left+FRAMEWIDTH;
                rcFrame2.bottom = rcDialog.bottom+4;
                MoveWindow(hwndControl, rcFrame2.left, rcFrame2.top, rcFrame2.right-rcFrame2.left, rcFrame2.bottom-rcFrame2.top, TRUE);

                // Now move IDC_FRAME1 to proper location
                hwndControl = GetDlgItem(hwndDialog, IDC_FRAME1);
                rcFrame1.left = (rcFrame2.left/2)-(FRAMEWIDTH/2);
                rcFrame1.top = -2;
                rcFrame1.right = rcFrame1.left+FRAMEWIDTH;
                rcFrame1.bottom = rcDialog.bottom+4;
                MoveWindow(hwndControl, rcFrame1.left, rcFrame1.top, rcFrame1.right-rcFrame1.left, rcFrame1.bottom-rcFrame1.top, TRUE);

                // Now calculate and save the left and middle panel 
                // rectangles for easier manipulation of the objects
                // that are going to be within them.
                rcLeft.left = X_SPACER;
                rcLeft.right = rcFrame1.left - X_SPACER;
                rcLeft.top = Y_SPACER;
                rcLeft.bottom = rcDialog.bottom - Y_SPACER;
                rcMiddle.left = rcFrame1.right + X_SPACER;
                rcMiddle.right = rcFrame2.left - X_SPACER;
                rcMiddle.top = Y_SPACER;
                rcMiddle.bottom = rcDialog.bottom - Y_SPACER;

                // Starting at the bottom of the middle section,
                // we place the controls from the bottom up (Step 3)
                //
                hwndControl = GetDlgItem(hwndDialog, IDC_PRESENT);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow( hwndControl, rcLeft.left + (((rcLeft.right-rcLeft.left)/2)-((rcControl.right-rcControl.left)/2)), rcLeft.bottom-(rcControl.bottom-rcControl.top), rcControl.right-rcControl.left, rcControl.bottom-rcControl.top, TRUE);
                rcLeft.bottom = rcLeft.bottom-(rcControl.bottom-rcControl.top)-Y_SPACER;
                //hwndControl = GetDlgItem(hwndDialog, IDC_CHECK_FULLSCREEN);
                //GetClientRect(hwndControl, &rcControl);
                //MoveWindow( hwndControl, rcLeft.left, rcLeft.bottom-(rcControl.bottom-rcControl.top), rcControl.right-rcControl.left, rcControl.bottom-rcControl.top, TRUE);
                //rcLeft.bottom = rcLeft.bottom-(rcControl.bottom-rcControl.top)-Y_SPACER;
                // Step 3 TEXT
                hwndControl = GetDlgItem(hwndDialog, IDC_STEP3);
                //GetClientRect(hwndControl, &rcControl);
                if ( (grcStep3.right-grcStep3.left) > (rcLeft.right-rcLeft.left) )
                    MoveWindow( hwndControl, rcLeft.left, rcLeft.bottom-(grcStep3.bottom-grcStep3.top), rcLeft.right-rcLeft.left, grcStep3.bottom-grcStep3.top, TRUE);
                else
                    MoveWindow( hwndControl, rcLeft.left, rcLeft.bottom-(grcStep3.bottom-grcStep3.top), grcStep3.right-grcStep3.left, grcStep3.bottom-grcStep3.top, TRUE);
                rcLeft.bottom = rcLeft.bottom-(grcStep3.bottom-grcStep3.top)-Y_SPACER;

                // Frame 3
                hwndControl = GetDlgItem(hwndDialog, IDC_FRAME3);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow( hwndControl, 0, rcLeft.bottom-FRAMEWIDTH, rcFrame1.right, FRAMEWIDTH, TRUE);
                rcLeft.bottom = rcLeft.bottom-FRAMEWIDTH-Y_SPACER;

                // Now line up STEP-1 and STEP-2 Text boxes
                hwndControl = GetDlgItem(hwndDialog, IDC_STEP1);
                if ( (grcStep1.right-grcStep1.left) > (rcLeft.right-rcLeft.left) )
                    MoveWindow(hwndControl, rcLeft.left, rcLeft.top, (rcLeft.right-rcLeft.left), (grcStep1.bottom-grcStep1.top), TRUE);
                else
                    MoveWindow(hwndControl, rcLeft.left, rcLeft.top, (grcStep1.right-grcStep1.left), (grcStep1.bottom-grcStep1.top), TRUE);                
                hwndControl2 = GetDlgItem(hwndDialog, IDC_STEP2);
                if ( (grcStep2.right-grcStep2.left) > (rcMiddle.right-rcMiddle.left) )
                    MoveWindow(hwndControl2, rcMiddle.left, rcMiddle.top, (rcMiddle.right-rcMiddle.left), (grcStep2.bottom-grcStep2.top), TRUE);
                else
                    MoveWindow(hwndControl2, rcMiddle.left, rcMiddle.top, (grcStep2.right-grcStep2.left), (grcStep2.bottom-grcStep2.top), TRUE);
                rcMiddle.top = rcMiddle.top + (grcStep2.bottom-grcStep2.top)+Y_SPACER;

                // Determine Middle Size for Step 2
                // 
                // MiddleHeight = (rcMiddle.bottom - rcMiddle.top)
                // 
                // ( static text height *2 ) + (y_spacer *7) + (button height *3) + (GreatestKeyHeight *4)
                //
                // This assume that the static text and the buttons
                // are the same height. We also expect the groups
                // of buttons to be the same width.
                //
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_GREEN1);
                GetClientRect(hwndControl, &rcControl);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_GREEN1);
                GetClientRect(hwndControl2, &rcControl2);
                if ( (rcControl.bottom-rcControl.top) > (rcControl2.bottom-rcControl2.top) )
                    GreatestKeyHeight = (rcControl.bottom-rcControl.top);
                else
                    GreatestKeyHeight = (rcControl2.bottom-rcControl2.top);

                hwndControl = GetDlgItem(hwndDialog, IDC_TEXT_SELECTIONS);
                GetClientRect(hwndControl, &rcControl);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_ADD);
                GetClientRect(hwndControl2, &rcControl2);
                VideoListBoxHeight = (int)(rcMiddle.bottom - rcMiddle.top);
                VideoListBoxHeight -= (int)( ((rcControl.bottom-rcControl.top)*2) + (Y_SPACER*7) + ((rcControl2.bottom-rcControl2.top)*3) + (GreatestKeyHeight*4) );
                VideoListBoxHeight /= 2;

                // We have everything we need, size the controls.
                hwndControl = GetDlgItem(hwndDialog, IDC_TEXT_SELECTIONS);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcMiddle.left, rcMiddle.top, rcMiddle.right-rcMiddle.left, rcControl.bottom-rcControl.top, TRUE);
                rcMiddle.top = rcMiddle.top + (rcControl.bottom-rcControl.top) + Y_SPACER;

                // Selections Box
                hwndControl = GetDlgItem(hwndDialog, IDC_TREERESULTLIST);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcMiddle.left, rcMiddle.top, rcMiddle.right-rcMiddle.left, VideoListBoxHeight, TRUE);
                rcMiddle.top = rcMiddle.top + (VideoListBoxHeight) + Y_SPACER;

                // Determine MAX Key Width so we can center the Key
                hwndControl = GetDlgItem(hwndDialog, IDC_TEXT_GREEN1);
                GetClientRect(hwndControl, &rcControl);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_YELLOW1);
                GetClientRect(hwndControl2, &rcControl2);
                if ( (rcControl.right-rcControl.left) > (rcControl2.right-rcControl2.left) )
                    GreatestKeyWidth = (rcControl.right-rcControl.left);
                else
                    GreatestKeyWidth = (rcControl2.right-rcControl2.left);
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_GREEN1);
                GetClientRect(hwndControl, &rcControl);
                GreatestKeyWidth += ((rcControl.right-rcControl.left)+X_SPACER);

                // Now determine the left side of the Key
                KeyLeft = rcMiddle.left + (((rcMiddle.right-rcMiddle.left)/2)-(GreatestKeyWidth/2));

                // Key Green 1
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_GREEN1);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, KeyLeft, rcMiddle.top, rcControl.right-rcControl.left, rcControl.bottom-rcControl.top, TRUE);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_GREEN1);
                GetClientRect(hwndControl2, &rcControl2);
                MoveWindow(hwndControl2, KeyLeft+(rcControl.right-rcControl.left)+X_SPACER, rcMiddle.top, rcControl2.right-rcControl2.left, rcControl2.bottom-rcControl2.top, TRUE);
                rcMiddle.top = rcMiddle.top + (GreatestKeyHeight);

                // Key Yellow 1
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_YELLOW1);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, KeyLeft, rcMiddle.top, rcControl.right-rcControl.left, rcControl.bottom-rcControl.top, TRUE);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_YELLOW1);
                GetClientRect(hwndControl2, &rcControl2);
                MoveWindow(hwndControl2, KeyLeft+(rcControl.right-rcControl.left)+X_SPACER, rcMiddle.top, rcControl2.right-rcControl2.left, rcControl2.bottom-rcControl2.top, TRUE);
                rcMiddle.top = rcMiddle.top + (GreatestKeyHeight) + Y_SPACER;

                // Add
                hwndControl = GetDlgItem(hwndDialog, IDC_ADD);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcMiddle.left+(((rcMiddle.right-rcMiddle.left)/2)-((rcControl.right-rcControl.left)/2)), rcMiddle.top, (rcControl.right-rcControl.left), (rcControl.bottom-rcControl.top), TRUE);
                rcMiddle.top = rcMiddle.top + (rcControl.bottom-rcControl.top) + Y_SPACER;

                // Playlist Static Text
                hwndControl = GetDlgItem(hwndDialog, IDC_TEXT_PLAYLIST);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcMiddle.left, rcMiddle.top, rcMiddle.right-rcMiddle.left, (rcControl.bottom-rcControl.top), TRUE);
                rcMiddle.top = rcMiddle.top + (rcControl.bottom-rcControl.top) + Y_SPACER;

                // Playlist Box
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEPLAYLIST);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcMiddle.left, rcMiddle.top, rcMiddle.right-rcMiddle.left, VideoListBoxHeight, TRUE);
                rcMiddle.top = rcMiddle.top + (VideoListBoxHeight) + Y_SPACER;

                // Determine MAX Key Width so we can center the Key
                hwndControl = GetDlgItem(hwndDialog, IDC_TEXT_GREEN2);
                GetClientRect(hwndControl, &rcControl);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_YELLOW2);
                GetClientRect(hwndControl2, &rcControl2);
                if ( (rcControl.right-rcControl.left) > (rcControl2.right-rcControl2.left) )
                    GreatestKeyWidth = (rcControl.right-rcControl.left);
                else
                    GreatestKeyWidth = (rcControl2.right-rcControl2.left);
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_GREEN2);
                GetClientRect(hwndControl, &rcControl);
                GreatestKeyWidth += ((rcControl.right-rcControl.left)+X_SPACER);

                // Now determine the left side of the Key
                KeyLeft = rcMiddle.left + (((rcMiddle.right-rcMiddle.left)/2)-(GreatestKeyWidth/2));

                // Key Green 2
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_GREEN2);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, KeyLeft, rcMiddle.top, rcControl.right-rcControl.left, rcControl.bottom-rcControl.top, TRUE);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_GREEN2);
                GetClientRect(hwndControl2, &rcControl2);
                MoveWindow(hwndControl2, KeyLeft+(rcControl.right-rcControl.left)+X_SPACER, rcMiddle.top, rcControl2.right-rcControl2.left, rcControl2.bottom-rcControl2.top, TRUE);
                rcMiddle.top = rcMiddle.top + (GreatestKeyHeight);

                // Key Yellow 2
                hwndControl = GetDlgItem(hwndDialog, IDC_TREEVIEW_YELLOW2);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, KeyLeft, rcMiddle.top, rcControl.right-rcControl.left, rcControl.bottom-rcControl.top, TRUE);
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TEXT_YELLOW2);
                GetClientRect(hwndControl2, &rcControl2);
                MoveWindow(hwndControl2, KeyLeft+(rcControl.right-rcControl.left)+X_SPACER, rcMiddle.top, rcControl2.right-rcControl2.left, rcControl2.bottom-rcControl2.top, TRUE);
                rcMiddle.top = rcMiddle.top + (GreatestKeyHeight) + Y_SPACER;

                // MOVE UP, MOVE DOWN
                hwndControl = GetDlgItem(hwndDialog, IDC_MOVEUP);
                GetClientRect(hwndControl, &rcControl);
                rcControl2.left = rcMiddle.left + (((rcMiddle.right-rcMiddle.left)/2) - (((rcControl.right-rcControl.left)*2)/2));
                MoveWindow(hwndControl, rcControl2.left, rcMiddle.top, (rcControl.right-rcControl.left), (rcControl.bottom-rcControl.top), TRUE);
                rcControl2.left += (rcControl.right-rcControl.left);
                hwndControl = GetDlgItem(hwndDialog, IDC_MOVEDOWN);
                MoveWindow(hwndControl, rcControl2.left, rcMiddle.top, (rcControl.right-rcControl.left), (rcControl.bottom-rcControl.top), TRUE);
                rcMiddle.top = rcMiddle.top + (rcControl.bottom-rcControl.top);

                // Delete
                hwndControl = GetDlgItem(hwndDialog, IDC_DELETE);
                GetClientRect(hwndControl, &rcControl);
                MoveWindow(hwndControl, rcMiddle.left+(((rcMiddle.right-rcMiddle.left)/2)-((rcControl.right-rcControl.left)/2)), rcMiddle.top, (rcControl.right-rcControl.left), (rcControl.bottom-rcControl.top), TRUE);
                rcMiddle.top = rcMiddle.top + (rcControl.bottom-rcControl.top) + Y_SPACER;

                // OK, now let's size the left TAB control.
                hwndControl = GetDlgItem(hwndDialog, IDC_TABFILTER);
                MoveWindow(hwndControl, rcLeft.left, rcLeft.top+((grcStep1.bottom-grcStep1.top)+Y_SPACER), rcLeft.right-rcLeft.left, (rcLeft.bottom-rcLeft.top)-((grcStep1.bottom-grcStep1.top)+Y_SPACER), TRUE);

                // Now move TREEVIEW into client area of IDC_TABFILTER
                hwndControl2 = GetDlgItem(hwndDialog, IDC_TREEVIEW);
                GetClientRect(hwndControl, &rcControl2);
                TabCtrl_AdjustRect(hwndControl, FALSE, &rcControl2);
                MapWindowPoints(hwndControl,hwndDialog,(LPPOINT)&rcControl2,2);
                MoveWindow(hwndControl2, rcControl2.left, rcControl2.top+1, (rcControl2.right-rcControl2.left), (rcControl2.bottom-rcControl2.top)-1, TRUE);
            }
            return 0;
        }

    default:
        return (DefWindowProc(hwnd, mMsg, wParam, lParam));
    }

    return 0;
}

LRESULT CALLBACK
ClientWndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam)
{
    return (DefWindowProc(hwnd, mMsg, wParam, lParam));
}

// Returns the handle of the toolbar if successful or NULL otherwise. 
// hwndParent - handle of the parent window 
HWND
ToolBar_Init(HWND hwndParent)
{
    HWND hwndTB;
    TBADDBITMAP tbab;
    int NumButtons = 0;
    int NumBitmaps = 0;
#define MAX_BUTTONS 50
    TBBUTTON tbb[MAX_BUTTONS];

    // Add first 5 buttons to get things started - Sep,New,Open,Save,Save As
    tbb[NumButtons].iBitmap = NumBitmaps;
    tbb[NumButtons].idCommand = 0;
    tbb[NumButtons].fsState = TBSTATE_ENABLED;
    tbb[NumButtons].fsStyle = TBSTYLE_SEP;
    tbb[NumButtons].dwData = 0;
    tbb[NumButtons].iString = tbb[NumButtons].idCommand;
    NumButtons++;
    tbb[NumButtons].iBitmap = NumBitmaps;
    tbb[NumButtons].idCommand = IDM_FILE_OPEN;
    tbb[NumButtons].fsState = TBSTATE_ENABLED;
    tbb[NumButtons].fsStyle = TBSTYLE_BUTTON;
    tbb[NumButtons].dwData = 0;
    tbb[NumButtons].iString = tbb[NumButtons].idCommand;
    NumButtons++;
    NumBitmaps++;
    tbb[NumButtons].iBitmap = NumBitmaps;
    tbb[NumButtons].idCommand = IDM_FILE_SAVE;
    tbb[NumButtons].fsState = TBSTATE_ENABLED;
    tbb[NumButtons].fsStyle = TBSTYLE_BUTTON;
    tbb[NumButtons].dwData = 0;
    tbb[NumButtons].iString = tbb[NumButtons].idCommand;
    NumButtons++;
    NumBitmaps++;
    tbb[NumButtons].iBitmap = NumBitmaps;
    tbb[NumButtons].idCommand = IDM_FILE_SAVEAS;
    tbb[NumButtons].fsState = TBSTATE_ENABLED;
    tbb[NumButtons].fsStyle = TBSTYLE_BUTTON;
    tbb[NumButtons].dwData = 0;
    tbb[NumButtons].iString = tbb[NumButtons].idCommand;
    NumButtons++;
    NumBitmaps++;

    // Create the toolbar with the first button
    hwndTB = CreateToolbarEx(hwndParent,
        WS_CHILD|TBSTYLE_TOOLTIPS,
        1,
        NumBitmaps,
        hInst,
        IDB_STDTOOLBAR,
        tbb,
        NumButtons,
        0, 0, 0, 0,
        sizeof(TBBUTTON));

    // Seperator
    tbb[0].iBitmap = 0;
    tbb[0].idCommand = 0;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_SEP;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;	
    ToolBar_AddButtons(hwndTB, 1, tbb);

    // Fullscreen / Window toggle
    tbb[0].iBitmap = NumBitmaps;
    tbb[0].idCommand = IDM_OPTIONS_FULLSCREEN;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_CHECK;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;
    tbab.hInst = hInst;
    tbab.nID = IDB_FULLSCREEN;
    ToolBar_AddBitmap(hwndTB, 1, &tbab);
    ToolBar_AddButtons(hwndTB, 1, tbb);
    NumBitmaps++;

    // Seperator
    tbb[0].iBitmap = 0;
    tbb[0].idCommand = 0;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_SEP;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;	
    ToolBar_AddButtons(hwndTB, 1, tbb);

    // Play_Play
    tbb[0].iBitmap = NumBitmaps;
    tbb[0].idCommand = IDB_PLAY_PLAY;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_BUTTON;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;
    tbab.hInst = hInst;
    tbab.nID = tbb[0].idCommand;
    ToolBar_AddBitmap(hwndTB, 1, &tbab);
    ToolBar_AddButtons(hwndTB, 1, tbb);
    NumBitmaps++;

    // Play_Pause
    tbb[0].iBitmap = NumBitmaps;
    tbb[0].idCommand = IDB_PLAY_PAUSE;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_CHECK;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;
    tbab.hInst = hInst;
    tbab.nID = tbb[0].idCommand;
    ToolBar_AddBitmap(hwndTB, 1, &tbab);
    ToolBar_AddButtons(hwndTB, 1, tbb);
    NumBitmaps++;

    // Play_Stop
    tbb[0].iBitmap = NumBitmaps;
    tbb[0].idCommand = IDB_PLAY_STOP;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_BUTTON;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;
    tbab.hInst = hInst;
    tbab.nID = tbb[0].idCommand;
    ToolBar_AddBitmap(hwndTB, 1, &tbab);
    ToolBar_AddButtons(hwndTB, 1, tbb);
    NumBitmaps++;

    // Seperator
    tbb[0].iBitmap = 0;
    tbb[0].idCommand = 0;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_SEP;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;	
    ToolBar_AddButtons(hwndTB, 1, tbb);

    // HELP
    tbb[0].iBitmap = NumBitmaps;
    tbab.nID = IDB_HELP;
    tbb[0].idCommand = IDM_HELP_HELPFILE;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_BUTTON;
    tbb[0].dwData = 0;
    tbb[0].iString = tbb[0].idCommand;
    tbab.hInst = hInst;
    ToolBar_AddBitmap(hwndTB, 1, &tbab);
    ToolBar_AddButtons(hwndTB, 1, tbb);
    NumBitmaps++;

    // Enabled
    ToolBar_EnableButton(hwndTB, IDB_PLAY_PLAY, TRUE);
    ToolBar_EnableButton(hwndTB, IDB_PLAY_PAUSE, TRUE);
    ToolBar_EnableButton(hwndTB, IDB_PLAY_STOP, TRUE);

    // Hide the pause button
    ToolBar_HideButton(hwndTB, IDB_PLAY_PAUSE, TRUE);

    ToolBar_CheckButton(hwndTB, IDM_OPTIONS_FULLSCREEN, gbFullscreen);

    // Fetch handle to tooltip control
    HWND hwndTT = ToolBar_GetToolTips(hwndTB);
    ToolTip_SetDelayTime(hwndTT, TTDT_AUTOPOP, 32000); 

    // Show the toolvar
    ShowWindow(hwndTB, SW_SHOW); 

    return hwndTB; 
} 

BOOL CALLBACK
HelpAboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDOK:
                {
                    EndDialog(hwndDlg, 1);					
                    break;
                }
            }
            return 0;
        }		
    }

    return FALSE;
}

BOOL CALLBACK
DialogProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam) 
{
    HWND hwndTabControl,hwndControl,hwndTreeControl;
    TCITEM tie;
    HIMAGELIST himl;
    HCURSOR hOldCursor;

    switch (mMsg)
    {
    case WM_INITDIALOG:
        {
            // Disable irrelevant controls
            hwndControl = GetDlgItem( hwnd, IDC_PRESENT );
            EnableWindow(hwndControl, FALSE);
            hwndControl = GetDlgItem( hwnd, IDC_DELETE );
            EnableWindow(hwndControl, FALSE);

            // We are going to save the *ORIGINAL* size of
            // Step 1 and 2 bitmaps in some globals
            hwndControl = GetDlgItem(hwnd, IDC_STEP1);
            GetWindowRect(hwndControl, &grcStep1);
            hwndControl = GetDlgItem(hwnd, IDC_STEP2);
            GetWindowRect(hwndControl, &grcStep2);
            hwndControl = GetDlgItem(hwnd, IDC_STEP3);
            GetWindowRect(hwndControl, &grcStep3);

            // Construct an image list for IDC_TABTEXT
            //  IDB_ICONINFORMATION
            //  IDB_ICONNOTES
            himl = ImageList_LoadBitmap(hInst,
                MAKEINTRESOURCE(IDB_TABIMAGELIST2),
                16,
                2,
                RGB(255,0,0));

            // Add two tabs to IDC_TABTEXT
            hwndTabControl = GetDlgItem(hwnd, IDC_TABTEXT);
            TabCtrl_SetImageList(hwndTabControl,himl);
            tie.mask = TCIF_TEXT | TCIF_IMAGE;
            tie.iImage = 0;
            tie.pszText = "Video Clip Information";
            TabCtrl_InsertItem(hwndTabControl, 0, &tie);
            tie.iImage = 1;
            tie.pszText = "Video Clip Notes";
            TabCtrl_InsertItem(hwndTabControl, 1, &tie);

            // Add 
            himl = ImageList_LoadBitmap(hInst,
                MAKEINTRESOURCE(IDB_TABIMAGELIST1),
                13,
                2,
                CLR_NONE);
            hwndTabControl = GetDlgItem(hwnd, IDC_TABFILTER);
            TabCtrl_SetImageList(hwndTabControl,himl);

            // Selections and Playlist TREEVIEW
            himl = ImageList_LoadBitmap(hInst,
                MAKEINTRESOURCE(IDB_TREEVIDEO),
                15,
                4,
                CLR_NONE);
            hwndTreeControl = GetDlgItem(hwnd, IDC_TREERESULTLIST);
            TreeView_SetImageList(hwndTreeControl,himl,TVSIL_NORMAL);
            hwndTreeControl = GetDlgItem(hwnd, IDC_TREEPLAYLIST);
            TreeView_SetImageList(hwndTreeControl,himl,TVSIL_NORMAL);

            // Selections and Playlist TREEVIEW
            himl = ImageList_LoadBitmap(hInst,
                MAKEINTRESOURCE(IDB_TREEHYPHEN),
                15,
                4,
                CLR_NONE);
            hwndTreeControl = GetDlgItem(hwnd, IDC_TREEFILTER);
            TreeView_SetImageList(hwndTreeControl,himl,TVSIL_NORMAL);

            return TRUE;
        }

    case WM_NOTIFY:
        {
            // We get here when either one of the 2 TAB controls
            // changes or when a selection or check state in
            // one of the three TREEVIEW controls changes.
            int idCtrl = (int)wParam;
            LPNMHDR pnmh = (LPNMHDR)lParam;
            LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
            BOOL bNewCheckState;

            // Let's determine what kind of notifiction message
            // we have.
            //
            //  pnmh
            //      hwndFrom : Window handle to the control sending a message. 
            //      idFrom : Identifier of the control sending a message. 
            //      code : Notification code. This member can be a control-specific notification code or it can be one of the common notification codes. 
            //
            switch (pnmh->idFrom)
            {
            case IDC_TABFILTER:
                hOldCursor = GetCursor();
                SetCursor(LoadCursor(NULL,IDC_WAIT));
                if (pnmh->code == TCN_SELCHANGE)
                {
                    gbTabReady=FALSE;
                    db_SaveCurrentNotes();
                    db_ConstructFilterTree(TabCtrl_GetCurSel(pnmh->hwndFrom));
                    SetPromptSave(TRUE);
                    gbTabReady=TRUE;
                }                    
                db_UpdateTABIcons();
                SetCursor(hOldCursor);
                break;
            case IDC_TABTEXT:
                if (pnmh->code == TCN_SELCHANGING)
                {
                    if (TabCtrl_GetCurSel(pnmh->hwndFrom)==1)
                    {
                        db_SaveCurrentNotes();
                    }
                }
                if (pnmh->code == TCN_SELCHANGE)
                {
                    SetPromptSave(TRUE);
                    db_UpdateEditControl();
                }
                break;
            case IDC_TREEFILTER:
                if (gbTabReady)
                {
                    if (pnmh->code == TVN_SELCHANGED)
                        db_SaveCurrentNotes();
                    bNewCheckState = db_DetermineTreeChecked( GetDlgItem(hwndDialog, IDC_TREEFILTER), TabCtrl_GetCurSel(GetDlgItem(hwndDialog, IDC_TABFILTER)) );
                    if (bNewCheckState)
                    {
                        SetPromptSave(TRUE);

                        // The check state has changed. We
                        // must determine whether the TAB 
                        // should include a TAB should include
                        // the CHeck icon to indicate filtering
                        //
                        db_UpdateTABIcons();
                        db_UpdateSelections();

                        db_SetMovieIndex(FALSE);

                        SetFocus(GetDlgItem(hwndDialog, IDC_TREERESULTLIST));
                    }
                }
                break;

            case IDC_TREERESULTLIST:
                if (!gbConstructingResultList)
                {
                    if (pnmh->code == NM_DBLCLK)
                    {
                        PlayMovie();
                    }
                    if (pnmh->code == TVN_SELCHANGED)
                    {
                        db_SaveCurrentNotes();
                        // pnmtv->itemOld is type TVITEM
                        // pnmtv->itemNew is type TVITEM
                        //
                        db_SetMovieIndex(FALSE);
                    }
                    if (pnmh->code == NM_SETFOCUS)
                    {
                        db_SetMovieIndex(FALSE);
                    }
                }
                break;
            case IDC_TREEPLAYLIST:
                if (!gbConstructingPlaylist)
                {
                    if (pnmh->code == NM_DBLCLK)
                    {
                        PlayMovie();
                    }
                    if (pnmh->code == TVN_SELCHANGED)
                    {
                        db_SaveCurrentNotes();
                        // pnmtv->itemOld is type TVITEM
                        // pnmtv->itemNew is type TVITEM
                        //
                        //pnmtv = (LPNMTREEVIEW)lParam;
                        db_SetMovieIndex(TRUE);
                    }
                    if (pnmh->code == NM_SETFOCUS)
                    {
                        db_SetMovieIndex(TRUE);
                    }
                }
                break;
            }
            return TRUE;
        }

    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDC_EDIT:
                {
                    SetPromptSave(TRUE);
                    if (HIWORD(wParam)==EN_KILLFOCUS)
                    {
                        db_SaveCurrentNotes();
                    }
                    break;
                }
            case IDC_ADD:
                {
                    SetPromptSave(TRUE);
                    db_AddToPlaylist();
                    SetFocus(GetDlgItem(hwndDialog, IDC_TREERESULTLIST));
                    break;
                }
            case IDC_DELETE:
                {
                    SetPromptSave(TRUE);
                    db_DeleteFromPlaylist();
                    SetFocus(GetDlgItem(hwndDialog, IDC_TREERESULTLIST));
                    db_SetMovieIndex(TRUE);
                    break;
                }
            case IDC_MOVEUP:
                {
                    SetPromptSave(TRUE);
                    db_MoveClipUp();
                    SetFocus(GetDlgItem(hwndDialog, IDC_TREEPLAYLIST));
                    break;
                }
            case IDC_MOVEDOWN:
                {
                    SetPromptSave(TRUE);
                    db_MoveClipDown();
                    SetFocus(GetDlgItem(hwndDialog, IDC_TREEPLAYLIST));
                    break;
                }
            case IDC_PRESENT:
                {
                    bPresentingPlaylist = TRUE;
                    break;
                }
            }
            break;
        }
    }

    return FALSE;
}

BOOL
BrowseForCDROM(HWND hwnd,char *FilledWithPath,char *lpName) 
{ 
    BOOL bReturn = FALSE;
    LPMALLOC g_pMalloc;// <-- I Added This 

    BROWSEINFO bi; 
    LPSTR lpBuffer; 
    LPITEMIDLIST pidlPrograms;  // PIDL for Programs folder 
    LPITEMIDLIST pidlBrowse;    // PIDL selected by user 

    SHGetMalloc(&g_pMalloc);// <-- I Added This 

    // Allocate a buffer to receive browse information. 
    if ( (lpBuffer=(LPSTR)g_pMalloc->Alloc(_MAX_PATH)) == NULL ) 
    {
        MessageBox(hwndMain,"Can not allocate any more memory. Try closing some other applications before running this application.\n\nif ( (lpBuffer=(LPSTR)g_pMalloc->Alloc(_MAX_PATH)) == NULL ) ","Error",MB_OK);
        return FALSE; 
    }

    // Get the PIDL for the Programs folder. 
    //if (!SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_DRIVES, &pidlPrograms)))
    //if (!SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_NETWORK, &pidlPrograms)))
    if (!SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &pidlPrograms)))
    { 
        MessageBox(hwndMain,"Can not allocate any more memory. Try closing some other applications before running this application.\n\nif (!SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_DRIVES, &pidlPrograms)))","Error",MB_OK);
        g_pMalloc->Free(lpBuffer); 
        return FALSE; 
    }

    // Fill in the BROWSEINFO structure. 
    bi.hwndOwner = hwnd; 
    bi.pidlRoot = pidlPrograms; 
    bi.pszDisplayName = lpBuffer; 
    bi.lpszTitle = "1. Insert the CD-ROM and wait for it to warm up.  2. Select the location of the CD-ROM drive below. Ex. (D:)  3. Click OK.";
    bi.ulFlags = BIF_RETURNONLYFSDIRS; 
    bi.lpfn = NULL; 
    bi.lParam = 0; 

    // Browse for a folder and return its PIDL. 
    pidlBrowse = SHBrowseForFolder(&bi); 
    if (pidlBrowse != NULL) 
    { 
        strcpy(lpName,lpBuffer);
        SHGetPathFromIDList(pidlBrowse, lpBuffer);
        strcpy(FilledWithPath,lpBuffer);

        // Free the PIDL returned by SHBrowseForFolder. 
        g_pMalloc->Free(pidlBrowse); 
        bReturn = TRUE;
    } 

    // Clean up. 
    g_pMalloc->Free(pidlPrograms); 
    g_pMalloc->Free(lpBuffer); 

    return bReturn;
} 

BOOL
GetUserConfiguration(void)
{
    int MessageBoxResult;
    char buffer[1024];
    HANDLE hFile;

    // Open User.cfg file containing user's settings.
    // If this file does not exist, we create it.
    // We have user select the location of thier CD-ROM
    // drive and then it is placed into this file.
    //
    if ( (hFile = r3d_FileOpen( "User.cfg", R3D_READ)) == INVALID_HANDLE_VALUE)
    {
        MessageBox(hwndMain,"Welcome to Word for Word. This software needs to be configured to specify the location of your CD-ROM drive. Please follow the instructions carefully.",szAppName,MB_OK|MB_ICONINFORMATION);
        if (SetUserConfiguration()==FALSE)
        {
            // Either an invalid drive has been specified or none 
            // has been specified at all. Exit with error.
            return FALSE;
        }
    }
    else
    {
        // Read the info from the file.
        r3d_FileRead(hFile,CDROM_Path,_MAX_PATH);
        r3d_FileClose(hFile);
    }

    // We now have what appears to be a valid CD-ROM drive. 
    // Try to open the database file. If it does not exist,
    // we have a problem. We need to go through some process 
    // of verifying and changing either the CD-ROM drive 
    // location and/or loading the DISK into the drive.
    if (db_Open(CDROM_Path)==FALSE)
    {
        // Houston, we've got a problem. First, we'll
        // verify the CD-ROM drive to be accurate.
        wsprintf(buffer,"An error has occurred when trying to access the database and video files on the CD-ROM drive.\n\nIs (Drive %s) the proper location of your CD-ROM drive?",CDROM_Path);
        MessageBoxResult = MessageBox(hwndMain,buffer,szAppName,MB_YESNO|MB_ICONQUESTION);
        if (MessageBoxResult==IDNO)
        {
            // Get new drive location.
            if (SetUserConfiguration()==FALSE)
            {
                // Either an invalid drive has been 
                // specified or none has been specified 
                // at all. Exit with error.
                return FALSE;
            }
        }
        // Second, we'll verify that a CD-ROM is loaded.
        wsprintf(buffer,"Is there a valid CD-ROM disk containing the database and video files currently loaded in CD-ROM drive at (Drive %s) ?",CDROM_Path);
        MessageBoxResult = MessageBox(hwndMain,buffer,szAppName,MB_YESNO|MB_ICONQUESTION);
        if (MessageBoxResult==IDNO)
        {
            wsprintf(buffer,"Please insert a valid CD-ROM disk containing the database and video files into the CD-ROM drive at (Drive %s). Wait for a few second for the CD-ROM drive to warm up and then click the [OK] button below.",CDROM_Path);
            MessageBox(hwndMain,buffer,szAppName,MB_OK|MB_ICONINFORMATION);
        }
        // All is now verified. If the user didn't do something
        // dumb like specify the wrong CD-ROM drive or load
        // the wrong CD-ROM into the drive, we exit with error.
        if (db_Open(CDROM_Path)==FALSE)
            return FALSE;
    }

    return TRUE;
}

// Write the CD-ROM drive location to the new file.
BOOL
SetUserConfiguration(void)
{
    HANDLE hFile;
    char FolderPath[_MAX_PATH],FolderName[_MAX_PATH];

    // Establish path of CD-ROM drive
    if (BrowseForCDROM(hwndMain,FolderPath,FolderName)==FALSE)
        return FALSE;

    // Copy path to CDROM_Path
    strcpy(CDROM_Path,FolderPath);

    // If there is a terminating \ then get rid of it. Root 
    // directories contain a backslash whereas directories 
    // do not.
    if (CDROM_Path[strlen(CDROM_Path)-1]=='\\')
    {
        CDROM_Path[strlen(CDROM_Path)-1]='\0';
    }

    hFile = r3d_FileOpen( "User.cfg", R3D_WRITE|R3D_CREATE|R3D_TRUNCATE);
    r3d_FileWrite(hFile,CDROM_Path,_MAX_PATH);
    r3d_FileClose(hFile);

    return TRUE;
}

void
DisplayErrorText(DWORD dwLastError)
{ 
    LPSTR MessageBuffer;

    // Call FormatMessage() to allow for message text to be acquired
    // from the system or the supplied module handle
    //
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_IGNORE_INSERTS |
        FORMAT_MESSAGE_FROM_SYSTEM | // always consider system table
        0,
        NULL,
        dwLastError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
        (LPSTR) &MessageBuffer,
        0,
        NULL
        );

    // Display the formated message
    MessageBox(hwndMain, MessageBuffer,"ERROR",MB_OK);

    // Free the buffer allocated by the system
    LocalFree(MessageBuffer);
}

BOOL
RunHelp(HWND hwndMain)
{
    //if ((int)ShellExecute(hwndMain,"open","Readme.doc",NULL,NULL,SW_MAXIMIZE)<32)
    if ((int)ShellExecute(hwndMain,"open","User's Guide.doc",NULL,NULL,SW_MAXIMIZE)<32)
    {
        MessageBox(hwndMain,"An error occured when trying to access the Readme.doc file.",szAppName,MB_OK|MB_ICONERROR);
        return FALSE;
    }
    return TRUE;
}

void
OnFilterTabChange(HWND hwndTabControl)
{
    gbTabReady=FALSE;
    db_ConstructFilterTree(TabCtrl_GetCurSel(hwndTabControl));
    gbTabReady=TRUE;
}

void
ToolBar_ShowPlay(void)
{
    if (ToolBar_IsButtonHidden(hwndToolBar,IDB_PLAY_PLAY))
    {
        ToolBar_HideButton(hwndToolBar,IDB_PLAY_PLAY,FALSE);
        ToolBar_HideButton(hwndToolBar,IDB_PLAY_PAUSE,TRUE);
        ToolBar_CheckButton(hwndToolBar,IDB_PLAY_PAUSE,FALSE);
    }
}

void
ToolBar_ShowPause(void)
{
    if (ToolBar_IsButtonHidden(hwndToolBar,IDB_PLAY_PAUSE))
    {
        ToolBar_HideButton(hwndToolBar,IDB_PLAY_PLAY,TRUE);
        ToolBar_HideButton(hwndToolBar,IDB_PLAY_PAUSE,FALSE);
        ToolBar_CheckButton(hwndToolBar,IDB_PLAY_PAUSE,FALSE);
    }
}

void
ConstructTitleBar(void)
{
    char TitleBar[_MAX_PATH+64];

    // Success
    strcpy(TitleBar,szAppName);
    strcat(TitleBar," - [");
    strcat(TitleBar,FilenameWFW);
    if (gbPromptSave)
        strcat(TitleBar," *");
    strcat(TitleBar,"]");
    SetWindowText(hwndMain,TitleBar);
}

void
SetPromptSave(BOOL bPromptSave)
{
    gbPromptSave = bPromptSave;
    ConstructTitleBar();
}

void
WordforWordFile_Close(void)
{
    gbTabReady=FALSE;

    // Destroy Playlist
    // Destroy all notes
    // Uncheck all filtering options
    // Make sure that fullscreen is not checked
    db_DeletePlaylist();
    db_DeleteNotes();
    db_ClearFilterOptions();

    // Make sure play buttons are enabled.
    ToolBar_EnableButton(hwndToolBar, IDB_PLAY_PLAY, TRUE);
    ToolBar_EnableButton(hwndToolBar, IDB_PLAY_PAUSE, TRUE);
    ToolBar_EnableButton(hwndToolBar, IDB_PLAY_STOP, TRUE);
    ToolBar_ShowPlay();

    gbTabReady=TRUE;
}

// WordforWordFile_Open assumes that all states are set to defult 
// project settings... Default meaning the same states as when
// the Word for Word first starts up or after
// WordforWordFile_Close has been called.
void
WordforWordFile_Open(char *Pathname)
{
    HANDLE hFile;
    int FileVersion;
    char AssociatedProjectName[256];
    char buffer[1024];
    char Filename[_MAX_FNAME],Extension[_MAX_EXT];
    char Filename83[_MAX_FNAME];
    int AnInt;

    // Get only the filename...
    _splitpath(Pathname,NULL,NULL,Filename,Extension);
    strcpy(Filename83,Filename);
    strcat(Filename83,Extension);

    gbTabReady=FALSE;

    // Open file...
    if ( (hFile = r3d_FileOpen( Pathname, R3D_READ)) == INVALID_HANDLE_VALUE)
    {
        MessageBox(hwndMain,Pathname,"Error opening file",MB_OK);
        return;
    }

    // Read Header
    r3d_FileRead(hFile,&FileVersion,sizeof(int));
    r3d_FileRead(hFile,&AssociatedProjectName,256);

    // At this point we check the header to see if it conforms.
    if (FileVersion!=FILEVERSION)
    {
        // Error
        MessageBox(hwndMain,"Incompatible file version. This procedure will now abort.",szAppName,MB_OK|MB_ICONINFORMATION);
        r3d_FileClose(hFile);
        strcpy(FilenameWFW,"Untitled.wfw");
        SetPromptSave(FALSE);
        return;
    }
    if ( strcmp(AssociatedProjectName,db_GetProjectName()) !=0 )
    {
        // Error
        wsprintf(buffer,"The %s file that you are trying to load is associated with the project named \"%s\".\n\nHowever, the project CD-ROM that you have loaded is \"%s\". If you would like to open the %s file, please close the %s application, load the \"%s\" CD-ROM, and then try loading the %s file again.\n\nThis procedure will now abort.",Filename83, AssociatedProjectName, db_GetProjectName(), Filename83, szAppName, AssociatedProjectName, Filename83);
        MessageBox(hwndMain,buffer,szAppName,MB_OK|MB_ICONINFORMATION);
        r3d_FileClose(hFile);
        strcpy(FilenameWFW,"Untitled.wfw");
        SetPromptSave(FALSE);
        return;
    }

    // Read States
    r3d_FileRead(hFile,&AnInt,sizeof(int));
    TabCtrl_SetCurSel(GetDlgItem(hwndDialog,IDC_TABFILTER),AnInt);
    r3d_FileRead(hFile,&AnInt,sizeof(int));
    TabCtrl_SetCurSel(GetDlgItem(hwndDialog,IDC_TABTEXT),AnInt);

    // Read selected filter selections
    db_ImportFilterSelections(hFile);

    // Read playlist
    db_ImportPlaylist(hFile);

    // Read notes
    db_ImportNotes(hFile);

    // Update interface based on new imported settings
    db_ConstructFilterTree(TabCtrl_GetCurSel(GetDlgItem(hwndDialog,IDC_TABFILTER)));
    db_UpdateSelections();
    db_UpdateTABIcons();

    SetFocus(GetDlgItem(hwndDialog,IDC_TREERESULTLIST));

    // Close file...
    r3d_FileClose(hFile);

    gbTabReady=TRUE;
}

void
WordforWordFile_Save(char *Pathname)
{
    HANDLE hFile;
    int FileVersion = FILEVERSION;
    char AssociatedProjectName[256];
    int AnInt;

    gbTabReady=FALSE;

    // Save file...
    if ( (hFile = r3d_FileOpen( Pathname, R3D_WRITE|R3D_CREATE|R3D_TRUNCATE)) == INVALID_HANDLE_VALUE)
    {
        MessageBox(hwndMain,Pathname,"Error saving file",MB_OK);
        return;
    }

    // Write Header
    r3d_FileWrite(hFile,&FileVersion,sizeof(int));
    strcpy(AssociatedProjectName,db_GetProjectName());
    r3d_FileWrite(hFile,&AssociatedProjectName,256);

    // Write States
    AnInt = TabCtrl_GetCurSel(GetDlgItem(hwndDialog,IDC_TABFILTER));
    r3d_FileWrite(hFile,&AnInt,sizeof(int));
    AnInt = TabCtrl_GetCurSel(GetDlgItem(hwndDialog,IDC_TABTEXT));
    r3d_FileWrite(hFile,&AnInt,sizeof(int));

    // Write selected filter selections
    db_ExportFilterSelections(hFile);

    // Write playlist
    db_ExportPlaylist(hFile);

    // Write notes
    db_ExportNotes(hFile);

    // Close file...
    r3d_FileClose(hFile);

    gbTabReady=TRUE;
}

LRESULT CALLBACK
MovieWndProc(HWND hwnd, UINT mMsg, WPARAM wParam, LPARAM lParam)
{
    switch (mMsg)
    {
    case MM_MCINOTIFY:
        {
            switch (wParam)
            {
            case MCI_NOTIFY_SUCCESSFUL:
                {
                    //Movie_Stop();
                    //Movie_Close();
                    bMovieIsPlaying = FALSE;
                    ToolBar_ShowPlay();
                    break;
                }
            }
            return 0;
        }

    default:
        return (DefWindowProc(hwnd, mMsg, wParam, lParam));
    }
}

// Returns:
//    0                          = Unknown (This is a failure case)
//    VER_PLATFORM_WIN32_WINDOWS = Windows 9X platform
//    VER_PLATFORM_WIN32_NT      = Windows NT platform
// 
BOOL
ProcessOperatingSystem(void)
{
    OSVERSIONINFO osVer;
    DWORD pdwPlatform;

    // First get the windows platform
    osVer.dwOSVersionInfoSize = sizeof(osVer);
    if (!GetVersionEx( &osVer ))
    {
        // We don't know but we try to run the app anyway
        // by returning TRUE.
        pdwPlatform = 0;
        return TRUE;
    }
    else
    {
        if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
        {
            // Windows NT
            pdwPlatform = VER_PLATFORM_WIN32_NT;
            if (osVer.dwMajorVersion < 4)
            {
                MessageBox(NULL,"This application will not work on any version of Windows NT prior to Windows NT 4. This application will now abort.",szAppName,MB_OK|MB_ICONERROR);
                return FALSE;
            }
            else
            {
                //MessageBox(NULL,"This application MAY not function correctly on systems which contain the Windows NT operating system.  If you experience any problems, you will need to install and run this application on systems equipped with either the Windows 95 or Windows 98 operating systems.  Click OK to continue.",szAppName,MB_OK|MB_ICONINFORMATION);
                return TRUE;
            }
        }
        else
        {
            // Windows 95 or Windows 98
            pdwPlatform = VER_PLATFORM_WIN32_WINDOWS;
            return TRUE;
        }
    }

    return TRUE;
}

void
PlayMovie(void)
{
    HCURSOR hOldCursor;
    BOOL bPathnameExists;
    char Pathname[_MAX_PATH];
    HANDLE find_handle;
    WIN32_FIND_DATA win32_find_data;
    char buffer[_MAX_PATH+512];
    BOOL bShowMessage;
    HWND hwndMovieMockFullscreen;

    bShowMessage = FALSE;
    if (bPresentingPlaylist)
    {
        if (PresentingPlaylistIndex==0)
            bShowMessage = TRUE;
    }
    else if (gbFullscreen)
    {
        bShowMessage = TRUE;
    }


    // This will play the currently selected movie

    // If a movie is open, close it.
    if (Movie_IsOpen())
    {
        Movie_Stop();
        ToolBar_ShowPlay();
        Movie_Close();
    }

    // Now determine whether the movie file
    // to be played is even available at the
    // specific path.
    bPathnameExists = TRUE;
    strcpy(Pathname,CDROM_Path);
    strcat(Pathname,"\\");
    strcat(Pathname,db_GetCurrentMovieFilename());
    if ( (find_handle=FindFirstFile(Pathname,&win32_find_data)) == INVALID_HANDLE_VALUE)
    {
        wsprintf(buffer,"Please insert Disk %d of \"%s\" into the CD-ROM Drive. Wait for the CD-ROM Drive to warm up. Then click OK.",db_GetCurrentMovieDiskNumber(),db_GetProjectName());
        MessageBox(hwndMain,buffer,szAppName,MB_OK|MB_ICONWARNING);
        if ( (find_handle=FindFirstFile(Pathname,&win32_find_data)) == INVALID_HANDLE_VALUE)
        {
            wsprintf(buffer,"There was an error opening the following video file:\n\n%s\n\nPlease make sure that you have Disk %d of \"%s\" inserted into the CD-ROM Drive. Then try again.",Pathname,db_GetCurrentMovieDiskNumber(),db_GetProjectName());
            MessageBox(hwndMain,buffer,"Error",MB_OK|MB_ICONERROR);
            bPathnameExists = FALSE;
        }
    }    
    FindClose(find_handle);

    // At this point the path exists
    if (bPathnameExists)
    {
        hOldCursor = GetCursor();
        SetCursor(LoadCursor(NULL,IDC_WAIT));

        // OK... open and play the movie
        //
        // By the way... The error on the new Laptop 
        // running Windows ME occurs somewhere in the 
        // Movie_Open function.
        //
        if (Movie_Open(Pathname)==FALSE)
        {
            MessageBox(hwndMain,"Can not open movie","Error",MB_OK|MB_ICONERROR);
            return;
        }
        else
        {
            // On windows NT, it seems that
            // video's don't always play
            // in the window. They always play
            // when the window moves... We 
            // try to simulate that here.
            // 
            InvalidateRect(hwndMovie, NULL, TRUE);
            UpdateWindow(hwndMovie);

            if (gbFullscreen)
            {
                if (bShowMessage)
                {
                    //MessageBox(hwndMovie,"Press the [ESC] key to stop playback at any time.","Note",MB_OK|MB_ICONINFORMATION);
                    DialogBox(hInst,MAKEINTRESOURCE(IDD_MESSAGEBOX_FULLSCREEN),hwndDialog,FullscreenProc);
                    InvalidateRect(hwndDialog, NULL, TRUE);
                    UpdateWindow(hwndDialog);
                }

                // Hide Cursor
                ShowCursor(FALSE);

                // Create Movie Window
                hwndMovieMockFullscreen = CreateWindowEx(WS_EX_TOPMOST,
                    "MovieMockFullscreen", NULL,
                    WS_POPUP|WS_VISIBLE|WS_MAXIMIZE,
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    hwndMain, NULL, hInst, NULL);
                ShowWindow(hwndMovieMockFullscreen, SW_MAXIMIZE);
                UpdateWindow(hwndMovieMockFullscreen);

                // Play Movie
                Movie_Play(TRUE,hwndMovieMockFullscreen,FALSE,db_GetStartTime(db_GetCurrentMovieIndex()),db_GetEndTime(db_GetCurrentMovieIndex()),db_GetFramesPerSecond(db_GetCurrentMovieIndex()));

                DestroyWindow(hwndMovieMockFullscreen);

                // Show Cursor
                ShowCursor(TRUE);
            }
            else
            {
                if (bShowMessage && bPresentingPlaylist)
                {
                    //MessageBox(hwndMovie,"Press the [ESC] key to stop playback at any time.","Note",MB_OK|MB_ICONINFORMATION);
                    DialogBox(hInst,MAKEINTRESOURCE(IDD_MESSAGEBOX_FULLSCREEN),hwndDialog,FullscreenProc);
                    InvalidateRect(hwndDialog, NULL, TRUE);
                    UpdateWindow(hwndDialog);
                }

                // Save Cursor
                hOldCursor = GetCursor();
                SetCursor(LoadCursor(NULL,IDC_WAIT));

                // Play Movie
                Movie_Play(bPresentingPlaylist,hwndMovie,FALSE,db_GetStartTime(db_GetCurrentMovieIndex()),db_GetEndTime(db_GetCurrentMovieIndex()),db_GetFramesPerSecond(db_GetCurrentMovieIndex()));

                // Restore Cursor
                SetCursor(hOldCursor);

                if (bPresentingPlaylist==FALSE)
                    ToolBar_ShowPause();
            }

            // On windows NT, it seems that
            // video's don't always play
            // in the window. They always play
            // when the window moves... We 
            // try to simulate that here.
            //
            InvalidateRect(hwndMovie, NULL, TRUE);
            UpdateWindow(hwndMovie);
        }
    }
}

BOOL CALLBACK
FullscreenProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDOK:
                {
                    EndDialog(hwndDlg, IDOK);
                    break;
                }
            }
            return 0;
        }		
    }

    return FALSE;
}

BOOL CALLBACK
ContinuePlaylistProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            case IDYES:
                {
                    EndDialog(hwndDlg, IDYES);
                    break;
                }
            case IDNO:
                {
                    EndDialog(hwndDlg, IDNO);
                    break;
                }
            }
            return 0;
        }		
    }

    return FALSE;
}