/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

/*
 * Local variables:
 *   gCommentsFontInfo = the font information for the comments window font (Geneva 9pt)
 *   gCommentsWindow = pointer to the statistics window
 *	 gCommentsImage = handle of the image whose comments we're showing
 *   gCommentsTextEdit = handle to the TextEdit record
 *   gCommentsRect = the rect of the TextEdit record
 *
 */

static WindowPtr gCommentsWindow = nil;
static FontInfo gCommentsFontInfo;
static ImageHandle gCommentsImage = (ImageHandle)-1;
static TEHandle gCommentsTextEdit = nil;
static Rect gCommentsRect = { 0, 0, 10, 400 };

/*
 * OpenComments()
 *
 *     Purpose: Creates and initializes the comments window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
OSErr OpenComments(void) 
{
	Rect theRect, mainRect;
	OSErr theErr = noErr;
	Point where;
	
	if (gCommentsWindow) {
		if (!WindowVisible(gCommentsWindow)) FWShowWindow(gCommentsWindow);
		return noErr;
	}
	if (!(gCommentsWindow = AllocateWindow())) return memFullErr;
	PushPort();
	MySetPort(nil);
	if (gCommentsWindow = FWGetNewFloatingWindow(rCommentsWindow, (Ptr)gCommentsWindow, 
			(WindowPtr)-1)) {
		MySetPort((CGrafPtr)gCommentsWindow);
		TextFont(geneva);
		TextSize(9);
		TextMode(srcCopy);
		TextFace(0);
		GetFontInfo(&gCommentsFontInfo);
		InsetRect(&gCommentsRect, 3, 0);
		gCommentsTextEdit = TENew(&gCommentsRect, &gCommentsRect);
		InsetRect(&gCommentsRect, -3, 0);
		if (gCommentsTextEdit) {
			(*gCommentsTextEdit)->txFont = geneva;
			(*gCommentsTextEdit)->txSize = 9;
			if (Width(&gThePrefs.commentsBounds) && Height(&gThePrefs.commentsBounds))
				SizeWindow(gCommentsWindow, Width(&gThePrefs.commentsBounds), 
						   Height(&gThePrefs.commentsBounds), false);
			theRect = gCommentsWindow->portRect;
			OffsetRect(&theRect, -theRect.left, -theRect.top);
			if (gThePrefs.commentsBounds.top != gThePrefs.commentsBounds.bottom) {
				gThePrefs.commentsBounds.right = gThePrefs.commentsBounds.left + Width(&theRect);
				gThePrefs.commentsBounds.bottom = gThePrefs.commentsBounds.top + Height(&theRect);
			}
			GetActiveRect(gMainMonitor, &mainRect);
			where.h = mainRect.right - kWindowBorderWidth - theRect.right;
			where.v = mainRect.bottom - kWindowBorderHeight - theRect.bottom;
			PlaceWindow(gCommentsWindow, &gThePrefs.commentsBounds, where);
			DrawCommentsWindow();
			gThePrefs.commentsOpen = true;
			PopPort();
			return noErr;
		} else theErr = memFullErr;
	} else theErr = memFullErr;
	CloseComments();
	PopPort();
	return theErr;
}

/*
 * CloseComments()
 *
 *     Purpose: Closes the comment window
 *      Inputs: none
 *     Returns: nothing
 *
 */

void CloseComments(void)
{
	PushPort();
	MySetPort(nil);
	if (gCommentsTextEdit) {
		TEDispose(gCommentsTextEdit);
		gCommentsTextEdit = nil;
	}
	if (gCommentsWindow) {
		gThePrefs.commentsOpen = false;
		SaveWindowPosition(gCommentsWindow, &gThePrefs.commentsBounds);
		FWCloseWindow(gCommentsWindow);
		DeallocateWindow(gCommentsWindow);
	}
	gCommentsWindow = nil;
	gCommentsImage = (ImageHandle)-1;
	PopPort();
}

/*
 * NudgeComments(Rect *oldRect)
 *
 *     Purpose: Nudges the comments window so it is fully visible on-screen
 *      Inputs: none
 *     Returns: nothing
 *
 */

void NudgeComments(Rect *oldRect)
{
	Boolean top = false, left = false;
	MonitorHandle theMonitor;
	Rect theRect, monRect;
	
	if (gCommentsWindow) {
		theRect = gCommentsWindow->portRect;
		GlobalRect(&theRect, gCommentsWindow);
		GlobalRect(oldRect, gCommentsWindow);
		if (theMonitor = GetMostDevice(&theRect)) {
			GetActiveRect(theMonitor, &monRect);
			monRect.top += 11;	// account for titlebar -- contact from Inf. Windoid code
			if ((oldRect->left - monRect.left) < (monRect.right - oldRect->right))
				left = true;
			if ((oldRect->top - monRect.top) < (monRect.bottom - oldRect->bottom))
				top = true;
			if (top) 
				OffsetRect(&theRect, 0, monRect.top + kWindowBorderHeight - theRect.top);
			else OffsetRect(&theRect, 0, monRect.bottom - kWindowBorderHeight - theRect.bottom);
			if (left) 
				OffsetRect(&theRect, monRect.left + kWindowBorderWidth - theRect.left, 0);
			else OffsetRect(&theRect, monRect.right - kWindowBorderWidth - theRect.right, 0);
			FWMoveWindow(gCommentsWindow, theRect.left, theRect.top, false);
		}
	}
}

/*
 * GetCommentsWindow()
 *
 *     Purpose: Returns a pointer to the statistics window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
WindowPtr GetCommentsWindow(void)
{
	return gCommentsWindow;
}

/*
 * DrawCommentsWindow()
 *
 *     Purpose: Draws the statistics window
 *      Inputs: none
 *     Returns: nothing
 *
 */
 
void DrawCommentsWindow(void) 
{
	short width, maxwidth = 110, start, end, i;
	Boolean autoComments = (!gSlideShow && gThePrefs.autoComments) || 
						   (gSlideShow && (*gSlideOptions)->autoComments);
	Rect theRect, tempRect, oldRect;
	MonitorHandle theMonitor;
	ImageHandle theImage;
	WindowPtr theWindow;
	Boolean wasVisible;

	if (!gCommentsWindow) return;
	wasVisible = WindowVisible(gCommentsWindow);
	oldRect = gCommentsWindow->portRect;
	PushPort();
	MySetPort((CGrafPtr)gCommentsWindow);	
	for (theWindow = GetFirstWindow(); theWindow && !(theImage = FindImage(theWindow));
		 theWindow = NextWindow(theWindow));
	if (autoComments && (!theImage || !(*theImage)->comments)) {
		if ((!gSlideShow && !gCommentsOpen) || gSlideShow) {
			PopPort();
			CloseComments();
			return;
		}
	}
	if (theImage != gCommentsImage) {
		FWHideWindow(gCommentsWindow);
		gCommentsImage = theImage;
		TESetSelect(0, 32767, gCommentsTextEdit);
		TEDelete(gCommentsTextEdit);
		TEScroll(0, (*gCommentsTextEdit)->viewRect.top - (*gCommentsTextEdit)->destRect.top, 
					gCommentsTextEdit);
		if (theImage && (*theImage)->comments) {
			HLock((*theImage)->comments);
			TEInsert(*(*theImage)->comments, GetHandleSize((*theImage)->comments),
			 		gCommentsTextEdit);
			HUnlock((*theImage)->comments);
			(*gCommentsTextEdit)->viewRect.bottom =
						(*gCommentsTextEdit)->viewRect.top + 
						(*gCommentsTextEdit)->lineHeight *
						(*gCommentsTextEdit)->nLines + gCommentsFontInfo.descent;
			tempRect = gCommentsWindow->portRect;
			GlobalRect(&tempRect, gCommentsWindow);
			theMonitor = GetMostDevice(&tempRect);
			GetActiveRect(theMonitor, &tempRect);
			tempRect.top += 11 + 2 * kWindowBorderHeight;
			if (Height(&(*gCommentsTextEdit)->viewRect) > Height(&tempRect))
				(*gCommentsTextEdit)->viewRect.bottom = 
							(*gCommentsTextEdit)->viewRect.top + Height(&tempRect);
		} else {
			(*gCommentsTextEdit)->viewRect.bottom = 
							(*gCommentsTextEdit)->viewRect.top +
							(*gCommentsTextEdit)->lineHeight + gCommentsFontInfo.descent;
			TEInsert(&gString[strNoComments][1], *gString[strNoComments],
					gCommentsTextEdit);
		}
		theRect = (*gCommentsTextEdit)->viewRect;
		InsetRect(&theRect, -3, 0);
		for (i = 0; i < (*gCommentsTextEdit)->nLines; i++) {
			uchar *text;
			start = (*gCommentsTextEdit)->lineStarts[i];
			end = (*gCommentsTextEdit)->lineStarts[i + 1] - 1;
			text = (uchar *)*(*gCommentsTextEdit)->hText + end;
			while (*text < 0x20) text--, end--;
			if (end > start) {
				HLock((Handle)(*gCommentsTextEdit)->hText);
				width = TextWidth(*(*gCommentsTextEdit)->hText, start, end - start + 1);
				HUnlock((Handle)(*gCommentsTextEdit)->hText);
			}
			if (width > maxwidth) maxwidth = width;
		}
		SizeWindow(gCommentsWindow, maxwidth + 6, Height(&theRect), true);
		if (autoComments) NudgeComments(&oldRect);
		if (wasVisible) {
			FWSelectWindow(gCommentsWindow);
			FWShowWindow(gCommentsWindow);
		}
	}
	PopPort();
}	

void UpdateCommentsWindow(void)
{
	Rect theRect;
	
	if (!gCommentsWindow) return;
	PushPort();
	MySetPort((CGrafPtr)gCommentsWindow);
	theRect = (*gCommentsTextEdit)->viewRect;
	TEUpdate(&theRect, gCommentsTextEdit);
	PopPort();
}

extern void HandleCommentsClick(EventRecord *theEvent)
{
	if (gDragMgrPresent && WaitMouseMoved(theEvent->where)) {
		RgnHandle theRgn = NewRgn(), tempRgn = NewRgn();
		DragReference theDrag;
		Handle textHandle;
		Rect startRect;
		OSErr theErr;
		char hState;
		
		if (theRgn && tempRgn) {
			theErr = NewDrag(&theDrag);
			if (theErr == noErr) {
				textHandle = (Handle)TEGetText(gCommentsTextEdit);
				hState = HGetState(textHandle);
				HLock(textHandle);
				AddDragItemFlavor(theDrag, (ItemReference)gCommentsTextEdit, 'TEXT', *textHandle, GetHandleSize(textHandle), 0);
				HSetState(textHandle, hState);
				startRect = (*gCommentsTextEdit)->viewRect;
				SectRect(&startRect, &gCommentsWindow->portRect, &startRect);
				GlobalRect(&startRect, gCommentsWindow);
				RectRgn(theRgn, &startRect);
				RectRgn(tempRgn, &startRect);
				InsetRgn(tempRgn, 1, 1);
				DiffRgn(theRgn, tempRgn, theRgn);
				SetDragItemBounds(theDrag, (ItemReference)gCommentsTextEdit, &(*theRgn)->rgnBBox);
				SetCursor(&qd.arrow);
				theErr = TrackDrag(theDrag, theEvent, theRgn);
				DisposeDrag(theDrag);
			}
		}
		if (theRgn) DisposeRgn(theRgn);
		if (tempRgn) DisposeRgn(tempRgn);
	} else if (FrontWindow() != gCommentsWindow) SendMoveToFront(gCommentsWindow);
}

/*
 * DoCommentsHelp(globalPt)
 *
 *     Purpose: Pops up help for the comments windoid; needed because it should be displayed even
 *					if it's not "active"
 *      Inputs: globalPt = point, in global coordinates, where the mouse is
 *     Returns: nothing
 *
 */
 
void DoCommentsHelp(Point globalPt)
{
	HMMessageRecord theRecord;
	Point tip = { 0, 0 };
	Rect aRect;
	
	if (HMIsBalloon() || gInBackground) return;
	PushPort();
	SetPort(gCommentsWindow);
	if (HMExtractHelpMsg(kHMRectListResType, rCommentsWindow, 1, kHMEnabledItem, &theRecord) == noErr) {
		tip = globalPt;
		aRect = gCommentsWindow->portRect;
		GlobalRect(&aRect, gCommentsWindow);
		HMShowBalloon(&theRecord, tip, &aRect, nil, 0, 0, kHMRegularWindow);
	}
	PopPort();
}
