//		DeviceManager.c

#include "ADFS_Prefs.h"
#include "offscreen_manager.h"
#include "DeviceManager.h"
#include "Utils.h"


Rect		GetGlobalWindowRect(WindowPtr theWindow)
{
	Rect		theRect;
	GrafPtr		windowPortP = (GrafPtr)GetWindowPort(theWindow);
	GrafPtr		savePortP;
	
	GetPort(&savePortP);
	SetPort(windowPortP);
	
	GetPortBounds((CGrafPtr)windowPortP, &theRect);
	LocalRectToGlobal(windowPortP, &theRect);

	SetPort(savePortP);

	return theRect;
}

int 		WindowScreenDepth(WindowPtr theWindow, int depthType)
{											
	Rect		theRect = GetGlobalWindowRect(theWindow);
	
	return(RectDepth(&theRect, depthType));
}

int			RectDepth(Rect *theRect, int depthType)
{
	int			targetDepth;

	if ((**gPrefsH).blackAndWhiteB) {
		targetDepth = 1;
	} else {
		GDHandle	theDevice;
		Rect		dRect, dummyRect;
		int			currentDepth;
		
		targetDepth = depthType == kMinDepth ? 32 : 1;
		
		FOR_EACH_OKAY_GDEVICE(theDevice) {

			dRect = (*theDevice)->gdRect;
			
			if (SectRect(&dRect, theRect, &dummyRect)) {
				
				currentDepth = (**(**theDevice).gdPMap).pixelSize;
				
				if (depthType == kMinDepth) {
					if (currentDepth < targetDepth)
						targetDepth = currentDepth;
				} else {
					if (currentDepth > targetDepth)
						targetDepth = currentDepth;
				}
			}
		}
	}

	return targetDepth;
}

void			WalkIntersectingDevices(
	WindowPtr theWindow, 
	void (*Callback)(Rect *theRect, short depth, void *callbackData),
	void *callbackData
) {
	GDHandle	theDevice;
	Rect		windowRect, deviceRect, sectRect;
	short		deviceDepth;
	
	if (*Callback != NULL) {
		GrafPtr		windowPortP = (GrafPtr)GetWindowPort(theWindow);

		windowRect = GetGlobalWindowRect(theWindow);
		
		FOR_EACH_OKAY_GDEVICE(theDevice) {
		
			deviceRect = (**theDevice).gdRect;
		
			if (SectRect(&windowRect, &deviceRect, &sectRect)) {
				GlobalRectToLocal(windowPortP, &sectRect);
				
				deviceDepth = (**(**theDevice).gdPMap).pixelSize;
				(*Callback)(&sectRect, deviceDepth, callbackData);
			}
		}
	}
}					


	/* Returns ctabSeed for any given window */
long		GetMaxCTabSeed(WindowPtr theWindow)
{
	Rect		theRect		= GetGlobalWindowRect(theWindow);
	GDHandle	theDevice	= GetMaxDevice(&theRect);

	return( (**(**(**theDevice).gdPMap).pmTable).ctSeed );
}

/* Returns CTabHandle	*/
CTabHandle	GetMaxCTabHandle(WindowPtr theWindow)
{											
	Rect		theRect		= GetGlobalWindowRect(theWindow);
	GDHandle	theDevice	= GetMaxDevice(&theRect);

	return( (*(*theDevice)->gdPMap)->pmTable );
}


void	CenterWindowToMainDevice(WindowPtr  whichWindow)
{
	Rect	moveRect = GetGlobalWindowRect(whichWindow);
	
	CenterRectToMainDevice(&moveRect);
	MoveWindow(whichWindow, moveRect.left, moveRect.top, FALSE);
}

void	CenterRectToMainDevice(Rect  *theRect)
{

	Rect		mainRect, newRect;
	GDHandle	mainDevice;
	
	mainDevice = GetMainDevice();
	mainRect = (**mainDevice).gdRect;
	
	/**  Center the rect 1/3 down from the menu bar.  **/
	
	newRect.left = mainRect.left + ((mainRect.right - mainRect.left) - 
				   (theRect->right - theRect->left)) / 2;
	newRect.right = newRect.left + (theRect->right - theRect->left);
	newRect.top = mainRect.top + ((mainRect.bottom - mainRect.top) -
				  (theRect->bottom - theRect->top)) / 3;
	newRect.bottom = newRect.top + (theRect->bottom - theRect->top);

	*theRect = newRect;
}


Rect			ReturnLowestBitRect()
{
	GDHandle	lowestBitDevice;
	Rect		lowestBitRect;
	lowestBitDevice = ReturnLowestBitDevice();
	lowestBitRect = (**lowestBitDevice).gdRect;
	if (lowestBitDevice == GetMainDevice())
		lowestBitRect.top += GetMBarHeight();
	return(lowestBitRect);
}

Rect		ReturnMainDeviceRect(void)
{
	GDHandle	mainDevice	= GetMainDevice();
	Rect		mainRect	= (*mainDevice)->gdRect;
	
	mainRect.top += GetMBarHeight();
	return(mainRect);
}

Rect		ReturnHighestBitRect()
{
	GDHandle	highestBitDevice;
	Rect		highestBitRect;
	highestBitDevice = ReturnHighestBitDevice();
	highestBitRect = (**highestBitDevice).gdRect;
	if (highestBitDevice == GetMainDevice())
		highestBitRect.top += GetMBarHeight();
	return(highestBitRect);
}

GDHandle		ReturnHighestBitDevice()
{
	int			bestRating, aRating;
	GDHandle	aDevice, bestDevice;

	/**  If all else fails, use the menu bar device.  **/

	bestDevice = GetMainDevice();
	bestRating = get_device_rating(bestDevice);
	
	FOR_EACH_GDEVICE(aDevice) {

		aRating = get_device_rating(aDevice);

		/**
		 **  Only count this device if it's valid (i.e., active and a screen device)
		 **  and if it's a higher rating than the previously considered best.
		 **/

		if((aRating >= 0) && (aRating > bestRating)) {
			bestRating = aRating;
			bestDevice = aDevice;
		}
	}
	
	return(bestDevice);
}

//	theRect in global coordinates
GDHandle	GetEnclosingDevice(Rect *theRect)
{
	Rect		sectRect, deviceRect;
	GDHandle	curDevice, bestDevice = NULL;
	long		curArea, bestArea = 0;

	FOR_EACH_OKAY_GDEVICE(curDevice) {

		deviceRect = (*curDevice)->gdRect;

		if (SectRect(&deviceRect, theRect, &sectRect)) {

			curArea = ((long)(sectRect.bottom - sectRect.top)
			  * (long)(sectRect.right - sectRect.left)
			);

			if (curArea > bestArea) {
				bestArea	= curArea;
				bestDevice	= curDevice;
			}
		}
	}

	return(bestDevice);
}


Rect			ReturnEnclosingDeviceRect(Rect *theRectPtr)
{
	GDHandle	theDevice	= GetEnclosingDevice(theRectPtr);
	Rect		deviceRect	= { 0, 0, 0, 0 };
	
	if (theDevice) {
		deviceRect = (*theDevice)->gdRect;

		deviceRect.top += 19;	/* Offset for drag bar */

		if (theDevice == GetMainDevice())
			deviceRect.top += GetMBarHeight();
	}

	return(deviceRect);
}

short		GetEnclosingDeviceDepth(Rect *theRect)
{
	GDHandle	theDevice	= GetEnclosingDevice(theRect);
	short		deviceDepth	= 0;
	
	if (theDevice) {
		deviceDepth = (**(**theDevice).gdPMap).pixelSize;
	}

	return(deviceDepth);
}

Boolean		DeviceOkay(GDHandle theDevice)
{
	return(		TestDeviceAttribute(theDevice, screenDevice)
			&&	TestDeviceAttribute(theDevice, screenActive));
}

GDHandle		ReturnLowestBitDevice()
{
	int			bestRating, aRating;
	GDHandle	aDevice, bestDevice;

	/**  If all else fails, use the menu bar device.  **/

	bestDevice = GetMainDevice();
	bestRating = get_device_rating(bestDevice);
	
	FOR_EACH_GDEVICE(aDevice) {
	
		aRating = get_device_rating(aDevice);

		/**
		 **  Only count this device if it's valid (i.e., active and a screen device)
		 **  and if it's a lower rating than the previously considered lowest.
		 **/

		if((aRating >= 0) && (aRating < bestRating)) {
			bestRating = aRating;
			bestDevice = aDevice;
		}
	}

	return(bestDevice);

}

Boolean		WindowOIsOffDeskTop(WindowPtr theWindow)
{
	Rect		windRect = GetGlobalWindowRect(theWindow);

	return(RectIsOffDeskTop(&windRect));
}

Boolean		RectIsOffDeskTop(Rect *theRect)
{
	Boolean			isOffDesktop;
	GDHandle		theDevice;
	Rect			dRect;
	RgnHandle		rectRgn		= NewRgn();
	RgnHandle		deviceRgn	= NewRgn();
	int				area;
	
	FOR_EACH_OKAY_GDEVICE(theDevice) {
		dRect = (*theDevice)->gdRect;
		RectRgn(rectRgn, &dRect);
		UnionRgn(rectRgn, deviceRgn, deviceRgn);
	}

	RectRgn(rectRgn, theRect);
	SectRgn(deviceRgn, rectRgn, rectRgn);
	
	GetRegionBounds(rectRgn, &dRect);
	area = (dRect.right - dRect.left) * (dRect.bottom - dRect.top);
	isOffDesktop = area < 128;

	DisposeRgn(rectRgn);
	DisposeRgn(deviceRgn);
	return(isOffDesktop);
}

Boolean		RectOnScreen(Rect *theRect)
{
	Boolean			isOnDesktop;
	GDHandle		theDevice, mainDevice;
	Rect			devRect, sectRect;
	
	isOnDesktop	= FALSE;
	mainDevice	= GetMainDevice();
	
	FOR_EACH_OKAY_GDEVICE(theDevice) {

		devRect = (*theDevice)->gdRect;
		if (mainDevice == theDevice)
			devRect.top += GetMBarHeight();
		
		SectRect(theRect, &devRect, &sectRect);
		
		if (EqualRect(&sectRect, theRect))
			isOnDesktop = TRUE;
	}
	
	return(isOnDesktop);
}

Rect		GetMBarRect(void)
{
	Rect	theRect;
	
	theRect.top		= 0;
	theRect.left	= 0;
	theRect.bottom	= GetMBarHeight();
	theRect.right	= (**GetMainDevice()).gdRect.right;
	
	return(theRect);
}

Boolean		WindowOnScreen(WindowPtr theWindow)
{
	Boolean			onScreenB = FALSE;
	RgnHandle		theRgn = NewRgn();
	Rect			windRect;
	
	if (theRgn) {
		GetWindowRegion(theWindow, kWindowStructureRgn, theRgn);
		
		GetRegionBounds(theRgn, &windRect);
		
		onScreenB = RectOnScreen(&windRect);
		
		DisposeRgn(theRgn);
	}
	
	
	return onScreenB;
}


int			get_device_rating(GDHandle theDevice)
{
	int		rating;
	
	if (!DeviceOkay(theDevice))
		rating = -1;
	else	{
		switch ((**theDevice).gdType)	{
			case directType:		/* assuming that we are dealing with a 24 bit board */
				rating = 10;
				break;
			case fixedType:
				rating = 0;			/* what is a fixed device anyways? */
				break;
			case clutType:
				switch (((**theDevice).gdFlags & 1) * 128 + (**(**theDevice).gdPMap).pixelSize) {
				
				case 1: rating = 1;			/* 1-bit monochrome */
					break;
				case 129: rating = 2;		/* 1-bit color */
					break;
				case 2: rating = 3;			/* 2-bit monochrome */
					break;
				case 130: rating = 4;		/* 2-bit color */
					break;
				case 4: rating = 5;			/* 4-bit monocrhome */
					break;
				case 8: rating = 6;			/* 8-bit monochrome */
					break;
				case 132: rating = 7;		/* 4-bit color */
					break;
				case 136: rating = 8;		/* 8-bit color */
					break;
				}
				break;
			default:
				rating = 0;
				break;
		}
	}
	return(rating);
}

Rect		GetDesktopRect(void)
{
	GDHandle		theDevice;
	Rect			desktopRect, dRect;
	RgnHandle		rectRgn		= NewRgn();
	RgnHandle		deviceRgn	= NewRgn();
	
	FOR_EACH_OKAY_GDEVICE(theDevice) {
		dRect = (*theDevice)->gdRect;
		RectRgn(rectRgn, &dRect);
		UnionRgn(rectRgn, deviceRgn, deviceRgn);
	}

	GetRegionBounds(deviceRgn, &desktopRect);

	DisposeRgn(rectRgn);
	DisposeRgn(deviceRgn);

	return(desktopRect);
}
