// frame.c - faithful port of ORCA-C's Frame.cc sample.
//
// Mike Westerfield, Byte Works 1989.  Original at
// tools/orca-c/C.Samples/Desktop.Samples/Frame.cc.
//
// The simplest possible Apple IIgs desktop app: Apple/File/Edit menu
// bar + TaskMaster event loop + About dialog.  File>Quit (or cmd-Q)
// exits.  The "About Frame" item in the Apple menu shows the original
// 4-line copyright dialog.
//
// Differences from the original:
//   - The watchdog at the bottom of the loop forces a clean exit so
//     the headless test (`demos/test.sh frame`) can verify $70 = $99.
//     In interactive use the watchdog is benign.

#include "iigs/toolbox.h"
#include "iigs/desktop.h"


#define apple_About 257
#define file_Quit   256

#define wInSpecial  25
#define wInMenuBar  3

#define norml       0
#define stop        1
#define note        2
#define caution     3

#define buttonItem  10
#define statText    136
#define itemDisable 0x8000


typedef struct {
    unsigned short  wmWhat;
    unsigned long   wmMessage;
    unsigned long   wmWhen;
    short           wmWhereV, wmWhereH;
    unsigned short  wmModifiers;
    unsigned long   wmTaskData;
    unsigned long   wmTaskMask;
    unsigned long   wmLastClickTick;
    unsigned long   wmClickCount;
    unsigned long   wmTaskData2;
    unsigned long   wmTaskData3;
    unsigned long   wmTaskData4;
} WmTaskRec;


typedef struct {
    short          itemID;
    short          itemRectV1, itemRectH1, itemRectV2, itemRectH2;
    unsigned short itemType;
    void          *itemDescr;
    short          itemValue;
    short          itemFlag;
    void          *itemColor;
} ItemTemplate;


typedef struct {
    short          atRectV1, atRectH1, atRectV2, atRectH2;
    short          atBtnHorz;
    short          atBeep0, atBeep1, atBeep2, atBeep3;
    void          *atSound;
    void          *atResv1;
    void          *atResv2;
    void          *atItemList[8];
} AlertTemplate;


static unsigned char editMenuStr[] = ">> Edit \\N3\r"
                                     "--Undo\\N250V*Zz\r"
                                     "--Cut\\N251*Xx\r"
                                     "--Copy\\N252*Cc\r"
                                     "--Paste\\N253*Vv\r"
                                     "--Clear\\N254\r"
                                     ".\r";

static unsigned char fileMenuStr[] = ">>  File \\N2\r"
                                     "--Close\\N255V\r"
                                     "--Quit\\N256*Qq\r"
                                     ".\r";

static unsigned char appleMenuStr[] = ">>@\\XN1\r"
                                      "--About Frame\\N257V\r"
                                      ".\r";

static unsigned char gAboutMsg[] =
    "\x3a" "Frame 1.0\r"
           "Copyright 1989\r"
           "Byte Works, Inc.\r\r"
           "By Mike Westerfield";

static WmTaskRec gEvent;
static volatile unsigned short gDone;


static void doAlert(unsigned short kind, void *msg) {
    static unsigned char okStr[] = "\x02OK";
    static ItemTemplate button = {
        1, 36, 15, 0, 0, buttonItem, okStr, 0, 0, (void *)0
    };
    static ItemTemplate message = {
        100, 5, 100, 90, 280, itemDisable | statText, (void *)0, 0, 0, (void *)0
    };
    static AlertTemplate alertRec = {
        50, 180, 107, 460,
        2,
        0x80, 0x80, 0x80, 0x80,
        (void *)0, (void *)0, (void *)0,
        { (void *)0, (void *)0, (void *)0, (void *)0,
          (void *)0, (void *)0, (void *)0, (void *)0 }
    };

    SetForeColor(0);
    SetBackColor(15);

    message.itemDescr      = msg;
    alertRec.atItemList[0] = (void *)&button;
    alertRec.atItemList[1] = (void *)&message;
    alertRec.atItemList[2] = (void *)0;

    switch (kind) {
        case norml:   (void)Alert(&alertRec, (void *)0);        break;
        case stop:    (void)StopAlert(&alertRec, (void *)0);    break;
        case note:    (void)NoteAlert(&alertRec, (void *)0);    break;
        case caution: (void)CautionAlert(&alertRec, (void *)0); break;
        default: break;
    }
}


static void menuAbout(void) {
    doAlert(note, gAboutMsg);
}


static void handleMenu(unsigned short menuNum) {
    switch (menuNum) {
        case apple_About: menuAbout(); break;
        case file_Quit:   gDone = 1;   break;
        default:          break;
    }
    HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16));
}


static void initMenus(void) {
    InsertMenu(NewMenu(editMenuStr),  0);
    InsertMenu(NewMenu(fileMenuStr),  0);
    InsertMenu(NewMenu(appleMenuStr), 0);
    FixAppleMenu(1);
    FixMenuBar();
    DrawMenuBar();
}


int main(void) {
    unsigned short userId = startdesk(640);
    (void)userId;

    paintDesktopBackdrop();      // white desktop (WM dither -> noise in
                                 // our 640 B/W palette; paint directly)
    initMenus();
    gEvent.wmTaskMask = 0x1FFFL;
    ShowCursor();

    gDone = 0;
    unsigned short watchdog = 0;
    do {
        unsigned short event = TaskMaster(0x076E, &gEvent);
        switch (event) {
            case wInSpecial:
            case wInMenuBar:
                handleMenu((unsigned short)gEvent.wmTaskData);
                break;
            default:
                break;
        }
        watchdog++;
    } while (!gDone && watchdog < 4000);

    *(volatile unsigned char *)0x70 = 0x99;
    return 0;
}
