/**************************************************************************/
/**	    SpyHead.c (SYSGADS) Apr 1991  L.v.Jeurissen  (LvJ)           **/
/**************************************************************************/

/**************************************************************************/
/** Spy Head V1.0 is a easy useable and nice looking program that shares **/
/** with you the information, on wich place the read/write head actually **/
/** is. When you insert a disk in a drive Spy head changes to that drive **/
/** to spy the drives head. The JumpScreen gadget, will open Spy Head's  **/
/** window in the next Screen if it is available and not to small.       **/
/** I have some questions :  Who knows why MANX detach.o gurus by an     **/
/** exit() call on an A1000 and that only with the shell. Is it my error **/
/** (look between #ifndef A1000 and #endif) or is it a bug in _main.c /  **/
/** _exit.c  look in directory sysio.arc from the MANX library sources.	 **/
/** Let me know if you have the right answer. In advance a big thank to  **/
/** the people, who wants to look in to that problem. THANK YOU !        **/
/** Another question is this one: After I Write some text to the CLI/    **/
/** Shell the prompt won't return after a `\n', this is a common problem **/
/** because lot's of people (programmers) know the problem, but they     **/
/** can't give me the right answer! WHO CAN! In this case I used a `\r'  **/
/** because it looks nicer than a missing prompt.                        **/
/** The same rules as for Spy Mouse V1.0 are valid: Anyone may sell this **/
/** proggy (only  for big  money, and only to idiots who want to get rid **/
/** of their money), sell (only idiots), throw away, change, etc.        **/
/** I won't feel, and act responsable for any damage or losses of goods  **/
/** and lives that this program may cause.  EVER!!			 **/
/** Good criticism and tips are however welcome. If you find flow        **/
/** errors or code that could be better or quicker let me know, it's     **/
/** a hobby, but I'am eager to learn new things.                         **/
/**									 **/
/** You feel like giving away some money?	  Send it to GreenPeace. **/
/**									 **/
/** All those seadogs are freezing to death without a warm coat, so	 **/
/** support those freezing annimals outthere. They supported us long	 **/
/** enough so now its our turn to support them. Buy them a warm furr !!  **/
/**									 **/
/** SeaBirds don't want a oilcoat they have one themselves.              **/
/**									 **/
/** Support me also, not with money, but with bug reports, tips. If you  **/
/** find big errors in the source? let me know. You scratch my back and  **/
/** I will scratch yours. You invented a wheel let me know, maybe I can  **/
/** use it to build a car.						 **/
/**									 **/
/** Apr 20 23:07:10 1991			L.V. Jeurissen		 **/
/**						Paterstraat 35		 **/
/**						6828 AG  Arnhem 	 **/
/**						085-455693		 **/
/**						Nederland		 **/
/**************************************************************************/

#include "Data.c"

#ifndef A1000
#define EGOSTRING "\x9B1mSpy Head V1.0\x9B0m  (c) Apr 1991 by \x9B1mL\x9B0mars \x9B1mV\x9B0man \x9B1mJ\x9B0meurissen\r"
#define EGOSTRLEN (long) sizeof(EGOSTRING)
#endif
#define BLOCKS(ACTTRK,ACTSEC) ((ACTTRK * (UWORD) NUMSECS) + ACTSEC)
#define WAITSEC 0L
#define WAITMIC 125000L

void _wb_parse()
{
}
void _cli_parse()
{
}

void main();
void LoopThisCode();
void SpyHead();
void ChangeDriveNumber();
void FillITextBuffer();
void NumberToBuffer();
void AudioInform();
void WakeMeUpService();
void JumpToNextScreen();
void OpenWindowCheck();
void CloseWindowCheck();
void DoThisCodeFirst();
void DoThisCodeLast();

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Window *Window = NULL;
struct Screen *Screen = NULL;
struct IOStdReq *DiskIO = NULL, *TimerIO = NULL;
struct Device *DiskDevice = NULL;
struct MsgPort *DiskPort = NULL, *TimerPort = NULL;

USHORT *ChipImageBlock = NULL;
UWORD DriveNumber = 0, Sektor = 0, Track = 0;
ULONG TimerSignal = NULL;
static ULONG DiskChange[NUMUNITS] = {0L, 0L, 0L, 0L};
static UBYTE TRACKDISKNAME[] = TD_NAME;

#ifndef A1000
extern BPTR _Backstdout;
long _BackGroundIO = 1L;
long _stack = 1536L + 256L;
char *_procname = "Spy Head V1.0";
long _priority = 0L;
#endif

void main()
{
    DoThisCodeFirst();
    LoopThisCode();
}

void LoopThisCode()
{
    register struct IntuiMessage *message;
    register ULONG Class;
    register APTR IAddress;
    register int count;

    WakeMeUpService(WAITSEC, WAITMIC);

    while (TRUE) {

	if (Wait(1L << Window->UserPort->mp_SigBit | TimerSignal) & TimerSignal) {
	    GetMsg(TimerPort);
	    SpyHead();
	    WakeMeUpService(WAITSEC, WAITMIC);
	}
	while (message = (struct IntuiMessage *) GetMsg(Window->UserPort)) {

	    Class = message->Class;
	    IAddress = message->IAddress;

	    ReplyMsg((struct Message *) message);
	    switch (Class) {
	    case CLOSEWINDOW:
		while (message = (struct IntuiMessage *) GetMsg(Window->UserPort))
		    ReplyMsg((struct Message *) message);
		DoThisCodeLast(RETURN_OK);
		break;
	    case DISKINSERTED:
		for (count = 0; count < NUMUNITS; count++) {
		    if (DiskChange[count] == FALSE)
			continue;
		    if (OpenDevice(TRACKDISKNAME, (long) count, (struct IOStdReq *) DiskIO, TDB_ALLOW_NON_3_5) > NULL)
			continue;
		    else {
			DiskIO->io_Command = TD_CHANGESTATE;
			DoIO(DiskIO);
			if (DiskIO->io_Actual != NULL) {
			    CloseDevice(DiskIO);
			    continue;
			}
			DiskIO->io_Command = TD_CHANGENUM;
			DoIO(DiskIO);
			if (DiskIO->io_Actual != DiskChange[count]) {
			    DiskChange[count] = DiskIO->io_Actual;
			    CloseDevice(DiskIO);
			    DriveNumber = (UWORD) count;
			    break;
			}
			CloseDevice(DiskIO);
		    }
		}
		AudioInform();
		break;
	    case GADGETUP:
		if (IAddress == (APTR) & ChangeDriveGadget) {
		    ChangeDriveNumber();
		    break;
		}
		if (IAddress == (APTR) & JumpScreenGadget) {
		    JumpToNextScreen();
		    break;
		}
            default:
                break;
	    }
	}
    }
}

#asm
	public	_SpyHead
_SpyHead:
	link	a5,#$0
	movem.l lb3,-(sp)
	move.l	_DiskDevice,a0
	moveq.l #$0,d0
	move.w	_DriveNumber,d0
	asl.w	#$2,d0
	movea.l $24(a0,d0.w),a1
	cmpa.l	#$0,a1
	beq.s	lb1
	move.w	$48(a1),_Sektor
	move.w	$4a(a1),_Track
	jsr	_FillITextBuffer
	bra.s	lb2
lb1:	jsr	_ChangeDriveNumber
	jsr	_AudioInform
lb2:	movem.l (sp)+,lb3
	unlk	a5
	rts
lb3:	reg	a0-a6/d0-d7
#endasm

void ChangeDriveNumber()
{
    DriveNumber++;
    if (DriveNumber > 3)
	DriveNumber = 0;
}

void FillITextBuffer()
{
    register int count;
    static char temp[27] = " B:0000  T:000  S:00  DF0: ";

    for (count = 0; count < 27; count++)
	buffer[count] = temp[count];

    NumberToBuffer(6, BLOCKS(Track, Sektor));
    NumberToBuffer(13, Track);
    NumberToBuffer(19, Sektor);
    NumberToBuffer(24, DriveNumber);
    PrintIText(Window->RPort, &IText, 26L, 1L);
}

void NumberToBuffer(count, Number)
register int count, Number;
{
    do {
	buffer[count] = ((int) (Number % 10) + 0x30);
	count--;
    } while ((Number /= 10) != 0);
}

void AudioInform()
{
    *(UWORD *) 0xdff0a0 = *(UWORD *) (ChipImageBlock + 680L);
    *(UWORD *) 0xdff0a4 = 0x0004;
    *(UWORD *) 0xdff0a8 = 0x0040;
    *(UWORD *) 0xdff0a6 = 0x01BF;
    *(UWORD *) 0xdff096 = 0x8201;
    Delay(5L);
    *(UWORD *) 0xdff096 = 0x0001;
}

void WakeMeUpService(S, M)
ULONG S, M;
{
    TimerIO->io_Command = TR_ADDREQUEST;
    TimerIO->io_Actual = S;
    TimerIO->io_Length = M;
    SendIO(TimerIO);
}

void JumpToNextScreen()
{
    Screen = Window->WScreen->NextScreen;
    if (Screen && Screen->Width > 340) {
        ScreenToBack(Window->WScreen);
        ScreenToFront(Screen);
        CloseWindowCheck();
        OpenWindowCheck(Screen);
    } else
        AudioInform();
}

void OpenWindowCheck(NWS)
struct Screen *NWS;
{
    NewWindow.Screen = NWS;
    if ((Window = (struct Window *) OpenWindow(&NewWindow)) == NULL)
        DoThisCodeLast(RETURN_WARN);
}

void CloseWindowCheck()
{
    if (Window) {
	RemoveGList(Window, &CloseWindowGadget, -1L);
	CloseWindow(Window);
    }
}

void DoThisCodeFirst()
{
    register int count;

    if ((TimerPort = (struct MsgPort *) CreatePort(0L, 0L)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    if ((TimerIO = (struct IOStdReq *) CreateStdIO(TimerPort)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct StdIOReq *) TimerIO, 0L) > NULL)
	DoThisCodeLast(RETURN_WARN);
    TimerSignal = 1L << TimerPort->mp_SigBit;
    if ((DiskPort = (struct MsgPort *) CreatePort(0L, 0L)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    if ((DiskIO = (struct IOStdReq *) CreateStdIO((struct MsgPort *) DiskPort)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    for (count = 0; count < NUMUNITS; count++) {
	if (OpenDevice(TRACKDISKNAME, (long) count, (struct StdIOReq *) DiskIO, TDB_ALLOW_NON_3_5) > NULL)
	    DiskChange[count] = FALSE;
	else {
	    if (count == 0)
		DiskDevice = DiskIO->io_Device;
	    DiskIO->io_Command = TD_CHANGENUM;
	    DoIO(DiskIO);
	    DiskChange[count] = DiskIO->io_Actual;
	    CloseDevice(DiskIO);
	}
    }
    if ((ChipImageBlock = (USHORT *) AllocMem(1368L, MEMF_CHIP)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    movmem(ImageBlock, ChipImageBlock, 1368);
    ChangeDriveImage.ImageData = (USHORT *) (ChipImageBlock + 0L);
    ChangeDriveSelectImage.ImageData = (USHORT *) (ChipImageBlock + 40L);
    OnTopImage.ImageData = (USHORT *) (ChipImageBlock + 80L);
    OnTopSelectImage.ImageData = (USHORT *) (ChipImageBlock + 120L);
    DownUnderImage.ImageData = (USHORT *) (ChipImageBlock + 160L);
    DownUnderSelectImage.ImageData = (USHORT *) (ChipImageBlock + 200L);
    DragWindowImage.ImageData = (USHORT *) (ChipImageBlock + 240L);
    CloseWindowImage.ImageData = (USHORT *) (ChipImageBlock + 520L);
    CloseWindowSelectImage.ImageData = (USHORT *) (ChipImageBlock + 560L);
    JumpScreenImage.ImageData = (USHORT *) (ChipImageBlock + 600L);
    JumpScreenSelectImage.ImageData = (USHORT *) (ChipImageBlock + 640L);
    if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    if ((GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L)) == NULL)
	DoThisCodeLast(RETURN_WARN);
    OpenWindowCheck(IntuitionBase->FirstScreen);
}

void DoThisCodeLast(returncode)
long returncode;
{
    if (TimerPort) {
	Wait(TimerSignal);
	GetMsg(TimerPort);
	CloseDevice(TimerIO);
	DeleteStdIO(TimerIO);
	DeletePort(TimerPort);
    }
    if (DiskPort)
	DeletePort(DiskPort);
    if (DiskIO)
	DeleteStdIO(DiskIO);
    CloseWindowCheck();
    if (GfxBase)
	CloseLibrary(GfxBase);
    if (IntuitionBase)
	CloseLibrary(IntuitionBase);
    if (ChipImageBlock)
	FreeMem(ChipImageBlock, 1368L);
#ifndef A1000
    if (_Backstdout)
	Write(_Backstdout, EGOSTRING, EGOSTRLEN);
#endif
    exit(returncode);
}
