//	OTLN_dmInterface.c

#include "Carbon68kGlue.h"
#include "OTLNp.h"

/**		OTLN_SetFontInfo	[30]
**/
Err			OTLN_SetFontInfo(OTLN_OutlineP ol, const char *font_name0, short font_size0)
{
	Err		err	= Err_NONE;
	
	if (font_name0 != NULL) {
		char	font_name[64];
		
		CopyCStringToPascal(font_name0, (unsigned char *)font_name);
		ol->font_id = FMGetFontFamilyFromName((StringPtr)font_name);
	}

	if (font_size0 != 0)
		ol->font_size = font_size0;

	if (font_name0 != NULL || font_size0 != 0) {
		OTLN_SaveFontInfo		sfi;
		FontInfo				finfo;
		WindowRef				windowRef;
		Rect					theRect = { 0, 0, 10, 10 };
		GrafPtr					thePort;
		
		GetPort(&thePort);
		
		windowRef = NewWindow(
			NULL, &theRect, "\pfonts", FALSE, documentProc, 
			NULL, FALSE, 0);
		
		if (windowRef) {
			SetPortWindowPort(windowRef);
			err = OTLN_SaveSetFontInfo(ol->self, &sfi);
			GetFontInfo(&finfo);
			(void)OTLN_RestoreFontInfo(&sfi);
			DisposeWindow(windowRef);
			SetPort(thePort);

			ol->cell_height	= 2 + finfo.ascent + finfo.descent + finfo.leading;
		} else {
			ol->cell_height = 14;
		}
		
		if (ol->cell_height < 14)
			ol->cell_height = 14;
	}
	
	return err;
}


/**		OTLN_SetTopicFontStyle	[31]
**/
Err			OTLN_SetTopicFontStyle(OTLN_TopicP to, Style *font_style0)
{
	if (font_style0) {
		if (*font_style0 == 0)
			to->font_style = normal;
		else
			to->font_style |= *font_style0;
	}
	
	return Err_NONE;
}

/**	OTLN_DrawOutlineSeparationBar	[75]
**/
static	M_Rect		S_frame_rect;
static	short		S_vPos			= OTLN_DRAG_REORDER_SENTINEL;

Err		OTLN_DrawOutlineSeparationBar(void)
{
	Err				err = Err_NONE;
	PenState		savePen;

	GetPenState(&savePen);

	PenNormal();
	PenMode(srcXor);
	
	err = OTLN_DrawSeparationBar(&S_frame_rect, S_vPos);
	
	SetPenState(&savePen);

	return err;
}

/**	OTLN_DrawSeparationBar	[58]
**/
Err		OTLN_DrawSeparationBar(M_Rect *frame_rect, short vPos)
{
	Err		err = Err_NONE;
	
	S_vPos			= vPos;
	S_frame_rect	= *frame_rect;
	
	if (vPos != OTLN_DRAG_REORDER_SENTINEL) {
		Rect		theRect;
		Pattern		thePat;
		
		theRect.left	= frame_rect->left;
		theRect.right	= frame_rect->right;
		theRect.top		= vPos;
		theRect.bottom	= vPos + 3;

		FrameRect(&theRect);
		PenPat(GetQDGlobalsGray(&thePat));
		MoveTo(theRect.left, vPos + 1);
		LineTo(theRect.right, vPos + 1);
		PenPat(GetQDGlobalsBlack(&thePat));
	}
	
	return(err);
}

/**	OTLN_DragReorderTopic	[59]
	if user gets an autoscroll callback, then dragData.u.pixels will give the number
	of pixels from the visual boundary of the list to the mouse pos and the user can 
	scroll the apropriet ammount.  IF, however, you ARE at the top/bottom  of the list
	then the user must return ZERO in this value to have the autoscroller to then try
	to drop the item at the top/bottom position
**/
Err		OTLN_DragReorderTopic(
	OTLN_Hit_n_Draw_Record	*hitDrawRec, 
	OLTN_DragReorderTopicCB	*callback, 
	void					*data, 
	M_Rect					*frame_rect, 
	long					cell_height0, 
	long					*oldIndex, 
	long					*newIndex
) {
	Err							err = Err_NONE;
	Point						oldPoint, newPoint;
	short						oldVpos = OTLN_DRAG_REORDER_SENTINEL, newVpos = OTLN_DRAG_REORDER_SENTINEL;
	PenState					savePen, myPen;
	Boolean						testDragAnyway;
	short						halfCellHeight;
	OTLN_DragReorderDataRec		dragData;
	Pattern						thePat;
	
	GetPenState(&savePen);
	PenPat(GetQDGlobalsBlack(&thePat));
	PenMode(srcXor);
	GetPenState(&myPen);
	
	oldPoint = hitDrawRec->hit_point;
	
	halfCellHeight = 
		(cell_height0 
			? cell_height0 
			: DH(hitDrawRec->outline)->cell_height
		) >> 1;
	
	*oldIndex = 0;
	*newIndex = 0;
	
	err = (*callback)(OTLN_DragReorderCBMessage_DRAG, NULL, data);

	if (!err) do {
		testDragAnyway = FALSE;
		
		GetMouse(&newPoint);

		if (newPoint.v < frame_rect->top) {
			dragData.u.p.pixels = newPoint.v - frame_rect->top;
			dragData.u.p.frame_rect = frame_rect;

			SetPenState(&savePen);
			err = (*callback)(OTLN_DragReorderCBMessage_SCROLL_UP, &dragData, data);
			SetPenState(&myPen);

			if (dragData.u.p.pixels == 0) {
				testDragAnyway = TRUE;
			} else {
				dragData.u.p.pixels = 0;
			}
		} else if (newPoint.v > frame_rect->bottom) {
			dragData.u.p.pixels = newPoint.v - frame_rect->bottom;
			dragData.u.p.frame_rect = frame_rect;

			SetPenState(&savePen);
			err = (*callback)(OTLN_DragReorderCBMessage_SCROLL_DOWN, &dragData, data);
			SetPenState(&myPen);

			if (dragData.u.p.pixels == 0) {
				testDragAnyway = TRUE;
			} else {
				dragData.u.p.pixels = 0;
			}
		} else {
			testDragAnyway = TRUE;
		}

		dragData.u.topic	= NULL;

		if (newPoint.v != oldPoint.v) {

			err = OTLN_TestTopicHit(
				hitDrawRec->outline, 
				newPoint.v + halfCellHeight, 
				hitDrawRec->topic, 
				&dragData.u.topic, 
				&newVpos
			);
			SetPenState(&myPen);
			
			if (!err && (newVpos != oldVpos)) {
				err = OTLN_DrawSeparationBar(frame_rect, oldVpos);
				
				if (!err)
					err = OTLN_DrawSeparationBar(frame_rect, newVpos);
				
				if (!err) {
					oldVpos = newVpos;
					
					if (newVpos == OTLN_DRAG_REORDER_SENTINEL) {
						err = (*callback)(OTLN_DragReorderCBMessage_DRAG, NULL, data);
					} else {
						if (dragData.u.topic) {
							err = (*callback)(OTLN_DragReorderCBMessage_AFTER, &dragData, data);
						} else {
							err = (*callback)(OTLN_DragReorderCBMessage_TO_FRONT, NULL, data);
						}
					}
				}
			}
		}
	} while (Button() && !err);
	
	if (!err)
		err = OTLN_DrawSeparationBar(frame_rect, oldVpos);
	
	//	the following tells the OTLN_Draw routine to NOT draw any more
	//	separation bars
	if (!err) {
		err = OTLN_DrawSeparationBar(frame_rect, OTLN_DRAG_REORDER_SENTINEL);
	}

	SetPenState(&savePen);

	if (!err)
		err = (*callback)(OTLN_DragReorderCBMessage_CLEAR, NULL, data);
	
	if (!err && newVpos != OTLN_DRAG_REORDER_SENTINEL) {

		err = OTLN_GetTopicIndex(hitDrawRec->outline, hitDrawRec->topic, oldIndex);
		
		if (!err) {
			if (dragData.u.topic) {
				err = OTLN_GetTopicIndex(hitDrawRec->outline, dragData.u.topic, newIndex);
				(*newIndex) += (*newIndex) < (*oldIndex);
			} else {
				*newIndex = 0;
			}
		}
	}
	
	return(err);
}
