/*
*	MemSnap.c
*
*	Just like MeMeter (a program I've been using for ages now).
*	Why write it? The MeMeter I've been using crashes under 2.0,
*	and I thought I'd take the time to learn (a bit) about 2.0
*	by programming with it. Nothing groundbreaking here, though.
*
*	Martin W Scott, 3/92.
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

#include "wintext.h"	/* font-independent positioning of text */

char version_str[] = "$VER: MemSnap 1.0 (" __DATE__ ")";

#define CHARS_ACROSS	32	/* max chars across for window texts */
#define CHARS_DOWN	 4	/* how many rows of text in window */

WINTEXT wtexts[] = {
	{ &wtexts[1], " Current",  6, 0, 3, JAM2 },
	{ &wtexts[2], "Snapshot", 15, 0, 3, JAM2 },
	{ &wtexts[3], "    Used", 24, 0, 3, JAM2 },
	{ &wtexts[4], " Chip",     0, 1, 2, JAM2 },
	{ &wtexts[5], " Fast",     0, 2, 2, JAM2 },
	{ NULL,       "Total",     0, 3, 2, JAM2 }
};

char cbuf[3][9], sbuf[3][9], ubuf[3][9];

WINTEXT ctexts[] = {
	{ &ctexts[1], &cbuf[0][0], 6, 1, 1, JAM2 },
	{ &ctexts[2], &cbuf[1][0], 6, 2, 1, JAM2 },
	{ NULL,       &cbuf[2][0], 6, 3, 1, JAM2 }
};

WINTEXT stexts[] = {
	{ &stexts[1], &sbuf[0][0], 15, 1, 1, JAM2 },
	{ &stexts[2], &sbuf[1][0], 15, 2, 1, JAM2 },
	{ NULL,       &sbuf[2][0], 15, 3, 1, JAM2 }
};

WINTEXT utexts[] = {
	{ &utexts[1], &ubuf[0][0], 24, 1, 1, JAM2 },
	{ &utexts[2], &ubuf[1][0], 24, 2, 1, JAM2 },
	{ NULL,       &ubuf[2][0], 24, 3, 1, JAM2 }
};

/* back to normal stuff */

struct Gadget biggadget;	/* this will be snapshot gadget */

#define LEFTEDGE 40		/* window coordinates */
#define TOPEDGE  20

struct NewWindow nw = {
	LEFTEDGE,TOPEDGE,0,0,-1,-1,		/* dimension, pens */
	CLOSEWINDOW | GADGETUP | NEWSIZE,	/* IDCMP flags */
	WFLG_CLOSEGADGET |  WFLG_DRAGBAR	/* window flags */
	| WFLG_DEPTHGADGET | WFLG_SMART_REFRESH,
	&biggadget, NULL,			/* gadgets, checkmark */
	"MemSnap",				/* title */
	NULL, NULL,				/* screen, bitmap */
	0,0,0,0,				/* extrema of dimensions */
	WBENCHSCREEN				/* screen to open onto */
};
WORD zipdata[4] = {LEFTEDGE, TOPEDGE};
struct TagItem wtags[] = {
	{ WA_Zoom, (LONG)&zipdata[0] },
	{ TAG_DONE }
};

struct TextFont *font;			/* screen's default font (and so ours) */
struct Window *w;			/* screen pointer */
struct GfxBase *GfxBase;		/* graphics pointer */
struct IntuitionBase *IntuitionBase;	/* intuition pointer */
WINTEXTINFO wtinfo;
#define DELAY_TIME	10L

/******************************************************************************/
/* My stub for dos.library's VPrintf - amiga.lib one doesn't work for me      */
/******************************************************************************/

#include <stdarg.h>

LONG __stdargs DosPrintf(char *s, ...);

LONG __stdargs DosPrintf(char *s, ...)
{
	va_list ap;
	va_start(ap,s);
	return VPrintf(s, (long *)ap);
}

/******************************************************************************/

/* prototypes for general routines */

void _main(char *);
BOOL OpenLibs(void);
void CloseAll(void), main(int, char **);
BOOL long2str(LONG, char *, UWORD);


BOOL OpenLibs()		/* open required libraries */
{
	if ((GfxBase = (void *)OpenLibrary("graphics.library", 0L)) &&
	    (IntuitionBase = (void *)OpenLibrary("intuition.library", 37L)))
		return TRUE;
	CloseAll();
	return FALSE;
}


void CloseAll()		/* close opened libraries */
{
	if (font) CloseFont(font);
	if (w) CloseWindow(w);
	if (GfxBase) CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
}


/* and this one is rather specific to this program... */

BOOL long2str(LONG n, char *s, UWORD len)	/* long to string, right-adjusted */
{						/* will NOT null-terminate */
						/* len is space in buffer (excl. '\0') */
						/* also, prints nothin if zero */
	short sign;		/* minus sign required? */
	char *t = &s[len-1];	/* get last space in string */

	if (n < 0)		/* get sign of n */
	{
		n = -n;
		sign = -1;
		len--;		/* reduce space (we'll need it for '-') */
	}
	else sign = 0;

	while (n && len)	/* work to do and space to do it */
	{
		*t = '0' + (n % 10);	/* get rightmost digit */
		t--;			/* mave back up string */
		len--;
		n /= 10;
	}

	if (sign)
		*t-- = '-';		/* put sign in now */

	while (len--)			/* fill remainder with spaces */
		*t-- = ' ';

	if (n) return FALSE;		/* failure */
	return TRUE;
}
	
		
/******************************************************************************/

/* Memory data management/manipulation routines */

void getmem(ULONG *), submem(ULONG *, ULONG *, ULONG *), updatemem(ULONG *, WINTEXT *); 

#define CHIP 0
#define FAST 1
#define TOTAL 2

#define clearmem(mem) 		mem[CHIP] = mem[FAST] = mem[TOTAL] = 0L

void getmem(ULONG *mem)		/* store current memory */
{
	mem[TOTAL] = mem[CHIP] = AvailMem(MEMF_CHIP);
	mem[TOTAL] += (mem[FAST] = AvailMem(MEMF_FAST));
}


void submem(ULONG *to, ULONG *from, ULONG *howmuch) /* to = from - howmuch */
{
	to[CHIP] = from[CHIP] - howmuch[CHIP];
	to[FAST] = from[FAST] - howmuch[FAST];
	to[TOTAL] = from[TOTAL] - howmuch[TOTAL];
}


void updatemem(ULONG *mem, WINTEXT *memtext)	/* update specified display */
{
	long2str(mem[CHIP], memtext[CHIP].text, 8);
	long2str(mem[FAST], memtext[FAST].text, 8);
	long2str(mem[TOTAL], memtext[TOTAL].text, 8);

	RenderWinTexts(&wtinfo, memtext);
}

/******************************************************************************/


void _main(char *args)		/* provide a memory 'meter' */
{
	struct IntuiMessage *msg;	/* our window messages */
	ULONG cmem[3],smem[3],umem[3];	/* storage of memory information */
	ULONG class;			/* message class */
	BOOL iconified = FALSE;		/* are we iconified? */


	if (!OpenLibs())	/* failure => under 1.3 */
	{
		if (Output())	/* got a CLI */
			Write(Output(), "Needs KS 2.0\n", -1);
	}
	else if (InitWinTextInfo(&wtinfo))
	{
		/* size window to fit screen font */
		nw.Height = CHARS_DOWN*wtinfo.font_y + wtinfo.toffset + wtinfo.boffset;
		nw.Width = CHARS_ACROSS*wtinfo.font_x + wtinfo.loffset + wtinfo.roffset;
		zipdata[2] = 20*wtinfo.font_x;
 		zipdata[3] = wtinfo.toffset;

		/* and set up big gadget */
		biggadget.LeftEdge = wtinfo.loffset;
		biggadget.TopEdge = wtinfo.toffset;
		biggadget.Width = CHARS_ACROSS*wtinfo.font_x;
		biggadget.Height = wtinfo.font_y;
		biggadget.Flags = GADGHCOMP;
		biggadget.Activation = RELVERIFY;

		if (w = OpenWindowTagList(&nw, wtags))
		{
			wtinfo.window = w;
			if (!(font = OpenFont(wtinfo.tattr)))
			{
				DosPrintf("Can't get screen's font!\n");
				CloseAll();	/* unlikely event... */
			}
			SetFont(w->RPort, font);
			RenderWinTexts(&wtinfo, wtexts);	/* draw initial texts */

			clearmem(smem);		/* initialize memory display */

			for (;;)	/* main event loop */
			{
				while (msg = (struct IntuiMessage *)GetMsg(w->UserPort))
				{
					class = msg->Class;
					ReplyMsg((struct Message *)msg);

					if (class == GADGETUP)
					{
						/* new snapshot */
						getmem(smem);
						updatemem(smem, stexts);
					}
					else if (class == NEWSIZE)
					{
						if (iconified)
						{
							iconified = FALSE;
							RenderWinTexts(&wtinfo, wtexts);
							RenderWinTexts(&wtinfo, stexts);
						}
						else iconified = TRUE;
					}
					else /* class == CLOSEWINDOW */
					{
						CloseAll();
						return;
					}

				} /* while */

				if (iconified)
					Wait(1 <<w->UserPort->mp_SigBit);
				else
				{
					getmem(cmem);
					submem(umem, smem, cmem);
					updatemem(cmem, ctexts);
					updatemem(umem, utexts);

					Delay(DELAY_TIME);
				}

			} /* for */
		}
		else DosPrintf("Can't open window\n");
	}
	else DosPrintf("Can't get screen info\n");

	CloseAll();
} /* main */