//	CWindow.c

#ifndef __GNUC__
	#include <Drag.h>
#endif

#include <string.h>
#include "IC_Errors.h"
#include "Utils.h"
#include "ADFS_Commands.h"
#include "Carbon68kGlue.h"
#include "CRenameTextEdit.h"
#include "CWindow.h"


ADFS_FontRec	gFontRec = { "\pGeneva", kFontIDGeneva, 9, normal, srcCopy };

static	DragTrackingHandlerUPP		DragTrackUPP	= NULL;
static	DragReceiveHandlerUPP		DragReceiveUPP	= NULL;

Boolean		CWindow::IWindow(ADFS_WindowType windowType)
{
	Boolean		success	= TRUE;
	
	i_windowType		= windowType;
	i_trackInstalled	= FALSE;
	i_receiveInstalled	= FALSE;
	i_dragCanAccept		= FALSE;
	i_frameRgn			= NULL;
	i_renameTE			= NULL;
	
	#ifdef OLD68K
	i_dirtyB			= FALSE;
	#endif

	if (success && DragTrackUPP == NULL) {
		DragTrackUPP	= NewDragTrackingHandlerUPP(DragTrackCB);
		DragReceiveUPP	= NewDragReceiveHandlerUPP(DragReceiveCB);
		success = DragTrackUPP != NULL && DragReceiveUPP != NULL;
	}
	
	if (success) {
		if (i_windowType >= ADFS_Window_FINDER || i_windowType == ADFS_Window_GENERATOR) {
		
			success = InstallTrackingHandler(DragTrackUPP, GetWindowRef(), this) == noErr;
			if (success) {
				i_trackInstalled = TRUE;

				success = InstallReceiveHandler(DragReceiveUPP, GetWindowRef(), this) == noErr;
				if (success) {
					i_receiveInstalled = TRUE;
				}
			}
		}
	}

	if (success) {
		i_clipRgn = NewRgn();
		success = i_clipRgn != NULL;
	}
	
	if (success) {
		gFontRec.fontID = FMGetFontFamilyFromName(gFontRec.fontName);
		
		SetPort(GetGrafPtr());
		UpdateFontInfo(&gFontRec);

		i_magic				= kCWindowMagic;
		i_invalid			= TRUE;

		SetWRefCon(GetWindowRef(), (long)this);
	}
	
	if (!success) {
		ReportErrorStr(-1, "Error allocating CWindow stuff");
	} else {
		Rect	rectR = GetSizeRect();
		
		SetDirty(FALSE);
		SetSizeRect(&rectR);
	}

	return success;
}

void		CWindow::Dispose(void)
{
	if (i_clipRgn) {
		DisposeRgn(i_clipRgn);
	}
	
	if (GetWindowRef()) {

		if (i_trackInstalled) {
			RemoveTrackingHandler(DragTrackUPP, GetWindowRef());
		}

		if (i_receiveInstalled) {
			RemoveReceiveHandler(DragReceiveUPP, GetWindowRef());
		}
		
		if (i_windowType >= ADFS_Window_DOCUMENT) {
			DisposeWindow(GetWindowRef());
		} else {
			DisposeDialog(i_macPort.dialog);
		}
	}
		
	delete this;
}


void		CWindow::SetFontInfo(void)
{
	FontInfo	fInfo;

	SetFontRec(&i_fontRec);
	
	GetFontInfo(&fInfo);
	i_fontInfo = fInfo;
}

void		CWindow::UpdateFontInfo(ADFS_FontRec *fontRec)
{
	if (memcmp(&i_fontRec, fontRec, sizeof(ADFS_FontRec))) {
		i_fontRec = *fontRec;
		SetFontInfo();
		InvalWindow(WindowRect_ALL);
	}
}

void	CWindow::DoKeyDown(EventRecord *event)
{
	if (i_renameTE) {
		Byte			keyCode;
		char			charCode;
		CRenameTextEdit	*cteP = CRenameTextEdit::GetCurTextEdit();

		charCode =	(event->message & 0x000000FF);
		keyCode =	(event->message & 0x00007F00) >> 8;

		ASSERT(cteP == i_renameTE || cteP == NULL);
		
		Prepare();
		i_renameTE->DoKeyDown(charCode, keyCode, event);
		UnPrepare();
	}
}

void	CWindow::DoClick(EventRecord *event)
{
	SelectWindow(GetWindowRef());
}

void	CWindow::ReActivate(Boolean active)
{
	i_active = active;
//	InvalWindow(WindowRect_ALL);
}

void			CWindow::SetTitle(char *nameZ)
{
	unsigned char	nameAC[256];
	
	CopyCStringToPascal(nameZ, nameAC);
	SetPTitle(nameAC);
}

void			CWindow::SetPTitle(unsigned char *nameZu)
{
	SetWTitle(GetWindowRef(), nameZu);
}

WindowRef		CWindow::GetWindowRef(void)
{
	return i_macPort.window;
}

GrafPtr			CWindow::GetGrafPtr(void)
{
	return (GrafPtr)GetWindowPort(GetWindowRef());
}

void	CWindow::Update(void)
{
	GrafPtr		grafPtr		= GetGrafPtr();
	WindowRef	windowRef	= GetWindowRef();
	RgnHandle	visRgn		= NewRgn();
	
	QuietErrors(TRUE);
	SetPort(grafPtr);
	BeginUpdate(windowRef);
	Draw();
	
	if (visRgn) {
		GetPortVisibleRegion(grafPtr, visRgn);
		UpdateControls(windowRef, visRgn);
		DisposeRgn(visRgn);
	} else {
		DrawControls(windowRef);
	}
	
	DrawOnlyGrowIcon(windowRef);
	
	EndUpdate(windowRef);

	QuietErrors(FALSE);
}

void	CWindow::Draw(void)
{
}

void	CWindow::Idle(void)
{
	if (i_renameTE) {
		Prepare();
		i_renameTE->Idle();
		UnPrepare();
	}
}

void	CWindow::Move(EventRecord *event)
{
	Rect	boundsRect;
	
	GetRegionBounds(GetGrayRgn(), &boundsRect);
	
	DragWindow(GetWindowRef(), event->where, &boundsRect);
}

Rect	CWindow::GetSizeRect(void)
{
	Rect	rectR;
	
	rectR.left		= 120;
	rectR.top		= 130;
	rectR.right		= 32767;
	rectR.bottom	= 32767;
	
	return rectR;
}

void	CWindow::SetSizeRect(Rect *sizeRect)
{
	i_sizeRect = *sizeRect;
}

Boolean		CWindow::IsShowing(void)
{
	return IsWindowVisible(GetWindowRef());
}

void	CWindow::SetWindowRect(Rect *r)
{
	if (!EmptyRect(r)) {
		Boolean		showingB = IsShowing();
		
		if (showingB) {
			ShowHide(FALSE);
		}
		
		MoveWindow(
			GetWindowRef(), r->left, r->top, FALSE);
			
		SizeWindow(
			GetWindowRef(), 
			r->right - r->left, 
			r->bottom - r->top, 
			FALSE);

		if (showingB) {
			ShowHide(TRUE);
		}
	}
}

void	CWindow::Size(EventRecord *event)
{
	Rect	oldRect		= GetWindowRect(WindowRect_ALL);
	long	result		= GrowWindow(GetWindowRef(), event->where, &i_sizeRect);
	
	if (
		oldRect.right - oldRect.left != LoShort(result)
		|| oldRect.bottom - oldRect.top != HiShort(result)
	) {
		SizeWindow(GetWindowRef(), LoShort(result), HiShort(result), TRUE);
		InvalWindow(WindowRect_ALL);
	}
}

void	CWindow::Zoom(EventRecord *event, short direction)
{
	if (TrackBox(GetWindowRef(), event->where, direction)) {
		ZoomWindow(GetWindowRef(), direction, TRUE);
		InvalWindow(WindowRect_ALL);
	}
}

Boolean	CWindow::CanClose(void)
{
	return TRUE;
}

void	CWindow::Show(Boolean show)
{
	if (show) {
		SelectWindow(GetWindowRef());
		ShowWindow(GetWindowRef());
	} else if (CanClose()) {
		Dispose();
	}
}

void	CWindow::ShowHide(Boolean show)
{
	if (show) {
		Show(show);
	} else {
		HideWindow(GetWindowRef());
	}
}

void	CWindow::GoAway(EventRecord *event)
{
	if (TrackGoAway(GetWindowRef(), event->where)) {
		DoCommand(cmdCloseWindow);
	}
}

Boolean	CWindow::DoCommand(long command)
{
	Boolean		handled = FALSE;
	
	if (i_renameTE) {
		RTE_CommandType		te_cmd;
		
		if (i_renameTE->WillHandleCommand(command, &te_cmd)) {
			handled = TRUE;
			
			Prepare();
			i_renameTE->DoCommand(te_cmd);
			UnPrepare();
		}
	}

	switch (command) {
		
		case cmdCloseWindow: {
			Show(FALSE);
			handled = TRUE;
			break;
		}
	}

	return handled;
}

void	CWindow::UpdateMenus(void)
{
	if (i_renameTE) {
		i_renameTE->UpdateMenus();
	}
}

//	always returns coordinates relative to topLeft { 0, 0 }
//	beeps if you call it when the offscreen is active
Rect	CWindow::GetWindowRect(WindowRectType wrType)
{
	Rect		theRect;
	
	GetPortBounds((CGrafPtr)GetGrafPtr(), &theRect);

//	OffsetRect(&theRect, -theRect.left, -theRect.top);
	
	switch (wrType) {
	
		case WindowRect_H_SCROLL:
		case WindowRect_V_SCROLL:
		case WindowRect_GROW_BOX:
		case WindowRect_HEADER:
		case WindowRect_HEADER_DISK_INFO:
		case WindowRect_HEADER_STAT_INFO: 
		case WindowRect_NONE: {
			theRect.left	= 0;
			theRect.right	= 0;
			theRect.top		= 0;
			theRect.bottom	= 0;
			break;
		}

		case WindowRect_ALL_GLOBAL: {
			LocalRectToGlobal(GetGrafPtr(), &theRect);
			break;
		}
		
		case WindowRect_ALL:
		case WindowRect_INTERIOR: {
			break;
		}
	}
	
	return theRect;
}

Boolean		CWindow::SectVisRgnWindowRect(WindowRectType windowRect, Rect *sectR)
{
	Boolean		sectB	= TRUE;
	RgnHandle	visRgn	= NewRgn(), windRgn = NewRgn();

	if (visRgn) {
		Rect	theRect = GetWindowRect(windowRect);
		
		RectRgn(windRgn, &theRect);
		
		GetPortVisibleRegion(GetGrafPtr(), visRgn);

		SectRgn(visRgn, windRgn, windRgn);
		
		sectB = !EmptyRgn(windRgn);
		
		if (sectB && sectR) {
			GetRegionBounds(windRgn, sectR);
		}
	}

	if (visRgn) {
		DisposeRgn(visRgn);
	}

	if (windRgn) {
		DisposeRgn(windRgn);
	}

	return sectB;
}

void	CWindow::InvalWindow(WindowRectType windowRect)
{
	Rect		theRect;
	
	SetPort(GetGrafPtr());
	
	//	inval the area necessary
	theRect = GetWindowRect(windowRect);
	InvalWindowRect(GetWindowRef(), &theRect);
	
	i_invalid = TRUE;
}

//========================================
OSErr		CWindow::IterateDragFlavors(
	DragReference			theDrag, 
	IterateDragFlavorsCB	IterateCB, 
	void					*data
) {
	OSErr				err = noErr;
//	Boolean				canAccept = FALSE;
	unsigned short		maxDragItems, dragItemIndex, maxItemFlavors, itemFlavorIndex;
	ItemReference		itemRef;
	FlavorType			flavorType;

	SetPort(GetGrafPtr());

	err = CountDragItems(theDrag, &maxDragItems);

	if (!err) for (
		dragItemIndex = 1; 
		dragItemIndex <= maxDragItems && !err; 
		dragItemIndex++
	) {

		err = GetDragItemReferenceNumber(theDrag, dragItemIndex, &itemRef);
		
		if (!err) err = CountDragItemFlavors(
			theDrag, itemRef, &maxItemFlavors
		);
		
		if (!err) for (
			itemFlavorIndex = 1; 
			itemFlavorIndex <= maxItemFlavors && !err; 
			itemFlavorIndex++
		) {
			
			err = GetFlavorType(
				theDrag, itemRef, itemFlavorIndex, &flavorType
			);
			
			if (!err) {
				err = IterateCB(this, theDrag, itemRef, flavorType, data);
			}
		}
	}
	
	if (err == -1) {
		err = noErr;
	}
	
	return err;
}

//========================================

typedef struct {
	FlavorType		flavorType;
	ItemReference	itemRef;
} DragHasFlavorRec;

static	OSErr	DragHasFlavorCB(
	CWindow			*thiz, 
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	void			*data)
{
	OSErr				err = noErr;
	DragHasFlavorRec	*flavorRecP = (DragHasFlavorRec *)data;
	
	if (flavorType == flavorRecP->flavorType) {
		flavorRecP->itemRef = itemRef;
		err = -1;
	}
	
	return err;
}

//========================================
OSErr		CWindow::DragHasFlavor(
	DragReference	theDrag, 
	FlavorType		flavorType, 
	ItemReference	*itemRefP)
{
	DragHasFlavorRec	flavorRec;
	OSErr				err;
	
	flavorRec.flavorType	= flavorType;
	flavorRec.itemRef		= NULL;
	err = IterateDragFlavors(theDrag, DragHasFlavorCB, &flavorRec);
	*itemRefP = flavorRec.itemRef;
	
	return err;
}


//========================================
//	static	
OSErr	CWindow::CanAcceptFlavorCB(
	CWindow			*thiz, 
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	void			*data)
{
	return thiz->CanAcceptFlavor(theDrag, itemRef, flavorType, (Boolean *)data);
}

OSErr		CWindow::CanAcceptFlavor(
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	Boolean			*goodFlavorB)
{
	return noErr;
}

//========================================
OSErr		CWindow::CanAcceptDrag(DragReference theDrag)
{
	Boolean		atLeastOneIsGoodB = FALSE;
	OSErr		err;
	
	err = IterateDragFlavors(theDrag, CanAcceptFlavorCB, &atLeastOneIsGoodB);

	if (!err && !atLeastOneIsGoodB) {
		err = dragNotAcceptedErr;
	}
	
	return err;
}

//========================================
OSErr		CWindow::DragTrackInWindow(DragReference theDrag)
{
	return noErr;
}

//========================================
//	static
pascal OSErr CWindow::DragTrackCB(
	DragTrackingMessage		message, 
	WindowPtr				theWindow, 
	void					*data, 
	DragReference			theDrag
) {
	CWindow		*thiz = (CWindow *)data; 

	QuietErrors(TRUE);
	return thiz->DragTrack(message, theDrag);
	QuietErrors(FALSE);
}

OSErr		CWindow::Prepare(void)
{
	SetPort(GetGrafPtr());
	SetFontInfo();

	return noErr;
}

void		CWindow::UnPrepare(void)
{
}

OSErr		CWindow::DragTrack(
	DragTrackingMessage		message, 
	DragReference			theDrag
) {
	OSErr		err = noErr;
	
	SetPort(GetGrafPtr());
	
	if (!err) switch (message) {

		case kDragTrackingEnterHandler: {
			i_frameRgn = NewRgn();

			if (i_frameRgn) {
				Rect	theRect = GetWindowRect(WindowRect_INTERIOR);
				
				RectRgn(i_frameRgn, &theRect);
			}
			break;
		}
		
		case kDragTrackingLeaveHandler: {
			if (i_frameRgn) {
				DisposeRgn(i_frameRgn);
				i_frameRgn = NULL;
			}
			break;
		}
		
		case kDragTrackingEnterWindow: {
			err = CanAcceptDrag(theDrag);
			if (!err) err = i_frameRgn ? (OSStatus)noErr : (OSStatus)dragNotAcceptedErr;
			
			i_dragCanAccept = (err == noErr);
			
			if (i_dragCanAccept) {
				err = ShowDragHilite(theDrag, i_frameRgn, TRUE);
			}
			break;
		}
		
		case kDragTrackingInWindow: {
			if (i_dragCanAccept) {
				err = DragTrackInWindow(theDrag);
			}
			break;
		}
		
		case kDragTrackingLeaveWindow: {
			if (i_dragCanAccept) {
				err = HideDragHilite(theDrag);
			}
			break;
		}
	}

	return err;
}

/*********************/
//	static	
OSErr	CWindow::DragReceiveFlavorCB(
	CWindow			*thiz, 
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	void			*data
) {
	return thiz->DragReceiveFlavor(theDrag, itemRef, flavorType, data);
}

OSErr		CWindow::DragReceiveFlavor(
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	void			*data
) {
	return dragNotAcceptedErr;
}

/******************************************************************/
//	static
pascal OSErr CWindow::DragReceiveCB(
	WindowPtr		theWindow, 
	void			*data, 
	DragReference	theDrag
) {
	CWindow		*thiz = (CWindow *)data; 
	OSErr		err = noErr;

	QuietErrors(TRUE);
	err = thiz->DragReceive(theDrag);
	QuietErrors(FALSE);
	
	return err;
}

OSErr		CWindow::DragReceive(
	DragReference	theDrag
) {
	OSErr		err = CanAcceptDrag(theDrag);
	
	if (!err) err = IterateDragFlavors(theDrag, DragReceiveFlavorCB, NULL);
	
	return err;
}

/******************************************************************/
//	non-object functions

CWindow		*GetCWindow(WindowRef windowRef)
{
	CWindow		*window	= NULL;

	if (windowRef) {
		window = (CWindow *)GetWRefCon(windowRef);

		if (window && window->i_magic != kCWindowMagic) {
			window = NULL;
		}
	}

	return window;
}

CWindow		*GetFrontCWindow(void)
{
	CWindow		*frontWindow	= NULL;
	WindowRef	window			= FrontWindow();
	
	if (window) {
		frontWindow = GetCWindow(window);
	}
	
	return frontWindow;
}

Boolean		IterateCWindows(CWindowCB cWindowCB, void *data)
{
	CWindow		*window;
	WindowRef	windowRef	= GetWindowList(), 
				nextWindow;
	Boolean		abort		= FALSE;
	
	while (!abort && windowRef) {
	
		nextWindow = GetNextWindow(windowRef);

		if ((window = GetCWindow(windowRef)) != NULL) {	/*=*/
			abort = (*cWindowCB)(window, data);
		}
		
		if (!abort) {
			windowRef = nextWindow;
		}
	};
	
	return abort;
}

static	Boolean	CloseAllCWindowsCB(CWindow *window, void *data)
{
	Boolean		abortB = FALSE;
	
	if (window->i_windowType != ADFS_Window_DESKTOP) {
	
		if (window->CanClose()) {
			window->Dispose();
		} else {
			abortB = TRUE;
		}
	}
	
	return abortB;
}

Boolean		CloseAllCWindows(void)
{
	return !IterateCWindows(CloseAllCWindowsCB, NULL);
}

static	Boolean	InvalAllWindowsCB(CWindow *window, void *data)
{
	window->InvalWindow(WindowRect_ALL);
	return FALSE;
}

void		InvalAllCWindows(void)
{	
	IterateCWindows(InvalAllWindowsCB, NULL);
}

Boolean		CWindow::IsFrontWindow(void)
{
	return FrontWindow() == GetWindowRef();
}

void		CWindow::Flush(void)
{
	#ifndef __68k__
		QDFlushPortBuffer(GetGrafPtr(), NULL);
	#endif
}

Boolean			CWindow::IsDirty(void)
{
	#ifndef __68k__
		return IsWindowModified(GetWindowRef());
	#else
		return i_dirtyB;
	#endif
}

void			CWindow::SetDirty(Boolean dirtyB)
{
	#ifndef __68k__
		SetWindowModified(GetWindowRef(), dirtyB);
	#else
		i_dirtyB = dirtyB;
	#endif
}

#ifndef __68k__
OSStatus		CWindow::SetAttribute(WindowAttributes attribs)
{
	#ifndef __68k__
		return ChangeWindowAttributes(GetWindowRef(), attribs, kWindowNoAttributes);
	#else
		return 0;
	#endif
}

OSStatus		CWindow::ClearAttribute(WindowAttributes attribs)
{
	#ifndef __68k__
		return ChangeWindowAttributes(GetWindowRef(), kWindowNoAttributes, attribs);
	#else
		return 0;
	#endif
}
#endif
