/*  :ts=8 bk=0
 * File mapper.  Uses trackdisk.device to grab sectors and traverse the
 * filesystem the hard way to find out what sectors a particular file
 * occupies.
 *
 * Crufted together by Leo Schwab while waiting for an open line on the WELL.
 *	8608.19
 * Finally finished:	8609.16
 * I could have done it quicker if I hadn't started working for Wendy's.
 *
 * Note: This program is only valid for 3.5" floppy drives.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <devices/trackdisk.h>
#include "things.h"


extern struct NewWindow	windef;
extern struct IntuiText	errmsg, ok;
extern struct Gadget	gad[];
extern char		filename[], devname[];

struct Window	*win;
struct RastPort *rp;
struct InfoData *id;
struct IOExtTD	*diskreq;
struct MsgPort	*diskport;
ULONG		diskchangecount, *diskbuffer, bitmap[SIZE];
int		bmsect;
void		*IntuitionBase, *GfxBase, *lok;


main (ac, av)
char *av[];
{
	struct IntuiMessage *msg;
	struct Gadget *ptr;
	int class;

	if (ac) {
		ac--;  av++;
		if (ac) {
			strcpy (devname, *av);
			ac--;  av++;
		} else
			strcpy (devname, "df0:");

		if (ac)
			strcpy (filename, *av);
		else
			strcpy (filename, ":");
	}
	openstuff ();
	drawgrid ();
	setdev ();

	/*  Process IntuiEvents  */
	for ever {
		WaitPort (win -> UserPort);
		msg = GetMsg (win -> UserPort);
		class = msg -> Class;
		ptr = (struct Gadget *) msg -> IAddress;
		ReplyMsg (msg);
		if (class == CLOSEWINDOW)
			break;
		else if (class == GADGETUP) {
			if (ptr == gad) {		/*  New filename  */
				drawbitmap ();
				findfile (filename);
			} else if (ptr == &gad[1])	/*  New device  */
				setdev ();
			else if (ptr == &gad[2]) {	/*  Refresh screen  */
				getbitmap ();
				drawbitmap ();
				findfile (filename);
			}
		}
	}
	closestuff ();
}


setdev ()
{
	int unit;

	/*
	 * This rather lengthy series of DOS calls is needed to turn DOS
	 * device names into unit numbers that OpenDevice() can deal with.
	 */
	if (!(lok = Lock (devname, ACCESS_READ)))
		die ("Can't obtain lock for specified device.");

	if (!(id = AllocMem ((long) sizeof (*id), MEMF_CLEAR)))
		die ("Can't get InfoData memory.");

	if (!Info (lok, id))
		die ("Call to Info() failed.");

	if (id -> id_DiskType == ID_NO_DISK_PRESENT)
		die ("No disk in drive.");

	unit = id -> id_UnitNumber;
	FreeMem (id, (long) sizeof (*id));  id = NULL;
	UnLock (lok);  lok = NULL;
	opendisk (unit);
	getbitmap ();
	drawbitmap ();
}

getbitmap ()
{
	register int i;

	MotorOn ();
	GetSector ((long) ROOTBLOCK);
	bmsect = diskbuffer [BITMAPINDEX];
	GetSector ((long) bmsect);
	MotorOff ();
	for (i=0; i<SIZE; i++)
		bitmap [i] = diskbuffer [i];
}

drawbitmap ()
{
	register int i, n, l, p;
	int free = NUMBLOCKS-2;
	long k, x, y;
	char buf[80];

	SetDrMd (rp, JAM1);
	SetAPen (rp, 3L);

	/*  Show sectors 0 and 1 (always allocated)  */
	RectFill (rp, XOFF+1, YOFF+1, XX+XOFF-1, YY+YY+YOFF-1);
	l = 2;
	for (i=1; i<=NUMLONGS; i++) {
		k = bitmap[i];
		for (n=0; n<32; n++) {
			/*  Bits progress from low to high order  */
			if (i<NUMLONGS || n<30) {	/*  Ignore last two  */
				/*  Perform icky conversion  */
				x = (l / 22) * XX + XOFF;
				y = (l % 22) * YY + YOFF;
				if (y >= BRKOVER)
					y += SEP;

				/*
				 * The following incantation basically means,
				 * don't draw sectors that don't need to be
				 * drawn.
				 */
				p = ReadPixel (rp, x+1, y+1);
				if (~k & 1) {
					free--;
					if (p != 3) {
						SetAPen (rp, 3L);
						RectFill (rp, x+1, y+1,
							  x+XX-1, y+YY-1);
					}
				} else if (p) {
					SetAPen (rp, 0L);
					RectFill
					 (rp, x+1, y+1, x+XX-1, y+YY-1);
				}
				k >>= 1;
			}
			l++;	/*  Increment sector number  */
		}
	}

	/*  Do labels  */
	SetAPen (rp, 1L);
	SetBPen (rp, 0L);
	SetDrMd (rp, JAM2);
	sprintf (buf, "Bitmap on sector %-4d", bmsect);
	Move (rp, XOFF, LABEL_Y);
	Text (rp, buf, (long) strlen (buf));
	sprintf (buf, "Sectors free: %-4d", free);
	Move (rp, 250L, LABEL_Y);
	Text (rp, buf, (long) strlen (buf));
	sprintf (buf, "Allocated: %-4d", (int) NUMBLOCKS-free);
	Move (rp, 450L, LABEL_Y);
	Text (rp, buf, (long) strlen (buf));
	Move (rp, NUMCYLS*XX+XOFF+10, NUMSECS*YY/2+YOFF+2);
	Text (rp, "Surface 0", 9L);
	Move (rp, NUMCYLS*XX+XOFF+10, NUMSECS*YY/2+BRKOVER+SEP+2);
	Text (rp, "Surface 1", 9L);
}

drawgrid ()	/*  Draw grid and labels so we can see  */
{
	long x, y;

	SetDrMd (rp, JAM1);
	SetAPen (rp, 1L);
	for (x=XOFF; x<=80*XX+XOFF; x += XX) {
		Move (rp, x, YOFF);
		Draw (rp, x, YOFF+11*YY);
		Move (rp, x, BRKOVER+SEP);
		Draw (rp, x, BRKOVER+SEP+11*YY);
	}
	for (y=0; y<=11*YY; y += YY) {
		Move (rp, XOFF, y+YOFF);
		Draw (rp, XOFF+80*XX, y+YOFF);
		Move (rp, XOFF, y+SEP+BRKOVER);
		Draw (rp, XOFF+80*XX, y+SEP+BRKOVER);
	}

	/*  Draw map markings  */
	Move (rp, XOFF+XX/2, YOFF);	  Draw (rp, XOFF+XX/2, YOFF-3);
	Move (rp, XOFF+80*XX-XX/2, YOFF); Draw (rp, XOFF+80*XX-XX/2, YOFF-3);
	Move (rp, XOFF, YOFF+YY/2);	  Draw (rp, XOFF-3, YOFF+YY/2);
	Move (rp, XOFF, YOFF+YY*10+YY/2); Draw (rp, XOFF-3, YOFF+YY*10+YY/2);
	Move (rp, XOFF-1, YOFF-4);	  Text (rp, "0", 1L);
	Move (rp, XOFF+79*XX-1, YOFF-4);  Text (rp, "79", 2L);
	Move (rp, XOFF-12, YOFF+6);	  Text (rp, "0", 1L);
	Move (rp, XOFF-20, YOFF+11*YY);   Text (rp, "10", 2L);
}

marksector (n, color)
long n;
int color;
{
	register int x, y;

	x = (n / 22) * XX + XOFF;
	y = (n % 22) * YY + YOFF;
	if (y >= BRKOVER)
		y += SEP;
	SetAPen (rp, (long) color);
	RectFill (rp, x+1L, y+1L, x+XX-1L, y+YY-1L);
}

openstuff ()
{
	if (!(IntuitionBase = OpenLibrary ("intuition.library", REV))) {
		/*
		 * If we can't open Intuition, then we can't use
		 * AutoRequest ()
		 */
		printf ("Intuition failed; you'll have to use logic.\n");
		closestuff ();
		exit (100);
	}

	if (!(GfxBase = OpenLibrary ("graphics.library", REV))) {
		printf ("Art shop closed.\n");
		closestuff ();
		exit (100);
	}

	if (!(win = OpenWindow (&windef))) {
		printf ("Window painted shut.\n");
		closestuff ();
		exit (100);
	}
	rp = win -> RPort;

	if (!(diskport = CreatePort (NULL, NULL)))
		die ("No port.");

	if (!(diskreq = CreateExtIO (diskport, (long) sizeof (*diskreq))))
		die ("Can't make IO block.");

	if (!(diskbuffer = AllocMem (BLOCKSIZE, MEMF_CLEAR | MEMF_CHIP)))
		die ("Can't allocate disk buffer.");
}

opendisk (unit)
int unit;
{
	long err;
	char *buf[80];

	/*  We may be changing units, so close it if it's open  */
	if (diskreq -> iotd_Req.io_Device) {
		CloseDevice (diskreq);
		diskreq -> iotd_Req.io_Device = NULL;
	}

	if (err = OpenDevice (TD_NAME, (long) unit, diskreq, NULL)) {
		sprintf (buf, "Can't get at disk; err = %ld.", err);
		die (buf);
	}

	diskreq -> iotd_Req.io_Command = TD_CHANGENUM;
	DoIO (diskreq);
	diskchangecount = diskreq -> iotd_Req.io_Actual;
}

closestuff ()
{
	if (lok)
		UnLock (lok);
	if (diskreq) {
		/*
		 * Apparently, if OpenDevice() fails, it fills in the
		 * io_Device field with -1.  This pretty much blows all
		 * my previous code out of the water, which assumed it got
		 * filled in with 0.  Sigh.  Why don't they tell us these
		 * things?
		 */
		if ((long) diskreq -> iotd_Req.io_Device != -1L)
			CloseDevice (diskreq);
		DeleteExtIO (diskreq, (long) sizeof (*diskreq));
	}

	if (diskbuffer)
		FreeMem (diskbuffer, (long) BLOCKSIZE);
	if (id)
		FreeMem (id, (long) sizeof (*id));
	if (diskport)
		DeletePort (diskport);
	if (win)
		CloseWindow (win);
	if (GfxBase)
		CloseLibrary (GfxBase);
	if (IntuitionBase)
		CloseLibrary (IntuitionBase);
}

notice (str)	/*  For non-fatal errors  */
UBYTE *str;
{
	MotorOff ();
	errmsg.IText = str;
	AutoRequest (win, &errmsg, NULL, &ok, NULL, NULL,
		     TextLength (rp, str, (long) strlen (str)) + 40, 46L);
}

die (str)	/*  For fatal errors  */
UBYTE *str;
{
	errmsg.IText = str;
	AutoRequest (win, &errmsg, NULL, &ok, NULL, NULL,
		     TextLength (rp, str, (long) strlen (str)) + 40, 46L);
	closestuff ();
	exit (100);
}

/*	Guess....
debug (str)
char *str;
{
	printf (str);
	getchar ();

}
*/
