/*  words.c
    words Application

    Copyright 1990 by William R. Ross

    12/26/89    start adding new "Fader" control
*/
 
#include <stdlib.h> /* for rand(), srand() */
#include <sys\types.h> /* for ftime() */
#include <sys\timeb.h> /* ditto */

#define NOMINMAX 
#include "windows.h"
#define WORDS_MAIN
#include "words.h"
#include "fader.h"

/* preface all functions w/FCN */
#define FCN
 
char *szAppName = "Words"; /* also class name for dialog */
char *szAbout = "About...";
char szTempBuf[150];
 
char *Adjectives[] = {
                     "timeless",
                     "skillful",
                     "blissful",
                     "powerful",
                     "fragrant",
                     "young",
                     "ancient",
                     "wanton",
                     "fervent",
                     "torrid",
                     "regretful",
                     "plaintive",
                     "soft",
                     "sweet",
                     "forgotten",
                     "unwanted",
                     "silent",
                     "willing",
                     "deliberate",
                     "serene",
                     "shrill",
                     "exotic",
                     "familiar",
                     "new",
                     "reluctant",
                     "languid",
                     "frozen",
                     "harsh",
                     "lone",
                     "desperate",
                     "soaring",
                     "sinister",
                     "gentle",
                     "tranquil",
                     "vicious",
                     "loving",
                     "grim",
                     "pitiless",
                     "savage",
                     "austere",
                     "stern",
                     "still",
                     "silent",
                     "dark"
                     };
 
#define NUMADJS sizeof(Adjectives) / sizeof (char *)
 
 
char *Nouns[] = {
                "leaders",
                "followers",
                "winds",
                "crystals",
                "brothers",
                "sisters",
                "mothers",
                "pioneers",
                "heroes",
                "icons",
                "idols",
                "children",
                "intentions",
                "goddesses",
                "artisans",
                "flowers",
                "wisdoms",
                "rivals",
                "opponents",
                "words",
                "symbols",
                "heresies",
                "visions",
                "songs",
                "fools",
                "demons",
                "patterns",
                "illusions",
                "warriors"
                 };
 
#define NUMNOUNS sizeof(Nouns) / sizeof (char *)
 
char *Verbs[] = {
                "balance",
                "sustain",
                "challenge",
                "arouse",
                "beguile",
                "tantalize",
                "seduce",
                "excite",
                "beckon",
                "shelter",
                "inspire",
                "annoy",
                "provoke",
                "torment",
                "welcome",
                "summon",
                "deprive",
                "ensnare",
                "entrap",
                "assert",
                "defend",
                "reveal",
                "conceal",
                "enrich",
                "improve",
                "demolish",
                "shield",
                "inform",
                "lure",
                "recall",
                "worship"
                };
 
#define NUMVERBS sizeof(Verbs) / sizeof (char *)
 
static HWND  hWnd;
static HANDLE hInst;
static int nLastControl;
 
#define NUMWORDS 50
#define NUMCTLS 5
#define ADJ 1
#define NOUN 2
#define VERB 3
 
static struct controls_tag {
        HWND hCtl;
        int nID;
        BOOL bDone;
        int  nType;
        int nNumWords;
        int nNumWordsDone;
        BOOL bWordsDone [NUMWORDS];
    } Controls [NUMCTLS];
 
 
BOOL bNounsDone [NUMNOUNS];
BOOL bVerbsDone [NUMVERBS];
BOOL bAdjsDone [NUMADJS];
int nNumNounsDone;
int nNumVerbsDone;
int nNumAdjsDone;

/* externs defined in KERNEL */
WORD far PASCAL _lwrite ();
WORD far PASCAL _lclose ();
 
/******************************************
* WordsInit
* function called when app loaded for the first time
*
*******************************************/
FCN BOOL WordsInit( hInstance )
HANDLE hInstance;
{
    PWNDCLASS   pClass;
 
    pClass = (PWNDCLASS)LocalAlloc( LPTR, sizeof(WNDCLASS) );

    /* this is the class for the main window */
    pClass->hCursor        = LoadCursor( NULL, IDC_ARROW );
    pClass->hIcon          = LoadIcon( hInstance, MAKEINTRESOURCE(HELLOICON) );
    pClass->lpszMenuName   = (LPSTR)NULL;
    pClass->lpszClassName  = (LPSTR)szAppName;
    pClass->hbrBackground  = (HBRUSH)GetStockObject( WHITE_BRUSH );
    pClass->hInstance      = hInstance;
    pClass->style          = CS_HREDRAW | CS_VREDRAW;
    pClass->lpfnWndProc    = WndProc;
 
    if (!RegisterClass( (LPWNDCLASS)pClass ) )
        /* Initialization failed.
         * Windows will automatically deallocate all allocated memory.
         */
        return FALSE;

    LocalFree( (HANDLE)pClass );
    if (!FaderInit (hInstance))
        return FALSE;
    else
        return TRUE;        /* Initialization succeeded */
} /* end of WordsInit */
 
/**********************************************
* main()
*
***********************************************/
FCN int PASCAL WinMain( hInstance, hPrevInstance, lpszCmdLine, cmdShow )
HANDLE hInstance, hPrevInstance;
LPSTR lpszCmdLine;
int cmdShow;
{
    MSG   msg;
    HMENU hMenu;
    RECT rect;
    OFSTRUCT Ofstruct;
 
    if (!hPrevInstance)
        {
        /* Call initialization procedure if this is the first instance */
        if (!WordsInit( hInstance ))
            {
            MessageBox(NULL, (LPSTR)"Cannot register window class",
                        (LPSTR)"Words", MB_OK);
            return FALSE;
            }
        }
 
    /* Save instance handle for DialogBox */
    hInst = hInstance;
 
    /* Bind callback function with module instance */
    lpprocAbout = MakeProcInstance( (FARPROC)About, hInstance );
 
    hWnd = CreateDialog (hInst, szAppName, 0, NULL);
    if (!hWnd)
        {
        MessageBox(NULL, (LPSTR) "CreateDialog returned NULL",
                   (LPSTR) "Words", MB_OK);
        return FALSE;
        }
    ShowWindow (hWnd, cmdShow);
 
    /* Insert "About..." into system menu */
    hMenu = GetSystemMenu(hWnd, FALSE);
    ChangeMenu(hMenu, 0, NULL, 999, MF_APPEND | MF_SEPARATOR);
    ChangeMenu(hMenu, 0, (LPSTR)szAbout, IDSABOUT, MF_APPEND | MF_STRING);
 
    /* Polling messages from event queue */
    while (GetMessage((LPMSG)&msg, NULL, 0, 0))
        {
        TranslateMessage((LPMSG)&msg);
        DispatchMessage((LPMSG)&msg);
        } /* while */
 
    return (int)msg.wParam;
} /* end of WinMain */
 

/***************************************************
* WndProc ()
* primary window procedure for app
*
***************************************************/
FCN long FAR PASCAL WndProc( hWnd, message, wParam, lParam )
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
    HWND hCtl;
    WORD wResult;
    int i;
    static BOOL bFirst = TRUE;
    static BOOL bSecond = FALSE;
    static int nNext = 0;
 
    switch (message)
    {
    case WM_INITDIALOG:
    case WM_CREATE:
        if (!(wResult = SetTimer (hWnd, 1, 3200, NULL)))
            {
            MessageBox (hWnd, "Not enough timers.", (LPSTR)szAppName,
                        MB_OK | MB_ICONEXCLAMATION);
            exit (0);
            }
        InitControls (hWnd);
        break;
 
    case WM_TIMER:
        if (bFirst)
            {
            bFirst = FALSE;
            KillTimer (hWnd, 1);
            SendDlgItemMessage (hWnd, ADJ1, (WORD)WM_FADER,
            (WORD)NULL, (long) (LPSTR) NULL);
            SendDlgItemMessage (hWnd, NOUN1, (WORD)WM_FADER,
            (WORD)NULL, (long) (LPSTR) NULL);
            SendDlgItemMessage (hWnd, VERB1, (WORD)WM_FADER,
            (WORD)NULL, (long) (LPSTR) NULL);
            SendDlgItemMessage (hWnd, ADJ2, (WORD)WM_FADER,
            (WORD)NULL, (long) (LPSTR) NULL);
            SendDlgItemMessage (hWnd, NOUN2, (WORD)WM_FADER,
            (WORD)NULL, (long) (LPSTR) NULL);
            SetTimer (hWnd, 1, 1700, NULL);
            bSecond = TRUE;
            break;
            }
 
        if (bSecond)
            {
            UpdateControl (hWnd, &Controls[nNext]);
            nNext++;
            if (nNext == NUMCTLS)
                {
                bSecond = FALSE;
                KillTimer (hWnd, 1);
                SetTimer (hWnd, 1, 3200, NULL);
                }
            break;
            }

        i = SelectControl ();
        UpdateControl (hWnd, &Controls[i]);
        break;
 
 
    case WM_SYSCOMMAND:
        switch (wParam)
        {
        case IDSABOUT:
            DialogBox( hInst, MAKEINTRESOURCE(ABOUTBOX), hWnd, lpprocAbout );
            break;
 
        default:
            return DefWindowProc( hWnd, message, wParam, lParam );
        }
        break;
 
    case WM_DESTROY:
        KillTimer (hWnd, NULL);
        PostQuitMessage( 0 );
        break;
 
    default:
        return DefWindowProc( hWnd, message, wParam, lParam );
        break;
    }
    return(0L);
} /* end of WndProc */


/***************************************************
* About ()
* window procedure for About dialog
*
***************************************************/
FCN BOOL FAR PASCAL About( hDlg, message, wParam, lParam )
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
    BOOL bDisplayed;
    WORD wResult;

    if (message == WM_COMMAND)
        {
        KillTimer (hDlg, 1);
        EndDialog( hDlg, TRUE );
        return TRUE;
        }
    else if (message == WM_INITDIALOG)
        {
        bDisplayed = TRUE;

        if (!(wResult = SetTimer (hDlg, 1, 1000, NULL)))
            MessageBox (hDlg, "About: Not enough timers.", (LPSTR)szAppName,
                        MB_OK | MB_ICONEXCLAMATION);

        return TRUE;
        }
    else if (message == WM_TIMER)
        {
        if (bDisplayed)
            {
            KillTimer (hDlg, 1);
            SetTimer (hDlg, 1, 1000, NULL);
            SendDlgItemMessage (hDlg, ID_TITLE, (WORD)WM_FADER,
                        (WORD)NULL, (long) NULL);
            bDisplayed = FALSE;
            }
        else
            {
            KillTimer (hDlg, 1);
            SetTimer (hDlg, 1, 3000, NULL);
            SendDlgItemMessage (hDlg, ID_TITLE, (WORD)WM_FADER,
                        (WORD)NULL, (long) (LPSTR) "Words by Ross");
            bDisplayed = TRUE;
            } /* else */
        return TRUE;
        } /* if wm_timer */
    else return FALSE;
} /* end of About */
 
/***************************************************
* InitControls ()
* Initialization for the Fader controls
*
***************************************************/
FCN void InitControls (HWND hDlg)
{
    int i,j;
    struct timeb timebuffer;
 
    /* init random number generator */
    ftime (&timebuffer);
    srand ((unsigned) timebuffer.millitm);
 
    /* get handles for the controls and store */
    Controls[0].hCtl = GetDlgItem ( hDlg, ADJ1 );
    Controls[0].nID = ADJ1;
    Controls[0].bDone = FALSE;
    Controls[0].nType = ADJ;
    Controls[0].nNumWordsDone = 0;
    Controls[0].nNumWords = NUMADJS;
 
    Controls[1].hCtl = GetDlgItem ( hDlg, NOUN1 );
    Controls[1].nID = NOUN1;
    Controls[1].bDone = FALSE;
    Controls[1].nType = NOUN;
    Controls[1].nNumWordsDone = 0;
    Controls[1].nNumWords = NUMNOUNS;
 
    Controls[2].hCtl = GetDlgItem (hDlg, VERB1 );
    Controls[2].nID = VERB1;
    Controls[2].bDone = FALSE;
    Controls[2].nType = VERB;
    Controls[2].nNumWordsDone = 0;
    Controls[2].nNumWords = NUMVERBS;
 
    Controls[3].hCtl = GetDlgItem (hDlg, ADJ2 );
    Controls[3].nID = ADJ2;
    Controls[3].bDone = FALSE;
    Controls[3].nType = ADJ;
    Controls[3].nNumWordsDone = 0;
    Controls[3].nNumWords = NUMADJS;
 
    Controls[4].hCtl = GetDlgItem (hDlg, NOUN2 );
    Controls[4].nID = NOUN2;
    Controls[4].bDone = FALSE;
    Controls[4].nType = NOUN;
    Controls[4].nNumWordsDone = 0;
    Controls[4].nNumWords = NUMNOUNS;
 
    for (i = 0; i < NUMCTLS; i++)
        {
        for (j = 0; j < Controls[i].nNumWords; j++)
            Controls[i].bWordsDone[j] = FALSE;
 
        UpdateControl (hDlg, &Controls[i]);
        } /* for */
 
        nLastControl = -1;

    for (i = 0; i < NUMVERBS; i++)
        bVerbsDone [i] = FALSE;

    for (i = 0; i < NUMNOUNS; i++)
        bNounsDone [i] = FALSE;

    for (i = 0; i < NUMADJS; i++)
        bAdjsDone [i] = FALSE;

    nNumNounsDone = 0;
    nNumAdjsDone = 0;
    nNumVerbsDone = 0;

 
} /* end of InitControls */
 
 
/***************************************************
* UpdateControl ()
* selects a word to display in a control
*
***************************************************/
FCN void UpdateControl (HWND hDlg, struct controls_tag *Control)
{
    int i, j;
 
    i = rand() % Control->nNumWords;
 
    switch (Control->nType)
        {
         case ADJ:
            if (nNumAdjsDone == NUMADJS)
                {
                nNumAdjsDone = 0;
                for (j = 0; j < NUMADJS; j++)
                    bAdjsDone[j] = FALSE;
                } /* if */

            while (bAdjsDone [i])
                {
                i++;
                if (i >= NUMADJS)
                    i = 0;
                } /* while */

            bAdjsDone[i] = TRUE;
            nNumAdjsDone++;
            SendDlgItemMessage (hDlg, Control->nID, (WORD)WM_FADER,
                        (WORD)NULL, (long) (LPSTR) Adjectives[i]);
            break;
 
        case NOUN:
            if (nNumNounsDone == NUMNOUNS)
                {
                nNumNounsDone = 0;
                for (j = 0; j < NUMNOUNS; j++)
                    bNounsDone[j] = FALSE;
                } /* if */

            while (bNounsDone [i])
                {
                i++;
                if (i >= NUMNOUNS)
                    i = 0;
                } /* while */

            bNounsDone[i] = TRUE;
            nNumNounsDone++;
            SendDlgItemMessage (hDlg, Control->nID, (WORD)WM_FADER,
                        (WORD)NULL, (long) (LPSTR) Nouns[i]);
            break;
 
        case VERB:
            if (nNumVerbsDone == NUMVERBS)
                {
                nNumVerbsDone = 0;
                for (j = 0; j < NUMVERBS; j++)
                    bVerbsDone[j] = FALSE;
                } /* if */

            while (bVerbsDone [i])
                {
                i++;
                if (i >= NUMVERBS)
                    i = 0;
                } /* while */

            bVerbsDone[i] = TRUE;
            nNumVerbsDone++;
            SendDlgItemMessage (hDlg, Control->nID, (WORD)WM_FADER,
                        (WORD)NULL, (long) (LPSTR) Verbs[i]);
            break;
 
        default:
            /* error */
            break;
 
        } /* switch */
 
} /* end of UpdateControls */
 
/***************************************************
* SelectControl ()
* selects a control to update
*
***************************************************/
FCN int SelectControl (void)
{
    int i;
 
    if (Controls[0].bDone &&
        Controls[1].bDone &&
        Controls[2].bDone &&
        Controls[3].bDone &&
        Controls[4].bDone)
        {
        Controls[0].bDone = FALSE;
        Controls[1].bDone = FALSE;
        Controls[2].bDone = FALSE;
        Controls[3].bDone = FALSE;
        Controls[4].bDone = FALSE;
        } /* if */
 
 
    i = rand() % NUMCTLS;
 
    while  ((Controls[i].bDone) || (i == nLastControl))
        {
        i++;
        if (i >= NUMCTLS)
            i = 0;
        } /* while */
 
    Controls[i].bDone = TRUE;
    nLastControl = i;
 
    return i;
 
} /* end of SelectControl */
