/***
 * SpinCursor.c - code to diplay a spin cursor
 *
 * This code should be used like this
 * ----------------------------------
 *
 * #include "SpinCursor.h"
 *
 *		StartSpinning(id);		must call to start
 *		...
 *
 *		StopSpinning();			must call it when done
 *
 ***/

#include "SpinCursor.h"
#include <Retrace.h>
//#include <SysEqu.h>
// There is a conflict between LoMem.h and SysEqu.h.  So, we
// cheated and copied this line out of SysEqu.h.  It's not like
// this is going to change or something.
enum {
 CrsrBusy = 0x8CD				/*[GLOBAL VAR]  Cursor locked out? [byte]*/
};

#define kInterval 6
#define kInitialDelay 120

pascal long GetVBLRec(void) = {0x2e88};

typedef struct {
	VBLTask			vblTask;
	short			num_cursors;
	short			index;
	CursHandle		frames[10];
} CursorTask;

typedef struct {
	short			num_cursors;
	short			index;
	CursHandle		frames[10];
} **AcurHdl;


static CursorTask gCursors;
static Boolean	  gInstalled = false;

/*----------------------------------------------------------------------------+
|	LoadSpinning                                                                |
+----------------------------------------------------------------------------*/
void LoadSpinning(short id)
{
short frame;
AcurHdl acur;
short i;

	gInstalled = false;
	gCursors.num_cursors = -1;
	acur = (AcurHdl) Get1Resource('acur', id);
	if (acur == NULL)
		return;

	/* Preload all cursors we will use */
	if( acur ) {
		HLockHi((Handle)acur);

		gCursors.num_cursors = (*acur)->num_cursors;
		if (gCursors.num_cursors > 10) {
			HUnlock((Handle)acur);
			ReleaseResource((Handle)acur);
			return;
			gCursors.num_cursors = -1;
		}

		gCursors.index = 0;
		for( i = 0; i < gCursors.num_cursors; i++ ) {

			frame = (short) ((long) (*acur)->frames[i] >> 16) & 0xFFFF;
			gCursors.frames[i] = GetCursor(frame);
			if (gCursors.frames[i]) {
				HLockHi((Handle)gCursors.frames[i]);
			}
		}
		
		HUnlock((Handle)acur);
		ReleaseResource((Handle)acur);
	}

}

/*----------------------------------------------------------------------------+
|	ChangeCursor                                                                |
+----------------------------------------------------------------------------*/

pascal void	ChangeCursor(void)
{
CursorTask *ptr;

	ptr = (CursorTask *)GetVBLRec();

	if ((ptr->num_cursors > 0) && (!(*(Boolean *)CrsrBusy)) &&
		(ptr->frames[ptr->index] != NULL)) {
		SetCursor((Cursor *)*ptr->frames[ptr->index]);
		ptr->index++;
		if (ptr->index == ptr->num_cursors)
			ptr->index = 0;
	}
	ptr->vblTask.vblCount = kInterval;
}

/*----------------------------------------------------------------------------+
|	StartSpinning                                                                |
+----------------------------------------------------------------------------*/

Boolean StartSpinning(void)
{
OSErr err;

	gInstalled = false;
	ShowCursor();
	if (gCursors.num_cursors < 0)
		return false;

	gCursors.index = 1;
	gCursors.vblTask.qType = vType;
	gCursors.vblTask.vblAddr = ChangeCursor;
	gCursors.vblTask.vblCount = kInitialDelay;
	gCursors.vblTask.vblPhase = 0;

	err = VInstall((QElemPtr)&gCursors.vblTask);
	if (err == noErr)
		gInstalled = true;

	return err == noErr;
}

/*----------------------------------------------------------------------------+
|	StopSpinning                                                                 |
+----------------------------------------------------------------------------*/
void StopSpinning()
{
OSErr err;
short i;

	if (!gInstalled)
		return;

	err = VRemove((QElemPtr)&gCursors.vblTask);

	for (i = 0; i < gCursors.num_cursors; i++) {
		HUnlock((Handle)gCursors.frames[i]);
		ReleaseResource((Handle)gCursors.frames[i]);
	}

	InitCursor();
	gInstalled = false;
}
