#include "animator.h"

/* btw: WM_NCCREATE and WM_CREATE return BOOLs. 
   Any message that needs *DefWndProc should call it
   explicitly in its function. */

BOOL NEAR PASCAL Frame_OnCreate (HWND,LPCREATESTRUCT);
VOID NEAR PASCAL Frame_OnInitMenu (HWND,HMENU);
VOID NEAR PASCAL Frame_OnCommand (HWND,UINT,HWND,UINT);
VOID NEAR PASCAL Frame_OnSize (HWND,UINT,short,short);
LONG NEAR PASCAL Frame_OnDestroy (HWND);
VOID NEAR PASCAL Frame_OnClose (HWND);




//////////////////////////////////////////////////////////////////////////
// FrameProc() - good example of how Message Crackers may be used.
// Intercepts messages, handles the ones we hande, and DefWndProc()'s
// the rest.
//////////////////////////////////////////////////////////////////////////

LRESULT _export CALLBACK FrameProc (WNDPROC_PARAMS)
{
    switch (uMsg) 
    {
        HANDLE_MSG (hWnd, WM_CREATE,          Frame_OnCreate); 
        HANDLE_MSG (hWnd, WM_INITMENU,        Frame_OnInitMenu);
        HANDLE_MSG (hWnd, WM_COMMAND,         Frame_OnCommand);
        HANDLE_MSG (hWnd, WM_SIZE,            Frame_OnSize);
        HANDLE_MSG (hWnd, WM_CLOSE,           Frame_OnClose);
        HANDLE_MSG (hWnd, WM_DESTROY,         Frame_OnDestroy);
    }

    return (LRESULT)DefFrameProc(hWnd, _hwndClient, uMsg, wParam, lParam);
}



//////////////////////////////////////////////////////////////////////////
// BroadcastProc - This is simply the enumeration function for all of 
// the child MDI windows.  It broadcasts a message to all alive MDI
// children.  In our case, we just use it to broadcast the WM_CLOSE
// message to everybody when the user wants to terminate session.
//////////////////////////////////////////////////////////////////////////

BOOL _export CALLBACK BroadcastProc(HWND  hwnd,
                  LONG  lParam)
{
    if (GetWindow(hwnd, GW_OWNER))
    {
        return TRUE;
    }

    if (lParam == WM_CLOSE)
    {
        if (SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0L))
        {
            MDI_Destroy (_hwndClient, hwnd);
        }
        else
        {
            return FALSE;
        }
    }
    else
    {
        SendMessage(hwnd, (UINT)LOWORD(lParam), (WPARAM)0, 0L);
    }

    return TRUE;
}
    


//////////////////////////////////////////////////////////////////////////
// Frame_OnCreate() - Restores position if there was anything in the
// WIN.INI, then creates the client and status children.
//////////////////////////////////////////////////////////////////////////

BOOL NEAR PASCAL Frame_OnCreate (HWND hwnd, CREATESTRUCT FAR* lpCS)
{
    CLIENTCREATESTRUCT  clicr;

    clicr.hWindowMenu = _hmenuChildWindow;
    clicr.idFirstChild = IDM_FIRSTCHILD;

    _hwndClient = CreateWindow("MDICLIENT", NULL,
                WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
                0, 0, 0, 0, hwnd, ID_CLIENT, _hInst, (LPSTR)&clicr);

    if (!IsWindow(_hwndClient)) return FALSE;
    
    // we find out the y-extent of the status bar based on the
    // height of the ansi-variable font.

    _nStatBarDY = GetANSITextHeight() + 7; // the '7' is the dead space

    _hwndStatus = CreateWindow (_szStatBarClass,NULL,
                           WS_CHILD | WS_VISIBLE,
                           0,0,0,0,
                           hwnd,ID_STATBAR, _hInst, NULL);

    if (!IsWindow(_hwndStatus)) 
    {
        return FALSE;
    }
    
    if (!SetTimer (hwnd, ID_TIMER, MINTIME, _lpfnTimer))
    {
        MESSAGE (IDS_TimerFail);
        return FALSE;
    }

    // Set up the Notify callback so we know when a task starts or dies...

    if (!NotifyRegister ((HTASK)GetWindowTask(hwnd), 
        (LPFNNOTIFYCALLBACK)_lpfnNotify, NF_NORMAL))
    {
        MESSAGE (IDS_NotifyFail);
        return FALSE;
    }
    
    return TRUE;
}



//////////////////////////////////////////////////////////////////////////
// Frame_OnInitMenu() - Grays out menu items if needed, depending
// on if something is currently animating, etc.
//////////////////////////////////////////////////////////////////////////

VOID NEAR PASCAL Frame_OnInitMenu(HWND hwnd, HMENU hMenu)
{   
    HWND hwndChild = MDI_GetActive (_hwndClient);            

    if (IsWindow(hwndChild)) 
    {
        short    sChild = WINDOWNUM(hwndChild);
        BOOL     b;
        
        b = (BOOL)(ISANIMATING(sChild) && SZEXELINK(sChild)[0] && TIMEINT(sChild));
        EnableMenuItem (hMenu, IDM_STOP,        b ? MF_ENABLED : MF_GRAYED);
        EnableMenuItem (hMenu, IDM_GO,          b ? MF_GRAYED : MF_ENABLED);
        EnableMenuItem (hMenu, IDM_SETTINGS,    b ? MF_GRAYED : MF_ENABLED);
        EnableMenuItem (hMenu, IDM_INSERTICON,  b ? MF_GRAYED : MF_ENABLED);
        EnableMenuItem (hMenu, IDM_ADDICON,     b ? MF_GRAYED : MF_ENABLED);
        EnableMenuItem (hMenu, IDM_DELETEICON,  b ? MF_GRAYED : MF_ENABLED);
    }

    DefFrameProc(hwnd, _hwndClient, WM_INITMENU, (WPARAM)hMenu, 0L);
}



//////////////////////////////////////////////////////////////////////////
// Frame_OnCommand() - This is what handles file | new and file | open,
// task exit/entry notification, and other things that logically need
// to be handles in the Frame proc.
//////////////////////////////////////////////////////////////////////////

VOID NEAR PASCAL Frame_OnCommand (HWND hwnd, UINT uMsg, HWND hChild, UINT uExtra) 
{
    short               sChild;
    MDICREATESTRUCT     mdicr;
    char                szBuff[32];
    char                szFileName [MAX_FILE_SIZE];
    HWND                hwndChild;

    switch (uMsg) 
    {
        case IDM_ABOUT:
        {
            DialogBox (_hInst, ABOUT, hwnd, _lpfnAbout);
            break;
        }
        case IDM_NEW:
        {
            for (sChild = 0 ;
                 _lPageFlags & (1 << sChild) ;
                 ++sChild) ;

            if (sChild >= MAXANIMATIONS)
            {
                MESSAGE (IDS_MaxAnimations);
                break;
            }

            _lPageFlags |= 1 << sChild;

            wsprintf((LPSTR)szBuff,(LPSTR)"%s%d",
                (LPSTR)_szUntitled, sChild+1);

            mdicr.szClass   = (LPSTR)_szChildClass;
            mdicr.szTitle   = (LPSTR)szBuff;
            mdicr.hOwner    = _hInst;
            mdicr.x         = CW_USEDEFAULT;
            mdicr.y         = CW_USEDEFAULT;
            mdicr.cx        = CW_USEDEFAULT;
            mdicr.cy        = CW_USEDEFAULT;
            mdicr.style     = 0;
            mdicr.lParam    = (LPARAM)sChild;

            MDI_Create (_hwndClient, &mdicr);

            break;
        }        

        case IDM_OPEN:
            szFileName[0] = '\0';
            OpenIconsInFile(szFileName) ;
            // no break, because we need to refresh animations anyways...
        case IDN_NEWTASK:   
            RefreshAnimations ();
            break;

        case IDN_EXITTASK:
        {
            short i;

            for (i=0 ; i<MAXANIMATIONS ; i++)
            {
                if (IsWindow (HWNDANIM(i)) && !IsWindow(HWNDTARGET(i)))
                {
                    SET_EXELOADED (i, FALSE);
                    SET_HWNDTARGET (i, NULL);
                    SET_HPREVICON (i, NULL);
                }
            }

            break;
        }

        case IDM_CLOSE:
        {
            if (hwndChild = MDI_GetActive (_hwndClient))
            {
                FORWARD_WM_CLOSE (hwndChild, SendMessage); 
            }
            break;
        }
        case IDM_CLOSEALL:
        {
            if (_lPageFlags)
            {
                EnumChildWindows(_hwndClient,(FARPROC)_lpfnBroadcast, 
                    (LONG)WM_CLOSE);
            }
            break;
        }
        case IDM_EXIT:
        {
            SendMessage (hwnd, WM_CLOSE, 0, 0L);
            break;
        }
        case WM_MDITILE:
        case WM_MDICASCADE:
        case WM_MDIICONARRANGE:
        {
            SendMessage(_hwndClient, uMsg, 0, 0L);
            break;
        }
        default:
        {
        
            if (IsWindow (hwndChild = MDI_GetActive (_hwndClient)))
            {
                SendMessage(hwndChild, WM_COMMAND,
                    uMsg, MAKELPARAM(hChild,uExtra));
            }
            
            DefFrameProc(hwnd, _hwndClient, WM_COMMAND, 
                (WPARAM) uMsg, MAKELPARAM (hChild, uExtra)); 
        
            break;
        }
    }
}

        

//////////////////////////////////////////////////////////////////////////
// Frame_OnSize() - Changes the position of the client and status
// children when the frame changes.
//////////////////////////////////////////////////////////////////////////

VOID NEAR PASCAL Frame_OnSize (HWND hwnd, UINT wSizeType, short cx, short cy)            
{
    MoveWindow (_hwndClient, 0, 0, cx, cy-_nStatBarDY, TRUE);
    MoveWindow (_hwndStatus, 0, cy-_nStatBarDY, cx, _nStatBarDY, TRUE);
}



//////////////////////////////////////////////////////////////////////////
// Frame_OnClose() - Does the queryendsession enumeration to the
// child windows. If anyone does not agree, close doesn't really
// close.
//////////////////////////////////////////////////////////////////////////

VOID NEAR PASCAL Frame_OnClose (HWND hwnd)
{
    if (_lPageFlags)
    {
        if (!EnumChildWindows(_hwndClient,(FARPROC)_lpfnBroadcast, 
            (LONG)WM_CLOSE))
        {
            return;
        }
    }

    DestroyWindow (hwnd);
}



//////////////////////////////////////////////////////////////////////////
// Frame_OnDestroy() - Handles the shutdown of the window.  Here,
// the position of the window is recorded to the WIN.INI, the timer
// is killed, the Register callback is unregistered, and the menus
// are dealt with.
//////////////////////////////////////////////////////////////////////////

LONG NEAR PASCAL Frame_OnDestroy (HWND hwnd)
{
    RecordPosition (hwnd);      
    KillTimer (hwnd,ID_TIMER);
    NotifyUnRegister (NULL);
    SetMenu(hwnd,NULL);                  
    DestroyMenu(_hmenuMain);
    DestroyMenu(_hmenuChild);
    PostQuitMessage(0);
    return 0L;
}




//////////////////////////////////////////////////////////////////////////
// RefreshAnimations() - This is what is called in response to a change
// in the task list.  When toolhelp.dll notifies us of an NFW_STARTTASK
// and when a script is opened, this updates our list of what is 
// actually loaded in the respects of the list.
//////////////////////////////////////////////////////////////////////////

VOID WINAPI RefreshAnimations (VOID)
{
    char    szModFileName[MAX_FILE_SIZE];
    HWND    hwndNext;
    short   i;

    for (i=0 ; i<MAXANIMATIONS ; i++)
    {
        if (!IsWindow(HWNDANIM(i))) continue;
        if (IsWindow(HWNDTARGET(i))) continue;

        for (hwndNext = GetWindow (_hwndFrame,GW_HWNDFIRST) ;
             hwndNext ; 
             hwndNext = GetWindow (hwndNext,GW_HWNDNEXT))
        {
            GetModuleFileName (GetWindowInstance(hwndNext), 
                (LPSTR)szModFileName,sizeof (szModFileName));

            if (lstrcmp((LPSTR)szModFileName,(LPSTR)SZEXELINK(i)) == 0)
            {
                SET_EXELOADED (i, TRUE);
                SET_HWNDTARGET (i, hwndNext);
                SET_HPREVICON (i, GetClassWord(hwndNext,GCW_HICON));
                if (AUTOANIMATE(i))
                {
                        SET_ISANIMATING (i, TRUE);
                }
            }
        }
    }
}


