//==========================================================================;
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE.
//
//  Copyright (c) 1992 - 1997  Microsoft Corporation.  All Rights Reserved.
//
//--------------------------------------------------------------------------;

#include "stdwin.h"
#include "cplay.h"
#include "about.h"
#include "file.h"
#include "media.h"
#include "toolbar.h"
#include "resource.h"

//
//
// What this sample illustrates
//
// A simple ActiveMovie application written in C.
//
//
// Summary
//
// This is an ActiveMovie application that is written in C. We create a window
// that has a simple menu allowing files to be opened and closed. The window
// also has three buttons for stopping, pausing and running the media. We are
// written to call the standard filtergraph interfaces. The only complication
// we have added is two UI alternatives. The filter can either be compiled to
// rewind to the start of the media when it is stopped, or alternatively it
// can leave the current position (and therefore frame) wherever it is stopped
//
// Files
//
// about.c          Run of the mill about box
// about.h          Header file for about box
// assert.c         Display a message box
// cplay.c          Main application code
// cplay.h          And its function protoypes
// file.c           Looks after file open dialogs
// file.h           And its two function prototypes
// makefile         How we build it
// media.c          Functions that call the graph
// media.h          And their prototypes
// player.rc        Visual C++ resource file
// resource.h       Header file for resources
// stdwin.c         Precompiled header file
// stdwin.h         Precompiled header file
// toolbar.c        Looks after the app toolbar
// toolbar.h        Public function prototypes
//
//


#define UNTITLED_STRING " - Untitled"
#define nMaxResourceStrSize 128

AppVars appVars;


//
// PlayerMessageBox
//
// Load and display an error message
//
void PlayerMessageBox( UINT nResource )
{
    char szStr[ nMaxResourceStrSize ];

    LoadString( appVars.hInstance, nResource, szStr, nMaxResourceStrSize );
    MessageBox( appVars.hwndMainFrame, szStr, appVars.szAppName,
                MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION );

} // PlayerMessageBox


//
// ProcessCommand
//
// Process a WM_COMMAND message to the main window
//
long ProcessCommand( HWND hwnd, UINT wParam, LONG lParam )
{
    switch( wParam ){
        case ID_FILE_EXIT:
            PostQuitMessage( 0 );
            break;

        case ID_HELP_ABOUT:
            DoAboutDialog( appVars.hInstance,hwnd );
            break;

        case ID_FILE_OPEN:
            OpenMediaFile( hwnd, NULL );
            break;

        case ID_MEDIA_PLAY:
            OnMediaPlay( );
            break;

        case ID_MEDIA_PAUSE:
            OnMediaPause( );
            break;

        case ID_MEDIA_STOP:
            OnMediaStop( );
            break;

        default:
            return DefWindowProc( hwnd, WM_COMMAND, wParam, lParam );
    }
    return (LRESULT) 0;

} // ProcessCommand


//
// OnGetMinMaxInfo
//
// Sets the minimum size of the main window and the maximum height
//
void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
    RECT rectRequired;
    SIZE sizeToolbar;

    // Our client area is going to be the toolbar, so find our its size
    CalcRequiredSize( &sizeToolbar );

    rectRequired.left = rectRequired.top = 0;
    rectRequired.right = sizeToolbar.cx;
    rectRequired.bottom = sizeToolbar.cy;

    // Take into account the menu, caption and thick frame
    AdjustWindowRect( &rectRequired, WS_CAPTION|WS_THICKFRAME, TRUE );

    // Set the min/max sizes
    lpMMI->ptMinTrackSize.x = rectRequired.right - rectRequired.left;
    lpMMI->ptMinTrackSize.y = lpMMI->ptMaxTrackSize.y =
            rectRequired.bottom - rectRequired.top;

} // OnGetMinMaxInfo


//
// MainFrameProc
//
// Handles the message sent to the main window
//
long FAR PASCAL MainFrameProc( HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    switch( message ){
        case WM_DESTROY:
            PostQuitMessage( 0 );
            break;

        case WM_GETMINMAXINFO:
            OnGetMinMaxInfo( (MINMAXINFO FAR *) lParam );
            break;

        case WM_DRAWITEM:
            DrawButton( appVars.hInstance, (DRAWITEMSTRUCT FAR *) lParam );
            break;

        case WM_INITMENUPOPUP:
            if( lParam == 1 ){          // Media popup menu
                EnableMenuItem( (HMENU) wParam, ID_MEDIA_PLAY,  CanPlay()  ? MF_ENABLED : MF_GRAYED );
                EnableMenuItem( (HMENU) wParam, ID_MEDIA_PAUSE, CanPause() ? MF_ENABLED : MF_GRAYED );
                EnableMenuItem( (HMENU) wParam, ID_MEDIA_STOP,  CanStop()  ? MF_ENABLED : MF_GRAYED );
            } else
                return DefWindowProc( hwnd, message, wParam, lParam );
            break;

        case WM_COMMAND:
            return ProcessCommand( hwnd, wParam, lParam );

        default:
            return DefWindowProc( hwnd, message, wParam, lParam );
    }
    return (LRESULT) 0;

} // MainFrameProc


//
// InitApplication
//
BOOL InitApplication()
{
    strcpy( appVars.szAppName, APP_NAME );

    // Filter interface initialize?
    if( SUCCEEDED( CoInitialize( NULL )))
		return TRUE;

    return FALSE;
}


//
// UnInitApplication
//
void UnInitApplication()
{
    CoUninitialize( );
}


//
// InitInstance
//
// Set the specific instance data and register our main
// window class if it has not been registered already
//
BOOL InitInstance( HANDLE hInstance, HANDLE hPrevInstance )
{
    appVars.hInstance = hInstance;

    if(!hPrevInstance){
        WNDCLASS wndClass;

        wndClass.style          = CS_HREDRAW | CS_VREDRAW;
        wndClass.lpfnWndProc    = MainFrameProc;
        wndClass.cbClsExtra     = 0;
        wndClass.cbWndExtra     = 0;
        wndClass.hInstance      = appVars.hInstance;
        wndClass.hIcon          = LoadIcon( appVars.hInstance, MAKEINTRESOURCE( IDR_MAINFRAME ));
        wndClass.hCursor        = LoadCursor( NULL, IDC_ARROW );
        wndClass.hbrBackground  = GetStockObject( LTGRAY_BRUSH );
        wndClass.lpszMenuName   = MAKEINTRESOURCE( IDR_MAINFRAME );
        wndClass.lpszClassName  = appVars.szAppName;

        RegisterClass( &wndClass );
    }

    return TRUE;

} // InitInstance


//
// InitMainFrame
//
// Create our main window
//
BOOL InitMainFrame( int nCmdShow )
{
    const DWORD Styles = WS_OVERLAPPEDWINDOW &~ WS_MAXIMIZEBOX;
    char szTitle[ 30 ];

    strcpy( szTitle, APP_NAME );
    strcat( szTitle, UNTITLED_STRING );

    appVars.hwndMainFrame =
        CreateWindow( appVars.szAppName,    // Our class name
                      szTitle,              // Window title
                      Styles,               // It's styles
                      CW_USEDEFAULT,        // No x position
                      CW_USEDEFAULT,        // And no y either
                      0, 65,                // Initial sizes
                      NULL,                 // No parent window
                      NULL,                 // And no menu
                      appVars.hInstance,    // App instance
                      NULL);                // Creation data

    ShowWindow( appVars.hwndMainFrame, nCmdShow );
    UpdateWindow( appVars.hwndMainFrame );
    return TRUE;

} // InitMainFrame


//
// DoMainLoop
//
// Main message loop
//
UINT DoMainLoop()
{
    MSG msg;
    HANDLE  ahObjects[1];       // Handles that need to be waited on
    const int cObjects = 1;     // Number of objects that we have

    // Message loop lasts until we get a WM_QUIT message
    // Upon which we shall return from the function

    while (TRUE) {
        if( (ahObjects[ 0 ] = GetGraphEventHandle()) == NULL ) {
            WaitMessage();
        } else {

            // Wait for any message or a graph notification

            DWORD Result = MsgWaitForMultipleObjects( cObjects,
                                                      ahObjects,
                                                      FALSE,
                                                      INFINITE,
                                                      QS_ALLINPUT);

            // Have we received an event notification

            if( Result != (WAIT_OBJECT_0 + cObjects) )
            {
                if( Result == WAIT_OBJECT_0 ) {
                    OnGraphNotify();
                }
                continue;
            }
        }

        // Read all of the messages in this next loop
        // removing each message as we read it

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                return msg.wParam;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

} // DoMainLoop


//
// WinMain
//
// Application entry point
//
int PASCAL WinMain( HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszCmdParam,
                    int nCmdShow )
{
    UINT nReturn;

    // Initialise COM and the application
    if ( InitApplication() == FALSE ) return 0;

    if( InitInstance( hInstance, hPrevInstance ) &&
        InitMainFrame( nCmdShow ) &&
        InitToolbar( hInstance, appVars.hwndMainFrame ) &&
        InitMedia( ) &&
        InitFileOpenDialog( appVars.hwndMainFrame ))
    {
        if( lpszCmdParam[0] != '\0' ) {
	    OpenMediaFile( appVars.hwndMainFrame, lpszCmdParam );
        }

        nReturn = DoMainLoop();

	// Stop the graph if we can
	if( CanStop() )
            OnMediaStop();

        // Release the filter graph
	DeleteContents();
    }

    UnInitApplication();
    return nReturn;

} // WinMain

