/*  Men˙.c V1.0
    ***********

    Author:     Teijo Kinnunen
            Oksantie 19
            FIN-86300  OULAINEN
            FINLAND

    Date:       30.05.1994

    Status:     Copyright 1994 Teijo Kinnunen. All rights reserved.
            Freely Distributable, along with the rest of the
            Men˙ package.

            Modified versions of this file and/or the executable
            program may not be distributed! (Contact the author
            if you have made improvements that you would like to
            share with other users, YOU may NOT release altered prog!.)
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

ULONG LOGOHEIGHT;

#define C_TITLE 1
#define C_ITEM 2
#define C_HDR 3
#define C_SECCOL 4
#define C_ENDM 5
#define C_MENU 6
#define C_SUBM 7
#define C_ITEMQ 8
#define C_WITEM 9
#define C_WMENU 10
#define C_WITEMQ 11
#define C_ISSUE 12
#define C_PICTURE 13
#define C_PICHEIGHT 14
#define C_PICWIDTH 15
#define C_PICDEPTH 16

struct Image logo;

WORD    frame_wht[] = { 312,0,0,0,0,13,1,12,1,1 },
    frame_blk[] = { 1,13,312,13,312,0,311,1,311,12 };
WORD    wframe_wht[] = { 625,0,0,0,0,13,1,12,1,1 },
    wframe_blk[] = { 1,13,625,13,625,0,624,1,624,12 };
WORD    mframe_wht[] = { 287,0,0,0,0,13,1,12,1,1 },
    mframe_blk[] = { 1,13,287,13,287,0,286,1,286,12 };
WORD    qframe_wht[] = { 49,0,0,0,0,13,1,12,1,1 },
    qframe_blk[] = { 1,13,49,13,49,0,48,1,48,12 };

struct Border brd[] = {
    { 0,0,2,0,JAM1,5,frame_wht,&brd[1] },
    { 0,0,1,0,JAM1,5,frame_blk,0L },
    { 0,0,2,0,JAM1,5,wframe_wht,&brd[3] },
    { 0,0,1,0,JAM1,5,wframe_blk,0L },
    { 0,0,2,0,JAM1,5,qframe_wht,&brd[5] },
    { 0,0,1,0,JAM1,5,qframe_blk,0L },
    { 0,0,2,0,JAM1,5,mframe_wht,&brd[7] },
    { 0,0,1,0,JAM1,5,mframe_blk,0L }
};

struct Border hibrd[] = {   // inversed borders
    { 0,0,1,0,JAM1,5,frame_wht,&hibrd[1] },
    { 0,0,2,0,JAM1,5,frame_blk,0L },
    { 0,0,1,0,JAM1,5,wframe_wht,&hibrd[3] },
    { 0,0,2,0,JAM1,5,wframe_blk,0L },
    { 0,0,1,0,JAM1,5,qframe_wht,&hibrd[5] },
    { 0,0,2,0,JAM1,5,qframe_blk,0L },
    { 0,0,1,0,JAM1,5,mframe_wht,&hibrd[7] },
    { 0,0,2,0,JAM1,5,mframe_blk,0L }
};

struct TextAttr t80 = { "topaz.font",8,0,0 };

struct IntuiText t[] = {
{ 1,0,JAM2,98-25,3,&t80,"« PARENT MENU",0 },
{ 1,0,JAM2,102-25,3,&t80,"«« MAIN MENU",0 },
{ 2,0,JAM2,4,3,&t80,"»",0 },
{ 1,0,JAM2,0,0,&t80,0,&t[4] },
{ 2,0,JAM1,-2,-1,&t80,0,0 },
{ 1,0,JAM2,550,3,NULL,0 },  // Issue
{ 1,0,JAM1,9,3,&t80,"Quit",0 }
};

struct Gadget g[] = {
{ &g[1],10,175,288,14,GFLG_GADGHIMAGE|GFLG_DISABLED,GACT_RELVERIFY,GTYP_BOOLGADGET,
  &brd[6],&hibrd[6],&t[0],0,0,999,0L },
{ &g[2],298,175,288,14,GFLG_GADGHIMAGE|GFLG_DISABLED,GACT_RELVERIFY,GTYP_BOOLGADGET,
  &brd[6],&hibrd[6],&t[1],0,0,998,0L },
{ NULL,298+288,175,50,14,GFLG_GADGHIMAGE,GACT_RELVERIFY,GTYP_BOOLGADGET,
  &brd[4],&hibrd[4],&t[6],0,0,997,0L }
};

UWORD scrpens[] = { (UWORD)~0 };

struct TagItem scrtags[] = {
    { SA_Pens,(ULONG)scrpens },
    { SA_PubName,(ULONG)"Men˙_Screen" },
    { SA_PubSig,0 },
    { TAG_DONE }
};

struct ExtNewScreen ns = {
    0,0,640,STDSCREENHEIGHT,2,0,1,HIRES|SPRITES,CUSTOMSCREEN|NS_EXTENDED,
    &t80,"Men˙ V1.0 Copyright 1994 Teijo Kinnunen",NULL,NULL,scrtags
};

struct NewWindow nw = {
    0,0,640,200,0xFF,0xFF,IDCMP_GADGETUP,
    WFLG_BACKDROP|WFLG_BORDERLESS|WFLG_SMART_REFRESH|WFLG_ACTIVATE|WFLG_NOCAREREFRESH|WFLG_RMBTRAP,
    &g[0],0,0L,0L,0L,
    0,0,0,0,CUSTOMSCREEN
};

long dispx = 10;

#define MAX_LINES 1000

struct Remember *gadgs;
long lines,menutop,currmenu,topmostitem,currpar,menubot;
UWORD parents[15],issuedsp = 0;
BPTR out;
struct Window *w;
struct Screen *s;
char *line[MAX_LINES],*verstag = "$VER: Men˙ 1.0 (30.05.94)";
void HandleMenu(void),DspMenu(void),UseMenu(LONG);
BOOL HandleGadget(UWORD);
BYTE pubscrsig = -1;
APTR picturedata;
LONG picturelen;

LONG GetCmd(char *);
char *GetArg(char *);

void msg(char *msg)
{
    Write(out,msg,strlen(msg));
}

ULONG asc_to_long(char *num)
{
    ULONG result = 0;
    while(*num >= '0' && *num <= '9') {
        result *= 10;
        result += *num++ - '0';
    }
    return(result);
}

BOOL ReadFile(char *name)
{
    char temp[260];
    FILE *fp;
    BOOL err = TRUE;
    fp = fopen(name,"r");
    if(!fp) {
        msg("Can't open script.\n");
        goto xrd0;
    }
    while(fgets(temp,256,fp)) {
        if(lines > MAX_LINES) {
            lines = MAX_LINES;
            msg("Line buffer overflow!\n");
            goto xrd1;
        }
        if(!(line[lines] = (char *)malloc(strlen(temp)+2))) {
            msg("Out of memory!\n");
            goto xrd1;
        }
        if(strlen(temp)) temp[strlen(temp) - 1] = 0;
        strcpy(line[lines++],temp);
    }
    err = FALSE;
xrd1:   fclose(fp);
xrd0:   return(err);
}

void main(int argc,char **argv)
{
    out = Output();
    pubscrsig = AllocSignal(-1);
    if(pubscrsig == -1) {
        msg("No signal!\n");
        goto done;
    }
    scrtags[2].ti_Data = (ULONG)pubscrsig;
    if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))) {
        msg("No intuition.library!\n");
        goto done;
    }
    if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) {
        msg("No graphics.library!\n");
        goto done;
    }
    if(argc < 2 || ReadFile(argv[1])) goto done;
    /* check if a picture descriptor exists */
    if(lines >= 4) {
        char *widstr,*heistr,*namestr,*depstr;
        ULONG wid,hei,dep;
        if(GetCmd(line[0]) == C_PICTURE && GetCmd(line[1]) == C_PICWIDTH &&
            GetCmd(line[2]) == C_PICHEIGHT && GetCmd(line[3]) == C_PICDEPTH &&
            (widstr = GetArg(line[1])) && (heistr = GetArg(line[2])) &&
            (namestr = GetArg(line[0])) && (depstr = GetArg(line[3]))) {
            FILE *picf;
            wid = asc_to_long(widstr);
            hei = asc_to_long(heistr);
            dep = asc_to_long(depstr);
            if(wid && hei && (picf = fopen(namestr,"r"))) {
                LONG len;
                fseek(picf,0,SEEK_END);
                len = ftell(picf);
                rewind(picf);
                if(picturedata = AllocMem(picturelen = len,MEMF_PUBLIC|MEMF_CHIP)) {
                    if(fread(picturedata,picturelen,1,picf) != 1) {
                        FreeMem(picturedata,picturelen);
                        picturedata = 0;
                    } else {
                        UBYTE planep = 0;
                        logo.ImageData = picturedata;
                        logo.Width = wid;
                        LOGOHEIGHT = logo.Height = hei;
                        logo.Depth = dep;
                        if(dep > 2) ns.Depth = dep;
                        while(dep--) {
                            planep <<= 1;
                            planep |= 1;
                        }
                        logo.PlanePick = planep;
                    }
                }
                fclose(picf);
            }
        }
    }
    if(!(s = OpenScreen((struct NewScreen *)&ns))) {
        msg("Can't open screen.\n");
        goto done;
    }
    if(IntuitionBase->LibNode.lib_Version >= 36) PubScreenStatus(s,0);
    nw.Screen = s;
    g[0].TopEdge += s->BarHeight;
    g[1].TopEdge += s->BarHeight;
    g[2].TopEdge += s->BarHeight;
    if(!(w = OpenWindow(&nw))) {
        msg("Can't open window.\n");
        goto done;
    }
    if(picturedata) DrawImage(w->RPort,&logo,0,s->BarHeight + 2);
    HandleMenu();
done:   if(w) CloseWindow(w);
    if(s) {
        if(IntuitionBase->LibNode.lib_Version >= 36) {
            while(!CloseScreen(s)) Wait(1<<pubscrsig);
        } else CloseScreen(s);
    }
    if(GfxBase) CloseLibrary((struct Library *)GfxBase);
    if(gadgs) FreeRemember(&gadgs,TRUE);
    if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
    if(picturedata) FreeMem(picturedata,picturelen);
    if(pubscrsig != -1) FreeSignal(pubscrsig);
}

void HandleMenu()
{
    register struct IntuiMessage *msg;
    register ULONG class;
    register struct Gadget *gadp;
    DspMenu();
    for(;;) {
        WaitPort(w->UserPort);
        while(msg = (struct IntuiMessage *)GetMsg(w->UserPort)) {
            class = msg->Class;
            gadp = (struct Gadget *)msg->IAddress;
            ReplyMsg((struct Message *)msg);
        }
        if(class == IDCMP_GADGETUP) {
            if(gadp->GadgetID < 500) {
                if(HandleGadget(gadp->GadgetID)) return;
            } else if(gadp->GadgetID == 998) {
                currpar = 0;
                UseMenu(0);
            } else if(gadp->GadgetID == 999) {
                if(currpar) UseMenu(parents[--currpar]);
            } else if(gadp->GadgetID == 997) return;
        }
    }
}

LONG GetCmd(char *ln)
{
    static char *cmdtbl[] = { "title","item","hdr","seccol","endm","menu","subm","itemq","witem",
        "wmenu","witemq","issue","picture","picheight","picwidth","picdepth",0 };
    register LONG cnt = 1;
    char cmdbuff[260];
    register char *to = cmdbuff,**ctp;
    while(*ln != ' ' && *ln != '\t' && *ln) *to++ = *ln++;
    *to = 0;
    ctp = cmdtbl;
    while(*ctp)
        if(!stricmp(*ctp,cmdbuff)) return(cnt);
        else {
            ctp++;
            cnt++;
        }
    return(0);
}

char *GetArg(char *ln)
{
    while(*ln != ' ' && *ln != '\t' && *ln) ln++;
    if(*ln == ' ' || *ln == '\t') ln++;
    if(!(*ln)) return 0;
    else return(ln);
}

void CreateGadg(UWORD left,UWORD top,char *text,ULONG line,BOOL menu,BOOL wide)
{
    register long txtlen = strlen(text);
    register struct Gadget *gad = (struct Gadget *)AllocRemember(&gadgs,sizeof
        (struct Gadget),MEMF_PUBLIC|MEMF_CLEAR);
    register struct IntuiText *txt = (struct IntuiText *)AllocRemember(&gadgs,
        sizeof(struct IntuiText),MEMF_PUBLIC|MEMF_CLEAR);
    if(!gad || !txt) return;
    gad->LeftEdge = left;
    gad->TopEdge = top;
    gad->Width = wide ? 626 : 313;
    gad->Height = 14;
    gad->Flags = GADGHIMAGE;
    gad->Activation = RELVERIFY;
    gad->GadgetRender = (wide ? &brd[2] : &brd[0]);
    gad->SelectRender = (wide ? &hibrd[2] : &hibrd[0]);
    gad->GadgetType = BOOLGADGET;
    gad->GadgetText = txt;
    gad->GadgetID = line;
    txt->FrontPen = 1;
    txt->DrawMode = JAM2;
    txt->TopEdge = 3;
    txt->LeftEdge = (wide ? 310 : 150) - (txtlen * 4);
    txt->ITextFont = &t80;
    txt->IText = text;
    if(menu) txt->NextText = &t[2];
    AddGadget(w,gad,-1);
}

BOOL SkipVert(void)
{
    menutop += 14;
    if(menutop > 170) {
        if(dispx == 10) {
            dispx = 323;
            menutop = topmostitem;
        } else return(TRUE);
    }
    return(FALSE);
}

void DspMenu()
{
    register LONG l,cmd,x;
    register char *li,*arg;
    topmostitem = menutop = s->BarHeight + LOGOHEIGHT + 3;
    menubot = 0;
    dispx = 10;
    for(l = currmenu; l < lines; l++) {
        li = line[l];
        cmd = GetCmd(li);
        arg = GetArg(li);
        switch(cmd) {
        case C_TITLE:
            if(menutop <= 168) {
                if(arg) {
                    if((x = strlen(arg)) >= 78) break;
                } else x = 0;
                if(menutop < menubot) menutop = menubot;
                if(x) {
                    t[3].IText = arg;
                    t[4].IText = arg;
                    PrintIText(w->RPort,&t[3],320 - (x * 4),menutop + 3);
                }
                menutop += 14;
                topmostitem = menutop;
                dispx = 10;
                if(menutop > menubot) menubot = menutop;
            }
            break;
        case C_ITEMQ: case C_ITEM: case C_MENU: case C_WMENU: case C_WITEM: case C_WITEMQ:
            if(arg) {
                register BOOL wide = (cmd == C_WMENU || cmd == C_WITEM || cmd == C_WITEMQ);
                x = strlen(arg);
                if(wide) {
                    if(x >= 78) break; 
                    dispx = 10;
                    if(menutop < menubot) menutop = menubot;
                } else if(x >= 38) break;
                CreateGadg(dispx,menutop,arg,l,(cmd == C_MENU || cmd == C_WMENU) ? TRUE : FALSE,
                    wide);
                if(wide) {
                    if((menutop += 14) > 170) goto xdisp;
                    topmostitem = menutop;
                } else if(SkipVert()) goto xdisp;
                if(menutop > menubot) menubot = menutop;
            }
            break;
        case C_HDR:
            if(arg && (x = strlen(arg)) < 38) {
                t[3].IText = arg;
                t[4].IText = arg;
                PrintIText(w->RPort,&t[3],dispx + 150 - (x * 4),menutop + 3);
                if(SkipVert()) goto xdisp;
                if(menutop > menubot) menubot = menutop;
            }
            break;
        case C_SECCOL:
            if(dispx == 10) {
                dispx = 323;
                menutop = topmostitem;
            }
            break;
        case C_ENDM:
            goto xdisp;
        case C_ISSUE:
            if(!issuedsp) {
                t[5].IText = arg;
                PrintIText(w->RPort,&t[5],0,s->BarHeight);
                issuedsp = 1;
            }
            break;
        }
    }
xdisp:  RefreshGadgets(&g[0],w,0L);
}

BOOL HandleGadget(UWORD gid)
{
    register char *ln,*mname,*n2;
    register LONG cmd,lc;
    if(gid >= lines) return(FALSE);
    ln = line[gid];
    cmd = GetCmd(ln);
    if(cmd == C_ITEM || cmd == C_ITEMQ || cmd == C_WITEM || cmd == C_WITEMQ) {
        for(lc = gid + 1; lc < lines; lc++) {
            ln = line[lc];
            if(!ln || !(*ln) || GetCmd(ln)) break;
            if(!stricmp(ln,"WBToFront")) WBenchToFront();
            else if(!stricmp(ln,"MenuToFront")) ScreenToFront(s);
            else Execute(ln,0,out);
        }
        if(cmd == C_ITEMQ || cmd == C_WITEMQ) return(TRUE);
    } else if(cmd == C_MENU || cmd == C_WMENU) {
        if(gid++ < lines && !GetCmd(line[gid])) {
            mname = line[gid];
            for(lc = 0; lc < lines; lc++) {
                if(GetCmd(line[lc]) == C_SUBM) {
                    n2 = GetArg(line[lc]);
                    if(!stricmp(n2,mname)) {
                        if(currpar < 14) parents[currpar++] = currmenu;
                        UseMenu(lc);
                        break;
                    }
                }
            }
            if(lc == lines) DisplayBeep(0);
        }
    }
    return(FALSE);
}

void UseMenu(LONG line)
{
    register WORD rempos;
    currmenu = line;
    RemoveGList(w,g[2].NextGadget,-1);
    if(gadgs) FreeRemember(&gadgs,TRUE);
    gadgs = 0;
    rempos = RemoveGList(w,&g[0],3);
    SetAPen(w->RPort,0);
    RectFill(w->RPort,w->BorderLeft,s->BarHeight+LOGOHEIGHT+3,
        w->Width - w->BorderRight,w->Height - w->BorderBottom);
    if(currpar) g[0].Flags &= ~GFLG_DISABLED;
    else g[0].Flags |= GFLG_DISABLED;
    if(currmenu) g[1].Flags &= ~GFLG_DISABLED;
    else g[1].Flags |= GFLG_DISABLED;
    if(rempos >= 0) AddGList(w,&g[0],rempos,3,NULL);
    DspMenu();
}