
/*
 *  LOADAV.C
 *
 *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  LOADAV  [frequency]     Connect to remote UNIX system and display
 *			    load average.  Default is every 5 minutes.
 *
 *  frequency in seconds, default is every 60 seconds
 *
 */

#include <stdio.h>
#include "/include/typedefs.h"
#include "/dnet/channel.h"

#include "/server/servers.h"
#define BASELOAD    2
#define LOADINCR    2

short MaxLoad = BASELOAD;
ubyte Title[64] = { "LoadAv" };

typedef struct timerequest IOT;

NW Nw = {
    640-150, 0, 150, 50, -1, -1,
    NEWSIZE|CLOSEWINDOW,
    WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH,
    NULL, NULL, Title, NULL, NULL,
    32, 18, -1, -1, WBENCHSCREEN
};

WIN *Win;
RP  *Rp;

int Enable_Abort;
char Buf[512];
char Cc;

extern void *OpenWindow();
extern void *GetMsg();
extern void *CreatePort();

long IntuitionBase;
long GfxBase;

main(ac,av)
char *av[];
{
    long chan = NULL;
    short numsecs = 60;
    long n;
    long imask, tmask, dmask, mask;
    char notdone = 1;
    char *host = NULL;
    PORT *TimPort = CreatePort(NULL, 0);
    IOT Iot;

    {
	register short i;
	for (i = 1; i < ac; ++i) {
	    if (strncmp(av[i], "-N", 2) == 0) {
		host = av[i]+2;
		continue;
	    }
	    numsecs = atoi(av[i]);
	}
    }


    Iot.tr_node.io_Device = NULL;

    if (OpenDevice("timer.device", UNIT_VBLANK, &Iot, 0))
	goto fail;
    Iot.tr_node.io_Command = TR_ADDREQUEST;
    Iot.tr_node.io_Message.mn_ReplyPort = TimPort;
    Iot.tr_time.tv_micro = 1;
    Iot.tr_time.tv_secs  = 0;
    SendIO(&Iot);

    Enable_Abort = 0;
    IntuitionBase = OpenLibrary("intuition.library", 0);
    GfxBase = OpenLibrary("graphics.library", 0);

    chan = DOpen(host, PORT_LOADAV, 25, 25);
    if (chan == NULL) {
	puts("no connect");
	goto fail;
    }
    Win = OpenWindow(&Nw);
    if (Win == NULL) {
	puts("Unable to open window");
	goto fail;
    }
    Rp = Win->RPort;
    imask   = 1 << Win->UserPort->mp_SigBit;
    dmask   = 1 << ((PORT *)chan)->mp_SigBit;
    tmask   = 1 << TimPort->mp_SigBit;

    clearwindow();
    while (notdone) {
	mask = Wait(imask|dmask|tmask|SIGBREAKF_CTRL_C);
	if (mask & SIGBREAKF_CTRL_C)
	    notdone = 0;
	if (mask & imask) {
	    IMESS *im;
	    while (im = GetMsg(Win->UserPort)) {
		switch(im->Class) {
		case NEWSIZE:
		    clearwindow();
		    break;
		case CLOSEWINDOW:
		    notdone = 0;
		    break;
		}
		ReplyMsg(im);
	    }
	}
	if (mask & dmask) {
	    char dummy;
	    if ((dummy = DNRead(chan, &dummy, 1)) != 0)
		notdone = 0;
	}
	while (mask & tmask) {      /*  while just so we can break */
	    char len = 0;
	    char buf[64];
	    long onei,onef,fivei,fivef,teni,tenf;

	    if (GetMsg(TimPort)) {
		Iot.tr_time.tv_micro = 0;
		Iot.tr_time.tv_secs  = numsecs;
		SendIO(&Iot);
		if (DWrite(chan, &len, 1) == 1 && DRead(chan, &len, 1) == 1) {
		    if (DRead(chan, buf, len) == len) {
			sscanf(buf, "%ld.%ld %ld.%ld %ld.%ld",
			    &onei,&onef,&fivei,&fivef,&teni,&tenf
			);
			updatewindow(onei,onef,fivei,fivef,teni,tenf);
			break;
		    }
		}
		notdone = 0;
	    }
	    break;
	}
    }

fail:
    if (Iot.tr_node.io_Device) {
	AbortIO(&Iot);
	WaitIO(&Iot);
	CloseDevice(&Iot);
    }
    DeletePort(TimPort);
    if (Win)
	CloseWindow(Win);
    if (chan)
	DClose(chan);
    if (IntuitionBase)
	CloseLibrary(IntuitionBase);
    if (GfxBase)
	CloseLibrary(GfxBase);
}

#define LSIZE	(sizeof(LBuf)/sizeof(LBuf[0]))
#define LIDX(i) ((Li + i) & (LSIZE-1))

uword LBuf[1024];    /*  The last N readings, (loadav * 256) + 1 */
		     /*  size must be power of 2 */
uword Li;
short Wbl, Wbt, Wbr, Wbb, Wh, Ww;

clearwindow()
{
    short i, j;
    short height;

    Wbl = Win->BorderLeft;
    Wbr = Win->BorderRight;
    Wbt = Win->BorderTop;
    Wbb = Win->BorderBottom;
    Ww	= Win->Width;
    Wh	= Win->Height;

    SetAPen(Rp, 0);
    RectFill(Rp, Wbl, Wbt, Ww - Wbr, Wh - Wbb);

    Wbl += 2;
    Wbr += 4;
    SetAPen(Rp, 1);
    for (i = 0, j = Ww - Wbr; i < LSIZE && j > Wbl; ++i, --j) {
	height = (Wh - Wbb - Wbt) * LBuf[LIDX(i)] / (MaxLoad << 8);
	if (Wh - Wbb - height > 0) {
	    Move(Rp, j, Wh - Wbb);
	    Draw(Rp, j, Wh - Wbb - height);

	}
    }
    SetAPen(Rp, 3);
    for (i = 1; i < MaxLoad; ++i) {
	height = Wh - Wbb - (Wh - Wbb - Wbt) * i / MaxLoad;
	RectFill(Rp, Wbl - 2     , height, Wbl - 1     , height + 1);
	RectFill(Rp, Ww - (Wbr - 3), height, Ww - (Wbr - 4), height + 1);
    }
    SetAPen(Rp, 1);
}

updatewindow(i1, f1, i5, f5, i10, f10)
{
    short height;
    short res = 0;

    while (i1 < 1000 && i1 >= MaxLoad) {
	MaxLoad += LOADINCR;
	res = 1;
    }
    if (res)
	clearwindow();
    sprintf(Title, "LoadAv %2ld.%02ld %2ld.%02ld %2ld.%02ld   Max=%2ld",
	i1, f1, i5, f5, i10, f10, MaxLoad
    );
    SetWindowTitles(Win, Title, -1);
    f1 = (f1  * 256) / 100;
    f5 = (f5  * 256) / 100;
    f10= (f10 * 256) / 100;
    ScrollRaster(Rp, 1, 0, Wbl, Wbt, Ww - Wbr, Wh - Wbb);
    Li = (Li-1) & (LSIZE-1);
    LBuf[Li] = ((i1 << 8) | f1) + 1;

    height = (Wh - Wbb - Wbt) * LBuf[Li] / (MaxLoad << 8);
    if (Wh - Wbb - height > 0) {
	Move(Rp, Ww - Wbr, Wh - Wbb);
	Draw(Rp, Ww - Wbr, Wh - Wbb - height);
    }
    SetAPen(Rp, 2);
    Move(Rp, Wbl, Wbt + Rp->TxBaseline);
    Text(Rp, Title + 7, 5);
    SetAPen(Rp, 1);
}

