/*************************************************************************
 ***                    ASK TASK - EXAMINES EXEC TASKS   (JJB TEMPLAR) ***
 *** Date begun: 31/3/89.                                              ***
 *** Last modified: 2/4/89.                                            ***
 ***                23/4/89 - added line to start from WB without con: ***
 ***                28/4/89 - use #define DEFAULT_PRI 0, use cback.o,  ***
 ***                          use __tinymain (so no noWBcons), added   ***
 ***                          printf kludge.                           ***
 ***                10/7/89 - added iconification.                     ***
 ***                11/7/89 - added tooltype stuff.                    ***
 ***                        - added trick menu.                        ***
 *************************************************************************/

#include "asktask.h"
#include "iconify.h"

#define DEFAULT_PRI 0

long    _stack = 10000;             /* Globals for cback.o */
char    *_procname = "asktask";
long    _priority = DEFAULT_PRI;
long    _BackGroundIO = 1;
extern BPTR _Backstdout;
extern char *_ProgramName;           /* cback sets this up */

struct GfxBase          *GfxBase;
struct IntuitionBase    *IntuitionBase;
struct IconBase         *IconBase;
struct ExecBase         *ExBase;
struct Window           *Window;
struct NewWindow        NewWindow = {
    0,0,640,145,0,1,RAWKEY|MOUSEBUTTONS|CLOSEWINDOW|GADGETUP,
    WINDOWDEPTH|WINDOWCLOSE|WINDOWDRAG|SMART_REFRESH|ACTIVATE,
    NULL,NULL,"AskTask - JJB TEMPLAR",NULL,NULL,0,0,0,0,WBENCHSCREEN};
  /* Damned if I'll let some Pascal derivative programmer use an ST font
   * on MY program! Can fix all the IntuiTexts with this, but what about
   * Window title and Menu? Well, the accursed FastFonts doesn't just set
   * a new default font. So this doesn't work! */
struct TextAttr         topaz = {"topaz.font",8,0,0};

struct  Task    *task[NUM_TASKS];
char            tnames[NUM_TASKS*TNAMESIZE];
char            *tnp[NUM_TASKS];
int             numtasks,page,ct;
BPTR            emerg;              /* Emergency console */
char            *tooltypes[3] = {"COLOR","ICONIFY","PRIORITY"};

char    *notaskerror = "But there's no task! What are you trying to do?";
char    *usagestring =
"[32mAskTask1.1: Jul 15 89 - [42m[33m JJB TEMPLAR [0m[33m[3m - a program to examine task data.[0m\n\
[32mUSAGE:[0m %s [<-opt>]\n";
char    *usagestring2 =
"    where opt = c       - use intended (my) colors.\n\
                i       - iconify on startup.\n\
                p{n}    - set asktask priority to n.\n\
[32mNOTE:[0m [] = optional, <> = 1 or more, {} = mandatory.\n";

char        mypri;
struct Task *me;
int         mycolors;
UWORD       cmap[4] = {0x000,0x455,0x999,0x600};
UWORD       tmap[4];

extern struct Gadget *firstgadg;
extern UWORD far    icon1[232];
struct Image    iconimg = {0,0,52,29,2,&icon1[0],3,0,NULL};
int     iconsuccess = 1;
  /** Can't use iconimg variables, as these are also used to draw the image,
   ** so icon appears to be blank when moved away from 0,0 **/
UWORD   ILeft,ITop;     /* Initialized to zero by Lattice startup code */
#define IL  (&ILeft)
#define IT  (&ITop)
#define IW  iconimg.Width
#define IH  iconimg.Height

extern int  menuflag;   /* Flag: if TRUE means menu intalled */

extern void help();
extern void about();
extern void input(struct Window *,char *,char *,char *,int,int,int,int,int);
extern void rmv();
extern void kill();
extern unsigned long bitsput(char *);
extern void putbits(char *,unsigned long);
extern void prevpage();
extern void nextpage();
extern void puttname(int,int);
extern void puttasks();
extern void puttaskdata();
extern void setupwindow();
extern void putmessage(char *,int);
extern char getchfromw();
extern int  yesno();
extern void setsignal();
extern void changepri();

void    gettasks();
void    cleanup(int);
void    doclick(short,short);
void    printf();       /* Don't define args. */
void    handleiconify();
void    doopts(int,char **);
int     getint(char *);

void    printf(cs,arg) /*================================================*/
char    *cs;           /* control string */
long    arg;           /* only ever one arg max */
{
int     j;
char    buf[512];      /* Easily enough for my purposes */

    if (!_Backstdout) return;       /* Don't write to nothing! */
    sprintf(buf,cs,arg);
    j = strlen(buf);
    Write(_Backstdout,buf,j);
}

void    gettasks() /*====================================================*/
{
int     i,j;
struct  Task *tp,**th;
    j = i = 0;
    Disable();
    th = (struct Task **)(ExBase->TaskReady.lh_Head);
    tp = *th;
    while (tp && (j < NUM_TASKS)) {
        task[j] = tp;
        strcpy(&tnames[i],tp->tc_Node.ln_Name);
        tnp[j] = &tnames[i];
        i += strlen(tnp[j]) + 1;
        j++;
        tp = (struct Task *)(tp->tc_Node.ln_Succ);
    }
    th = (struct Task **)(ExBase->TaskWait.lh_Head);
    tp = *th;
    while (tp && (j < NUM_TASKS)) {
        task[j] = tp;
        strcpy(&tnames[i],tp->tc_Node.ln_Name);
        tnp[j] = &tnames[i];
        i += strlen(tnp[j]) + 1;
        j++;
        tp = (struct Task *)(tp->tc_Node.ln_Succ);
    }
    Enable();
    numtasks = j;
    page = 0;   ct = -1;
}

void    doclick(x,y) /*==================================================*/
short   x,y;
{
    putmessage("",1);
    if ((x >= 2) && (x <= 165)) {
        if ((y < 21) || (y > 132)) return;
        y -= 21;
        y = (page * 14) + (y / 8);
        if (y >= numtasks) return;
        ct = y;
        puttaskdata();
        if (!tnp[y][0]) putmessage("WARNING: nameless tasks are dubious!",3);
    }
    else if ((x >= 168) && (x <= 471)) {
        if ((y < 10) || (y > 132)) return;
        puttaskdata();
    }
}

void    handleiconify() /*===============================================*/
{
    if (iconsuccess) {
        NewWindow.LeftEdge = Window->LeftEdge;
        NewWindow.TopEdge = Window->TopEdge;
        if (menuflag) {
            menuflag = 0;           /* Warn help() that AhaMenu is gone */
            ClearMenuStrip(Window); /* Don't set menu back after iconify */
        }
        CloseWindow(Window);
        if (mycolors) LoadRGB4(&(Window->WScreen->ViewPort),tmap,4);
        iconsuccess = iconify(IL,IT,IW,IH,NULL,&iconimg,ICON_IMAGE);
        if (!(Window = OpenWindow(&NewWindow))) {
          /* ERROR: failed to recover from Iconify - no error output */
            cleanup(2);
        }
        if (mycolors) LoadRGB4(&(Window->WScreen->ViewPort),cmap,4);
        setupwindow();
        gettasks();
        puttasks();
        puttaskdata();
        putmessage("Welcome back to AskTask...",1);
    }
    else {
        putmessage("[Haven't I already told you iconify failed?]",1);
        return;
    }
    if (!iconsuccess)
        putmessage("Iconify has failed!",3);
}

void    doopts(argc,argv) /*=============================================*/
int     argc;
char    *argv[];
{
struct DiskObject *dobj;
char    *val;
int     temp;
    if (!argc) {
        if (!(IconBase = (struct Library *)OpenLibrary("icon.library",0L)))
            return;         /* Failed to open icon.library - no big deal */
        if (!(dobj = (struct DiskObject *)GetDiskObject(_ProgramName))) {
            CloseLibrary(IconBase); /* Failed to get icon - too bad */
            return;
        }
        while (argc < 3) {
            if (val = (char *)FindToolType(dobj->do_ToolTypes,tooltypes[argc])) {
                switch (argc) {
                    case (0): if (MatchToolValue(val,"ON")) mycolors = 1;
                              break;
                    case (1): if (MatchToolValue(val,"ON")) iconsuccess = 0;
                              break;
                    case (2): temp = getint(val);
                              mypri = (char)temp;
                              break;
                }
            }
            argc++;
        }
        FreeDiskObject(dobj);
        CloseLibrary(IconBase);
    }
    else {
        while (--argc) {
            if (argv[argc][0] == '?') {
                printf(usagestring,argv[0]);
                printf(usagestring2);
                cleanup(0);                     /* To zap _Backstdout */
            }
            if (argv[argc][0] == '-') {
                switch (argv[argc][1]) {
                    case ('c'): mycolors = 1; break;
                    case ('i'): iconsuccess = 0; break;  /* var overloading? */
                    case ('p'): temp = getint(&argv[argc][2]);
                                mypri = (char)temp;
                                break;
                    default: printf("WARNING: unknown option: %s\n",argv[argc]);
                }
            }
            else printf("WARNING: unknown option: %s\n",argv[argc]);
        }
    }
}

int     getint(cp) /*====================================================*/
register char   *cp;
{
register char   *st = cp;
register int    ret,place;
    while (isdigit(*cp)) *cp++;
    ret = 0;    place = 1;
    while (--cp >= st) {
        ret += (*cp - '0') * place;
        place *= 10;
    }
    return(ret);
}

void    main(argc,argv) /*===============================================*/
int     argc;
char    *argv[];
{
struct IntuiMessage *msg,m;
struct Gadget       *gp;
int         event,j;
long        *hook;

    mypri = DEFAULT_PRI;    mycolors = 0;
    doopts(argc,argv);
    me = (struct Task *)FindTask(NULL);
    if (me->tc_Node.ln_Pri < mypri) SetTaskPri(me,mypri);

    hook = (long *)0x4L;
    ExBase = (struct ExecBase *)*hook;

    if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L))) {
        printf("ERROR: unable to open graphics.library!\n");
        cleanup(0);
    }
    if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L))) {
        printf("ERROR: unable to open intuition.library!\n");
        cleanup(1);
    }
    NewWindow.FirstGadget = firstgadg;
    if (!(Window = (struct Window *)OpenWindow(&NewWindow))) {
        printf("ERROR: unable to open window!\n");
        cleanup(2);
    }

    if (_Backstdout) {
        Close(_Backstdout);
        _Backstdout = NULL;
    }

    if (mycolors) {
        for (j = 0; j < 4; j++)
            tmap[j] = GetRGB4(Window->WScreen->ViewPort.ColorMap,j);
        LoadRGB4(&(Window->WScreen->ViewPort),cmap,4);
    }

    setupwindow();      /* Draw boxes and things */

    gettasks();
    puttasks();
    puttaskdata();
    putmessage("Welcome to AskTask...  (version dated 15/7/89)",1);

    if (!iconsuccess) {     /* From -i option. MUST put back to 1 */
        iconsuccess = 1;    /* This is what I mean by var overloading - */
        handleiconify();    /* same variable used for different purposes */
    }

    event = 1;
    while (event) {
        Wait(1<<Window->UserPort->mp_SigBit);
        while (msg = (struct IntuiMessage *)GetMsg(Window->UserPort)) {
            m = *msg;
            ReplyMsg((struct Message *)msg);
            switch (m.Class) {
                case (CLOSEWINDOW): event = 0;  break;
                case (RAWKEY): switch (m.Code) {
                    case (0x45): event = 0;     break;  /* ESC */
                    case (0x50): gettasks();            /* F1 */
                                 puttasks();
                                 puttaskdata();
                                 putmessage("[Task data refreshed]",1);
                                 break;
                    case (0x51): puttaskdata(); break;  /* F2 */
                    case (0x52): handleiconify();   break;
                    case (0x54): kill();        break;  /* F5 */
                    case (0x55): rmv();         break;  /* F6 */
                    case (0x56): setsignal();   break;  /* F7 */
                    case (0x57): changepri();   break;  /* F8 */
                    case (0x59): about();       break;  /* F10 */
                    case (0x4c): prevpage();    break;  /* CSR UP */
                    case (0x4d): nextpage();    break;  /* CSR DN */
                    case (0x5d):                        /* NUMK '*' */
                        putmessage("[Emergency? Providing CLI. Don't forget to endcli soon!]",0);
                        emerg = Open("CON:0/0/640/100/AskTask: Emergency?",MODE_NEWFILE);
                        Execute("",emerg,0L);
                        Close(emerg);
                        putmessage("[Emergency over? Glad to be back.]",0);
                        break;
                    case (0x5f): help();        break;  /* HELP */
                }
                break;
                case (MOUSEBUTTONS):
                    if (m.Code == SELECTDOWN) doclick(m.MouseX,m.MouseY);
                    break;
                case (GADGETUP): gp = (struct Gadget *)msg->IAddress;
                switch (gp->GadgetID) {
                    case (G_QUIT):     event = 0;   break;
                    case (G_HELP):     help();      break;
                    case (G_NEXTPAGE): nextpage();  break;
                    case (G_PREVPAGE): prevpage();  break;
                    case (G_SETSIG):   setsignal(); break;
                    case (G_CHANGE_P): changepri(); break;
                    case (G_REF_TASK): puttaskdata(); break;
                    case (G_EXITTASK): kill();      break;
                    case (G_REMOVE):   rmv();       break;
                    case (G_REFRESH):  gettasks();
                                       puttasks();
                                       puttaskdata();
                                       putmessage("[Task data refreshed]",1);
                                       break;
                    case (G_ICONIFY):  handleiconify(); break;
                    case (G_ID):       break;   /* Do nothing gadget */
                }
                break;
                default: putmessage("Unused input!",1);
            }
        }
    }

    cleanup(ENDNORMAL);
}

void    cleanup(n) /*====================================================*/
int     n;
{
    switch (n) {
        case (3): if (mycolors) LoadRGB4(&(Window->WScreen->ViewPort),tmap,4);
                  if (menuflag) ClearMenuStrip(Window);
                  CloseWindow(Window);
        case (2): CloseLibrary(IntuitionBase);
        case (1): CloseLibrary(GfxBase);
        case (0): if (_Backstdout) Close(_Backstdout);
                  break;
        default: printf("cleanup() default error!\n");
                 putmessage("cleanup() default error!\n",3);
    }
    XCEXIT(0);
}
