//	Utils.c

#ifndef __GNUC__
	#include <AppleEvents.h>
	#include <Processes.h>
	#include <Aliases.h>
#endif
	
#include "ADFS_LogFile.h"
#include "FSUtils.h"
#include "Carbon68kGlue.h"
#include "stdio.h"
#include "string.h"
#include "IC_Errors.h"
#include "Utils.h"

extern	EventRecord	gEvent;
Rect		gEmptyRect	= { 0, 0, 0, 0 };

unsigned char*	c2p(const char *strZ)
{
	static	unsigned char	bufA[256];
	
	CopyCStringToPascal(strZ, bufA);
	return bufA; 
}

Boolean		TrackMouse1(
	Rect *theRectPtr,
	void (*HilightProc)(Rect *theRect, void *data, Boolean in, Boolean Last),
	void (*TrackingProc)(void *data),
	void *data
) {
	Point		thePoint;
	Boolean		inLastTime = FALSE, inThisTime;

	if (!StillDown()) {			// mouse already up, assume we had a quick-click inside
		(*HilightProc)(theRectPtr, data, TRUE, FALSE);
		if (TrackingProc)
			(*TrackingProc)(data);
		(*HilightProc)(theRectPtr, data, FALSE, TRUE);
		return TRUE;
	}
	
	do {
		GetMouse(&thePoint);
		if ((inThisTime = PtInRect(thePoint, theRectPtr)) == TRUE) { /*=*/
			if (!inLastTime)
				(*HilightProc)(theRectPtr, data, inThisTime, FALSE);
			if (TrackingProc != NULL)
				(*TrackingProc)(data);
		} else
			if (inLastTime)
				(*HilightProc)(theRectPtr, data, inThisTime, FALSE);		
		inLastTime = inThisTime;
	} while (StillDown());

	if (inLastTime) {
		(*HilightProc)(theRectPtr, data, !inLastTime, TRUE);
		return(TRUE);
	} else
		return(FALSE);
}		

Boolean		TrackMouseRgn(
	RgnHandle	rgnH,
	void		(*HilightProc)(RgnHandle rgnH, void *data, Boolean in, Boolean Last),
	void		(*TrackingProc)(void *data),
	void		*data
) {
	Point		thePoint;
	Boolean		inLastTime = FALSE, inThisTime;

	if (!StillDown()) {			// mouse already up, assume we had a quick-click inside
		(*HilightProc)(rgnH, data, TRUE, FALSE);
		if (TrackingProc)
			(*TrackingProc)(data);
		(*HilightProc)(rgnH, data, FALSE, TRUE);
		return TRUE;
	}
	
	do {
		GetMouse(&thePoint);
		if ((inThisTime = PtInRgn(thePoint, rgnH)) == TRUE) { /*=*/
			if (!inLastTime)
				(*HilightProc)(rgnH, data, inThisTime, FALSE);
			if (TrackingProc != NULL)
				(*TrackingProc)(data);
		} else
			if (inLastTime)
				(*HilightProc)(rgnH, data, inThisTime, FALSE);		
		inLastTime = inThisTime;
	} while (StillDown());

	if (inLastTime) {
		(*HilightProc)(rgnH, data, !inLastTime, TRUE);
		return(TRUE);
	} else
		return(FALSE);
}		

/******************************************************************************
		DrawOnlyGrowIcon
 ******************************************************************************/
void	DrawOnlyGrowIcon(WindowPtr theWindow)
{
	Boolean		hasGrowIconB = FALSE;
 	
 	if (GetSystemVers() >= 0x0800) {
 		ulong		featuresL;
 		
 		if (GetWindowFeatures(theWindow, &featuresL) == noErr) {
 			hasGrowIconB = (featuresL & kWindowCanGrow) != 0;
 		}
 	} else {
		short	windowVariantS = GetWVariant(theWindow);
 		
 		hasGrowIconB = 
 			windowVariantS == zoomDocProc 
 			|| windowVariantS == documentProc;
 	}
 
	if (hasGrowIconB) {
		#define			rectSiz 15
		GrafPtr			savePort;
		Rect 			clippingRect;
		RgnHandle		tempRgn = NewRgn();

		if (theWindow && tempRgn) {
			GetPortBounds(GetWindowPort(theWindow), &clippingRect);
			clippingRect.left	= clippingRect.right	- rectSiz;
			clippingRect.top	= clippingRect.bottom	- rectSiz;
			GetPort(&savePort);		
			SetPortWindowPort(theWindow);

			GetClip(tempRgn);
			ClipRect(&clippingRect);
			DrawGrowIcon(theWindow);
			SetClip(tempRgn);
			
			DisposeRgn(tempRgn);
			
			SetPort(savePort);
		}
	}
}

/*********************************************************************************************
			Concat
 *********************************************************************************************/
void		Concat(uchar *srcStr1, uchar *srcStr2, uchar *dstString)
{
	int		i, offset;
	Str255	final;

	CopyString(srcStr1, final);
	offset = final[0];
	for (i = srcStr2[0]; i > 0; --i)
		if (offset + i < 256)
			final[offset + i] = srcStr2[i];
	final[0] = srcStr2[0] + offset;
	CopyString(final, dstString);
}

void		ConcatNumToString(void *srcStr1, long theNum, void *dstString)
{
	Str255	numStr, final;
	
	CopyString((uchar *)srcStr1, final);
	NumToString(theNum, (StringPtr)numStr);
	Concat(final, numStr, final);
	CopyString(final, (uchar *)dstString);
}

/*********************************************************************************************
			CopyString
 *********************************************************************************************/
void		CopyString(uchar *srcString, uchar *dstString)
{
	register	int		i;
	register	char	*src, *dst;

	src = (char *)srcString;
	dst = (char *)dstString;
	
	for (i = srcString[0]; i >= 0; --i)	{
		*dst = *src;
		++src;
		++dst;
	}
}

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

void		ShrinkString(void *buf, int space_for_string)
{
	TruncString(space_for_string, (unsigned char *)buf, truncEnd);
}

/*

unsigned char gElipses[4] = "\p...";
	#define	theString		((unsigned char *)buf)
	short	length			= theString[0];
	short	elipsCharWid	= CharWidth(tokenEllipsis);
	short	elipsStrWid		= StringWidth(gElipses);
	
	space_for_string += elipsCharWid - elipsStrWid;
	
	if (length > 0) {
		if (elipsStrWid > space_for_string || length < 3) {
			theString[0] = 0;
		} else if (TruncString(space_for_string, theString, truncMiddle) == smTruncated) {
			theString[0] += 2;
			memcpy(&theString[theString[0] - 3], &gElipses[1], 3);
		}
	}
	
	#undef theString
}

/*	unsigned	int	s_pix;
	unsigned	int	s_len;
	unsigned	int	e_len = StringWidth(gElipses);

	if (space_for_string <= 0)
	{
		space_for_string = 0;
		((StringPtr)theString)[0] = 0;
	}
	s_pix = StringWidth((StringPtr)theString);
	if (s_pix > space_for_string)
	{
		s_len = ((StringPtr)theString)[0];
		space_for_string -= e_len;
		if (space_for_string <= 0)
		{
			space_for_string = 0;
			((StringPtr)theString)[0] = 0;
		} else {
			for (
				s_len = ((StringPtr)theString)[0]; 
				s_len && s_pix >= space_for_string; 
				s_len--
			) {
				s_pix -= CharWidth(((StringPtr)theString)[s_len]);
			}
			
			((StringPtr)theString)[0] = s_len;
			Concat(theString, gElipses, theString);
		}
	}
}
*/

char	*ShrinkCString(char *buf, short width)
{
	CopyCStringToPascal(buf, (unsigned char *)buf);
	ShrinkString(buf, width);
	CopyPascalStringToC((unsigned char *)buf, buf);
	return buf;
}

/*
	short	length			= strlen(buf);
	short	elipsCharWid	= CharWidth(tokenEllipsis);
	short	elipsStrWid		= StringWidth(gElipses);
	short	result;
	
	result	= TruncText(width + elipsCharWid - elipsStrWid, buf, &length, truncEnd);
	
	if (result == smTruncated) {
		length += 2;
		buf[length] = 0;
		memcpy(&buf[length - 3], &gElipses[1], 3);
	} else if (result == smTruncErr) {
		buf[0] = 0;
	}

	return buf;
}
*/

char		*FormatWithCommas(ulong bytes, char *buf)
{
	short	strLen, numCommas, commaStart, srcChar, dstChar;
	char	sourceAC[256];
	
	sprintf(sourceAC, "%lu", bytes);
	strLen		= strlen(sourceAC);
	numCommas	= (strLen - 1) / 3;
	commaStart	= (strLen) % 3;
	if (commaStart == 0) {
		commaStart += 3;
	}
	
	for (dstChar = 0, srcChar = 0; srcChar < strLen; dstChar++, srcChar++) {
		if (commaStart-- == 0) {
			buf[dstChar++] = ',';
			commaStart = 3;
		}
		
		buf[dstChar] = sourceAC[srcChar];
	}

	buf[dstChar] = 0;
	return buf;
}

char		*FormatSize(ulong bytes, char *buf)
{
	if (bytes == 0) {
		strcpy(buf, "0 K");
	} else if (bytes < 1000) {
		sprintf(buf, "%d b", (int)bytes);
	} else if (bytes <= 1024) {
		strcpy(buf, "1 K");
	} else if (bytes < 10000) {
		sprintf(buf, "%.1f K", (float)bytes / 1024.0);
	} else {
		ulong	kilo = (bytes + 1) / 1024;
		
		if (kilo < 1000) {
			sprintf(buf, "%d K", (int)kilo);
		} else if (kilo <= 1024) {
			sprintf(buf, "1 MB", kilo);
		} else if (kilo < 10240) {
			sprintf(buf, "%.1f MB", (float)kilo / 1024.0);
		} else {
			ulong	megs = (kilo + 1) / 1024;

 			sprintf(buf, "%d MB", (int)megs);
		}
	}
	
	return buf;
}

#define		kTicksPerSecond		(double)(60.0)
#define		kTicksPerMinute		(double)(60.0 * kTicksPerSecond)
#define		kTicksPerHour		(double)(60.0 * kTicksPerMinute)

void	TicksToTime(
	ulong ticksUL, 
	short *hoursS, 
	short *minutesS, 
	short *secondsS)
{
	double		ticksD = ticksUL;
	
	*hoursS		= (short)((ticksD / kTicksPerHour));
	ticksD		-= (double)(*hoursS) * kTicksPerHour;
	ASSERT(ticksD < kTicksPerHour && ticksD >= 0);
	
	*minutesS	= (short)((ticksD / kTicksPerMinute));
	ticksD		-= (double)(*minutesS) * kTicksPerMinute;
	ASSERT(ticksD < kTicksPerMinute && ticksD >= 0);
	
	*secondsS	= (short)((ticksD / kTicksPerSecond));
	ticksD		-= (double)(*secondsS) * kTicksPerSecond;
	ASSERT(ticksD < kTicksPerSecond && ticksD >= 0);
}

char	*TimeToString(
	short	hoursS, 
	short	minutesS, 
	short	secondsS, 
	char	*buf)
{
	
	if (hoursS > 0) {
		
		if (minutesS < 2) {
			sprintf(buf, "About %d hour%s.", 
				(int)hoursS, (hoursS > 1) ? "s" : "");
		} else {
			sprintf(buf, "About %d hour%s and %d minutes.", 
				(int)hoursS, (hoursS > 1) ? "s" : "", (int)minutesS);
		}
	} else if (minutesS > 0) {
		if (secondsS < 2) {
			sprintf(buf, "About %d minute%s.", 
				(int)minutesS, (minutesS > 1) ? "s" : "");
		} else {
			sprintf(buf, "About %d minute%s and %d seconds.", 
				(int)minutesS, (minutesS > 1) ? "s" : "", (int)secondsS);
		}
	} else {
		if (secondsS == 0) {
			secondsS = 1;
		}
		
		sprintf(buf, "About %d second%s.", 
			(int)secondsS, (secondsS > 1) ? "s" : "");
	}
	
	return buf;
}

char	*FormatTicks(ulong ticksUL, char *buf)
{
	short	hoursS, minutesS, secondsS;
	
	TicksToTime(ticksUL, &hoursS, &minutesS, &secondsS);
	return TimeToString(hoursS, minutesS, secondsS, buf);
}

void	DrawCString(char *buf)
{
	DrawText(buf, 0, strlen(buf));
}

int			check_key_down(long key_mask)
{
	long	keys = 0;
	KeyMap	theKeys;
	
	GetKeys(theKeys);

	#if TARGET_RT_LITTLE_ENDIAN
		keys = Endian32_Swap(theKeys[1].bigEndianValue);
	#else
		keys = theKeys[1];
	#endif
	
	return (keys & key_mask) == key_mask;
}

char	Upcase(char c)
{
	if (c >= 'a' && c <= 'z')
		return	(char)(c - 'a' + 'A');
	else
		return(c);
}

char	VirtualASCII(EventRecord *eventP)
{
	static ulong 	state = 0;
	unsigned long	result = 0;
	ushort			keyCode;
	Handle			keyCharH;
	char			char1, char2;

//	keyCode =	((ushort)eventP->modifiers & 0xFF00)
//				| ((eventP->message & 0x00007F00) >> 8);

	//	do NOT include the modifiers, we want it unmodified
	keyCode =	(eventP->message & 0x00007F00) >> 8;
	
	keyCharH = GetResource('KCHR', 0);
	HLock((Handle)keyCharH);	

	result = KeyTranslate(*keyCharH, keyCode, &state);
	char1 = Upcase((result & 0x00FF0000) >> 16);
	char2 = Upcase((result & 0x000000FF) >> 0);
		
	HUnlock((Handle)keyCharH);

	return (char1 ? char1 : char2);
}

Boolean		MouseStateChanged(
	Point	start_pt, 
	long	timeout_ticksL, 
	short	pix_deltaS, 
	Boolean	*movedPB, 
	Boolean	*button_upPB)
{
	Boolean				state_changedB = FALSE;
	unsigned long		last_tickLu;
	
	if (timeout_ticksL < 0)
		timeout_ticksL = 60 * 60 * 60 * 24 * 30;		//	time out in one month
	
	last_tickLu = TickCount() + timeout_ticksL;

	#ifndef OLD68K
	if (Is_OS_X()) {
		MouseTrackingResult	result;
		OSStatus			err = noErr;
		Point				loc_pt = {0, 0};
		unsigned long		modifiersLu = 0;
		
		*button_upPB = *movedPB = FALSE;
		
		do {
			err = TrackMouseLocationWithOptions(
				NULL, 
				kTrackMouseLocationOptionDontConsumeMouseUp, 
				timeout_ticksL, 
				&loc_pt, &modifiersLu, &result);
		
			*button_upPB = ((err == noErr) && (result == kMouseTrackingMouseReleased));
			*movedPB = ((err == noErr) && (result == kMouseTrackingMouseMoved || result == kMouseTrackingMouseDragged));
			
			state_changedB = (*movedPB || *button_upPB);
		} while (!err && !state_changedB/* && TickCount() <= last_tickLu*/);
	} else {
	#endif
		Boolean		use_buttonB = (timeout_ticksL == -2);
		Point		thePoint;
		Rect		theRect			= PointToRect(start_pt, pix_deltaS, 1);
		
		do {
			GetMouse(&thePoint);
			*movedPB			= !MacPtInRect(thePoint, &theRect);
			
			if (use_buttonB) {
				*button_upPB		= !Button();
			} else {
				*button_upPB		= !StillDown();
			}

			state_changedB	= (*movedPB || *button_upPB);
		} while (!state_changedB && TickCount() <= last_tickLu);
	
	#ifndef OLD68K
	}
	#endif
	
	return(state_changedB);
}

Rect	PointToRect(Point thePoint, short size, short extra)
{
	Rect	theRect;
	
	theRect.left	= theRect.right		= thePoint.h;
	theRect.top		= theRect.bottom	= thePoint.v;
	MacInsetRect(&theRect, -size, -size);
	
	if (extra > 0) {
		theRect.right	+= extra;
		theRect.bottom	+= extra;
	} else {
		theRect.left	+= extra;
		theRect.top		+= extra;
	}
	
	return(theRect);
}

Boolean		MouseMoved(int direction)
{
	Point		thePoint;
	Boolean		movedB, buttonUpB;
	
	thePoint = gEvent.where;
	GlobalToLocal(&thePoint);

	MouseStateChanged(thePoint, -1, 2, &movedB, &buttonUpB);
	return movedB;
}
/*
	#define		thresh	2
	Point		thePoint;
	Rect		theRect;
	Boolean		moved, done;
	
	thePoint = gEvent.where;
	GlobalToLocal(&thePoint);

	if (direction & kTrackHorizontal) {
		theRect.left	= (short)(thePoint.h - thresh);
		theRect.right	= (short)(thePoint.h + thresh);
	} else {
		theRect.left	= -32000;
		theRect.right	= 32000;
	}

	if (direction & kTrackVertical) {
		theRect.top		= (short)(thePoint.v - thresh);
		theRect.bottom	= (short)(thePoint.v + thresh);
	} else {
		theRect.top		= -32000;
		theRect.bottom	= 32000;
	}
	
	do {
		GetMouse(&thePoint);
		moved	= (Boolean)!PtInRect(thePoint, &theRect);
		done	= (Boolean)!Button();
	} while (!(done || moved));
	
	return(moved);
}
*/



void		GlobalRectToLocal(GrafPtr portP, Rect *theRect)
{
	GrafPtr savePort;
	
	GetPort(&savePort);
	SetPort(portP);
	GlobalToLocal((Point *)(theRect));
	GlobalToLocal((Point *)&(theRect->bottom));
	SetPort(savePort);
}

void		LocalRectToGlobal(GrafPtr portP, Rect *theRect)
{
	GrafPtr savePort;
	
	GetPort(&savePort);
	SetPort(portP);
	LocalToGlobal((Point *)(theRect));
	LocalToGlobal((Point *)&(theRect->bottom));
	SetPort(savePort);
}

void	OpenClipRect(void)
{
	Rect	clipRect	= { -32767, -32767, 32767, 32767 };
	
	ClipRect(&clipRect);
}

void	TEGetSelect(
	TEHandle	hTE, 
	long		*selStart,
	long		*selEnd)
{
	*selStart	= (**hTE).selStart;
	*selEnd		= (**hTE).selEnd;
}

void	TESetFont(
  short              mode,
  const TextStyle *  newStyle,
  Boolean            fRedraw,
  TEHandle           hTE)
{
	FontInfo		fontInfo;	

	if (mode & doFont) {
		(**hTE).txFont = newStyle->tsFont;
		TextFont(newStyle->tsFont);
	}
	
	if (mode & doFace) {
		(**hTE).txFace = newStyle->tsFace;
		TextFace(newStyle->tsFace);
	}
	
	if (mode & doSize) {
		(**hTE).txSize = newStyle->tsSize;
		TextSize(newStyle->tsSize);
	}
	
	if (mode & doMode) {
		(**hTE).txMode = *(short *)&(newStyle->tsColor);
		TextMode(srcCopy);
	}
	
	GetFontInfo(&fontInfo);
	(**hTE).lineHeight = fontInfo.ascent + fontInfo.descent;
	(**hTE).fontAscent = fontInfo.ascent;

	if (fRedraw) {
		TEUpdate(&(**hTE).viewRect, hTE);
	}
}

ushort		CStringWidth(char *buf)
{
	ushort	width;
	
	CopyCStringToPascal(buf, (unsigned char *)buf);
	width = StringWidth((unsigned char *)buf);
	CopyPascalStringToC((unsigned char *)buf, buf);
	
	return width;
}

void		MeasureCString(char *buf, Rect *theRect)
{
	CFStringRef		stringRef = NULL;
	short			baselineS;
	Point			boundsPt;
	
	stringRef = CFStringCreateWithCString(NULL, buf, kTextEncodingMacRoman);

	(void)GetThemeTextDimensions(
		stringRef, kThemeCurrentPortFont, 
		kThemeStateActive, FALSE, &boundsPt, &baselineS);
	
	theRect->right = theRect->left + boundsPt.h + 1;
	theRect->bottom = theRect->top + boundsPt.v;
	
	CFRelease(stringRef);
}

void		DrawCStringInRect(char *buf, Rect *theRect, short justifyS)
{
	short			mode = GetPortTextMode((CGrafPtr)GetQDGlobalsThePort());
	CFStringRef		stringRef = NULL;
	
	stringRef = CFStringCreateWithCString(NULL, buf, kTextEncodingMacRoman);

	#ifndef __68k__
		if (mode != srcOr) {
			EraseRect(theRect);
		}
	#endif
	
	(void)DrawThemeTextBox(
		stringRef, kThemeCurrentPortFont, 
		kThemeStateActive, TRUE, theRect, 
		justifyS, NULL);
	
	CFRelease(stringRef);
}
/*
	short			maxWidth	= theRect->right - theRect->left;
	char			origStr[256];
	char			workStr[256], *pos;
	unsigned char	*strP		= (unsigned char *)workStr;
	short			nextStrInd, vPos;
	FontInfo		fontInfo;
	
	GetFontInfo(fontInfo);
	vPost = theRect->top + fontInfo.leading + fontInfo.ascent;
	
	while (workStr[0] != 0) {
		while (CStringWidth(workStr) > maxWidth) {
			pos = strrchr(workStr, ' ');

			if (pos) {
				nextStrInd	= pos - workStr;
				*pos	= 0;
			} else {
				workStr[strlen(workStr) - 1] = 0;
			}
		}
		
		c2pstr(workStr);
		MoveTo(theRect->left, vPos);
		DrawString(strP);
		vPos += fontInfo.leading + fontInfo.ascent + fontInfo.descent;
	}
}
*/

Boolean		StillDown_Loop(void)
{
	Boolean	still_downB = FALSE;
	
	if (Is_OS_X()) {
		MouseTrackingResult		result = kMouseTrackingMousePressed;
		Point					loc_pt = {0, 0};
		OSStatus				err = noErr;
		unsigned long			modifiersLu = 0;
		
		err = TrackMouseLocationWithOptions(
			NULL, 
			kTrackMouseLocationOptionDontConsumeMouseUp, 
			kEventDurationForever, 
			&loc_pt, &modifiersLu, &result);
		
		still_downB = ((err == noErr) && (result != kMouseTrackingMouseReleased));
	} else {
		still_downB = StillDown();
	}
	
	return still_downB;
}	

void		WaitNTicks(long ticks)
{
	#ifdef OLD68K
		long	dummy;
	#else
		ulong	dummy;
	#endif
	
	Delay((unsigned long)ticks, &dummy);
}

#ifdef __GNUC__
OSStatus		FSrGetResourceFolder(FSRef *fsRefP)
{
	OSStatus		err = noErr;
	CFBundleRef     myAppBundle(CFBundleGetMainBundle());

	if ((CFBundleRef)myAppBundle) {
		CFURLRef	myAppResourcesURL(
			CFBundleCopyResourcesDirectoryURL(myAppBundle));

		if (myAppResourcesURL) {
			if (!CFURLGetFSRef(myAppResourcesURL, fsRefP)) {
				err = fnfErr;
			}
		}
		
		CFRelease(myAppResourcesURL);
	}
	
	return err;
}

OSErr			FSrMakeFSSpec(
	const FSRef		&fileRef, 
	FSSpec			*specP)
{
	return FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, specP, NULL);
}
#endif

OSStatus		FSpGetResourceFolder(FSSpec *fsSpecP)
{
	OSStatus		err = noErr;
	
	#ifdef __GNUC__
		FSRef			fsRef;
		
		ERR(FSrGetResourceFolder(&fsRef));
		ERR(FSrMakeFSSpec(fsRef, fsSpecP));
	#else
		ERR(FSpThisApp(fsSpecP));
	#endif

	return err;
}


#define		kFontName	"Apple ]["
FMFontFamily		GetAppFonts(short column_widthS)
{
	FMFontFamily			return_font		= systemFont;
	static	FMFontFamily	sFont40			= systemFont;
	static	FMFontFamily	sFont80			= systemFont;

	if (
		column_widthS		== 40
		|| column_widthS	== 80
	) {
		if (sFont40 == systemFont) {
			OSStatus			err = noErr;

			#ifndef __68k__
				if (Is_OS_X()) {
					FSSpec					myFSSpec;
					
					err = FSpGetResourceFolder(&myFSSpec);
					
					if (!err) {
						ADFS_Log("activating Apple II fonts\n");
						err = FMActivateFonts(&myFSSpec, NULL, NULL, kFMDefaultOptions);
						if (err) AlertID("Error activating " kFontName " font: ", err);
					}
				}
			#endif
			
			if (!err) {
				ADFS_Log("about to get font IDs\n");
				sFont40 = FMGetFontFamilyFromName("\p" kFontName " 40 Column");
				sFont80 = FMGetFontFamilyFromName("\p" kFontName " 80 Column");
			}
			
			if (err || sFont40 < 0) {
				sFont40 = kFontIDMonaco;
				sFont80 = kFontIDMonaco;
			}

			ADFS_Log("got fonts\n");
		}
		
		if (column_widthS == 40) {
			return_font = sFont40;
		} else {
			return_font = sFont80;
		}
	} else {
		AlertID("Error specifying " kFontName " column width: ", column_widthS);
	}

	return return_font;
}

ushort		GetSystemVers(void)
{
	long	result;
	ushort	version = 0x0600;
	
	if (Gestalt(gestaltSystemVersion, &result) == noErr) {
		version = (ushort)result & 0x0000FFFF;
	}
	
	return version;
}

ushort		GetInterfaceVers(void)
{
	ushort	version = 0x0710;
	
	#ifndef __68k__
		long	result;

		if (Gestalt(gestaltCarbonVersion, &result) == noErr) {
			version = (ushort)result & 0x0000FFFF;
		}
	#else
		version = GetSystemVers();
	#endif
	
	return version;
}

Boolean	Is_OS_X(void)
{
	return GetSystemVers() >= 0x1000;
}

static		Boolean		g_isDraggingB = FALSE;
void		SetDragging(Boolean isDraggingB)
{
	g_isDraggingB = isDraggingB;
	QuietErrors(isDraggingB);
}

Boolean		IsDragging(void)
{
	return g_isDraggingB;
}

void		GetCurFontRec(ADFS_FontRec *fontRecP)
{
	CGrafPtr		thePort;
	
	GetPort((GrafPtr *)&thePort);
	
	fontRecP->fontID	= GetPortTextFont(thePort);
	fontRecP->fontSize	= GetPortTextSize(thePort);
	fontRecP->fontFace	= GetPortTextFace(thePort);
	fontRecP->fontMode	= GetPortTextMode(thePort);
}

void		GetSysFontRec(ADFS_FontRec *fontRecP)
{
	fontRecP->fontID		= systemFont;
	fontRecP->fontSize		= 12;
	fontRecP->fontFace		= normal;
	fontRecP->fontMode		= srcCopy;
}

void		GetSmallFontRec(ADFS_FontRec *fontRecP)
{
	fontRecP->fontID		= FMGetFontFamilyFromName("\pGeneva");
	fontRecP->fontSize		= 9;
	fontRecP->fontFace		= normal;
	fontRecP->fontMode		= srcCopy;	
}

void		SetFontRec(ADFS_FontRec *fontRecP)
{
	TextFont(fontRecP->fontID);
	TextSize(fontRecP->fontSize);
	TextFace(fontRecP->fontFace);
	TextMode(fontRecP->fontMode);
}

void		SetStandardCursor(short cursorID)
{
	Cursor		cursorRec;
	
	if (Button()) {
		cursorID = arrowCursor;
	}
	
	switch (cursorID) {
		
		default:
		case arrowCursor: {
			GetQDGlobalsArrow(&cursorRec);
			break;
		}
		
		case iBeamCursor:
		case crossCursor:
		case plusCursor:
		case watchCursor: {
			cursorRec = **GetCursor(cursorID);
			break;
		}
	}

	SetCursor(&cursorRec);
}

static	Rect		InBetweenRect(Rect *start, Rect *end, int frame, int total)
{
	double	t_1, t_2;
	Rect	result;
	
	t_1 = (double)frame / total;
	t_1 *= t_1;
	t_2 = 1 - t_1;
	result.left		= (short)(t_2 * start->left		+ t_1 * end->left);
	result.right	= (short)(t_2 * start->right	+ t_1 * end->right);
	result.top		= (short)(t_2 * start->top		+ t_1 * end->top);
	result.bottom	= (short)(t_2 * start->bottom	+ t_1 * end->bottom);
	return(result);
}

void	FlushCurPort(void)
{
	#ifndef __68k__
		GrafPtr		portP;
		
		GetPort(&portP);
		QDFlushPortBuffer(portP, NULL);
	#endif
}

void		ZoomRect(Rect *start, Rect *end)
{
	#define		total		8
	short		frame;
	Rect		newRect, oldRect = {	0, 0, 0, 0	};
	PenState	savePen;
	
	GetPenState(&savePen);
	PenSize(1, 1);
	PenMode(srcXor);
	
	for (frame = 1; frame <= total; frame++) {
		newRect = InBetweenRect(start, end, frame, total);
		FrameRect(&newRect);
		FrameRect(&oldRect);
		FlushCurPort();
		WaitNTicks(1);

		oldRect = newRect;
	}

	FrameRect(&oldRect);
	FlushCurPort();
		
	SetPenState(&savePen);
}

short		CompareCString(char *strA, char *strB)
{
	return CompareText(strA, strB, strlen(strA), strlen(strB), NULL);
}

short		ComparePString(uchar *strA, uchar *strB)
{
	return CompareText(&strA[1], &strB[1], strA[0], strB[0], NULL);
}

long		CompareTime(DateTimeRec *dtA, DateTimeRec *dtB)
{
	ulong	secsA, secsB;
	
	DateToSeconds(dtA, &secsA);
	DateToSeconds(dtB, &secsB);
	
	return secsA - secsB;
}

void		DrawTriangle(QD_TriangleType type, Rect *rectP)
{
	Point		pointsA[3];
	PolyHandle	polyH = OpenPoly();
	
	rectP->right--;
	rectP->bottom--;
	
	switch (type) {

		case QD_Triangle_UP: {
			pointsA[0].h = rectP->left;
			pointsA[0].v = rectP->bottom;
			pointsA[1].h = (rectP->right + rectP->left) / 2;
			pointsA[1].v = rectP->top;
			pointsA[2].h = rectP->right;
			pointsA[2].v = rectP->bottom;
			break;
		}

		case QD_Triangle_DOWN: {
			pointsA[0].h = rectP->left;
			pointsA[0].v = rectP->top;
			pointsA[1].h = (rectP->right + rectP->left) / 2;
			pointsA[1].v = rectP->bottom;
			pointsA[2].h = rectP->right;
			pointsA[2].v = rectP->top;
			break;
		}

		case QD_Triangle_RIGHT: {
			pointsA[0].h = rectP->left;
			pointsA[0].v = rectP->top;
			pointsA[1].h = rectP->right;
			pointsA[1].v = (rectP->top + rectP->bottom) / 2;
			pointsA[2].h = rectP->left;
			pointsA[2].v = rectP->bottom;
			break;
		}

		case QD_Triangle_LEFT: {
			pointsA[0].h = rectP->right;
			pointsA[0].v = rectP->top;
			pointsA[1].h = rectP->left;
			pointsA[1].v = (rectP->top + rectP->bottom) / 2;
			pointsA[2].h = rectP->right;
			pointsA[2].v = rectP->bottom;
			break;
		}
	}
	
	MoveTo(pointsA[0].h, pointsA[0].v);
	LineTo(pointsA[1].h, pointsA[1].v);
	LineTo(pointsA[2].h, pointsA[2].v);
	LineTo(pointsA[0].h, pointsA[0].v);
	
	ClosePoly();
	
	PaintPoly(polyH);
	KillPoly(polyH);
}

/**************************************************/
Boolean		IsADFS(void)
{
	#ifdef __ROSE__
		return FALSE;
	#else
		return TRUE;
	#endif
}

//static	SpeechChannel	g_speech_chan = NULL;

void	SpeakCString(char *strZ, long lengthL)
{
//	OSErr			err = noErr;

//	if (!g_speech_chan) {
//		if (!err) err = NewSpeechChannel(NULL, &g_speech_chan);
//	}
	
//	if (!err) err = SpeakText(g_speech_chan, strZ, lengthL ? lengthL : strlen(strZ));
}

void	Idle_DisposeSpeechChannel(Boolean forceB)
{
//	if (g_speech_chan) {
//		if (forceB || !SpeechBusy()) {
//			(void)StopSpeech(g_speech_chan);
//			(void)DisposeSpeechChannel(g_speech_chan);
//			g_speech_chan = NULL;
//		}
//	}
}