//	OTLN_Interface.c

//#include <U.h>
#include "OTLNp.h"

#define		G_DrawLine(x1, y1, x2, y2)	\
do {									\
	MoveTo(x1, y1);						\
	LineTo(x2, y2);						\
} while (0)

/****************************************************************
			twirly arrow stuff
 ****************************************************************/

/**		OTLN_TwirlArrow	[28]
**/
extern	Boolean		Is_OS_X(void);

Err			OTLN_TwirlArrow(Rect *destRect, Boolean twirlDown)
{
	Err		err = Err_NONE;	
	short	arrow, extraTick = 0;
	long	lastTick;
	
	if (!Is_OS_X()) {
		extraTick = 1;
	}
	
	lastTick = M_TICKCOUNT();
	
	if (twirlDown) {
		for (arrow = 0; arrow <= (kNumTwirlies - 1) && !err; arrow++) {
			err = OTLN_BlitArrow(arrow, destRect);
			#ifndef __68k__
				if (!err) {
					lastTick += 1 + extraTick;
					do {} while (M_TICKCOUNT() < lastTick);
				}
			#endif
		}
	} else {
		for (arrow = (kNumTwirlies - 1); arrow >= 0 && !err; arrow--) {
			err = OTLN_BlitArrow(arrow, destRect);
			#ifndef __68k__
				if (!err) {
					lastTick += 1 + extraTick;
					do {} while (M_TICKCOUNT() < lastTick);
				}
			#endif
		}
	}
	
	return err;
}

/**		OTLN_DrawTwirlieArrow	[27]
**/
Err			OTLN_DrawTwirlieArrow(short xPos, short yPos, Boolean up)
{
	Err		err = Err_NONE;
	Rect	theRect;
	
	theRect.left	= xPos;
	theRect.top		= yPos;
	theRect.right	= theRect.left + 9;
	theRect.bottom	= theRect.top + 9;
	
	err = OTLN_BlitArrow(
		up ? kCollapsedOpenArrow : kUnCollapsedOpenArrow , &theRect);
	
	return(err);
}

/**		OTLN_HiliteArrow	[29]
	this is a callback from TrackMouse1, and therefore does not return an error
**/
void	OTLN_HiliteArrow(Rect *theRect, void *data, Boolean in, Boolean Last)
{
	short		arrow;
	Boolean		*up = (Boolean *)data;
	
	if (in) {
		if (*up)
			arrow = kCollapsedClosedArrow;
		else
			arrow = kUnCollapsedClosedArrow;
	} else {
		if (*up)
			arrow = kCollapsedOpenArrow;
		else 
			arrow = kUnCollapsedOpenArrow;
	}
	
	(void)OTLN_BlitArrow(arrow, theRect);
}


/****************************************************************
			Outline drawing
 ****************************************************************/

//	no custom data strux (yet)


/**		OTLN_DrawTopicDefault	[52]
**/
Err			OTLN_DrawTopicDefault(OTLN_Hit_n_Draw_Record *drawRec)
{
	Err					err = Err_NONE;
	M_Rect				theRect;
	OTLN_TopicFlags		flags;
	M_Rect				cellRect = drawRec->rect;
	OTLN_OutlineP		ol = *(drawRec->outline);
	OTLN_TopicP			to = *(drawRec->topic); 
	
	flags = OTLN_GET_TopicP_FLAGS(to);
	
	//	draw the twirly arrow if there is one
	if (to->daughters != NULL && OTLN_IS_TopicFlag_SET(flags, OTLN_TopicFlags_IS_EXPANDABLE)) {
	
		theRect = OTLN_GetCellRect(ol, OTLN_CellRect_TWIRLY_ARROW, &cellRect);
		
		err = OTLN_BlitArrow(
				OTLN_IS_TopicFlag_SET(flags, OTLN_TopicFlags_COLLAPSED)
				?	kCollapsedOpenArrow
				:	kUnCollapsedOpenArrow, 
				&theRect);
	}
	
	if (!err) {
		if (OTLN_IS_TopicFlag_SET(flags, OTLN_TopicFlags_HAS_SEPARATOR))
			G_DrawLine(0, cellRect.top, cellRect.right, cellRect.top);

		if (OTLN_IS_TopicFlag_SET(flags, OTLN_TopicFlags_HAS_ICON)) {
			theRect = OTLN_GetCellRect(ol, OTLN_CellRect_ICON, &cellRect);
			err = OTLN_BlitIcon(ol, to->icon_reference, &theRect);
			theRect = OTLN_GetCellRect(ol, OTLN_CellRect_NAME_ICON, &cellRect);
		} else {
			theRect = OTLN_GetCellRect(ol, OTLN_CellRect_NAME, &cellRect);
		}
	}
	
	if (!err) {
		//	draw the name of the topic
		err = OTLN_DrawName(ol, to, &theRect);
	}
	
	return(err);
}

/**		OTLN_DrawTopicCallback	[32]
**/
static	Err		OTLN_DrawTopicCallback(
					OTLN_OutlineP				ol, 
					OTLN_TopicP					to, 
					M_Rect						*cellRect, 
					OTLN_GenericCallbackData	*callbackData)
{
	Err							err = Err_NONE;
	OTLN_Hit_n_Draw_Record		drawRec;
	
	drawRec.action	= OTLN_Action_DRAW;
	drawRec.topic	= to->self;
	drawRec.outline	= ol->self;
	
	to->recent_cell = *cellRect;
	
	if (to->custom_draw) {
		drawRec.rect	= OTLN_GetCellRect(ol, OTLN_CellRect_LEFT, cellRect);
		if (!M_EmptyRect(&drawRec.rect)) {
			drawRec.where	= OTLN_Where_LEFT;			
			err = (*(to->custom_draw))(&drawRec);
		}
		
		if (!err) {
			M_Rect		theRect = OTLN_GetCellRect(ol, OTLN_CellRect_CENTER, cellRect);
			
			drawRec.rect = *cellRect;

			if (!M_EmptyRect(&theRect)) {
				drawRec.where	= OTLN_Where_CENTER;
				err = (*(to->custom_draw))(&drawRec);
			}
		}
		
		if (!err) {
			drawRec.rect = OTLN_GetCellRect(ol, OTLN_CellRect_RIGHT, cellRect);
			if (!M_EmptyRect(&drawRec.rect)) {
				drawRec.where	= OTLN_Where_RIGHT;
				err = (*(to->custom_draw))(&drawRec);
			}
		}
	} else {
		drawRec.rect = OTLN_GetCellRect(ol, OTLN_CellRect_CENTER, cellRect);
		if (!M_EmptyRect(&drawRec.rect)) {
			drawRec.where	= OTLN_Where_CENTER;
			err = OTLN_DrawTopicDefault(&drawRec);
		}
	}
	
	return err;
}


/**		OTLN_DragReorderAutoscrollSetup	[33]
**/
Err		OTLN_DragReorderAutoscrollSetup(
	OTLN_DragReorderCBMessageType	message, 		//	IN
	long							pixels, 		//	IN
	Rect							*min_frame, 	//	IN
	Rect							*max_frame, 	//	OUT
	Point							*the_point)		//	OUT
{
	*max_frame = *min_frame;

	InsetRect(max_frame, 0, -5000);

	the_point->h = min_frame->left;
	the_point->v = (message == OTLN_DragReorderCBMessage_SCROLL_UP
		? (min_frame->top - 1)
		: (min_frame->bottom + 1))
		+ pixels;
	
	return Err_NONE;
}

/**		OTLN_DrawTopics	[33]
**/
Err			OTLN_DrawTopics(OTLN_OutlineH outline)
{
	Err					err = Err_NONE;
	OTLN_SaveFontInfo	sfi;

	err = OTLN_SaveSetFontInfo(outline, &sfi);
	
	if (!err) {
		err = OTLN_IterateOutline(
			outline, 
			NULL, 
			OTLN_IterateComp_STD_ONSCREEN, 
			OTLN_DrawTopicCallback, 
			NULL
		);
	}

	//	even if the iterate fails, we still need to re-set the font info
	(void)OTLN_RestoreFontInfo(&sfi);
	
	if (!err)
		err = OTLN_DrawOutlineSeparationBar();
	
	return err;
}

/****************************************************************
			Outline Hit Test
 ****************************************************************/
typedef	struct {
	OTLN_GenericCallbackDataHeader
	
	OTLN_Hit_n_Draw_Record	*hitRec;
} TestHitCallbackData;

/**		OTLN_TestHitTopicDefault	[55]
**/
Err			OTLN_TestHitTopicDefault(OTLN_Hit_n_Draw_Record *hitRec)
{
	Err					err			= Err_NONE;
	M_Rect				cellRect	= hitRec->rect;
	OTLN_OutlineP		ol			= *(hitRec->outline);
	OTLN_TopicP			to			= *(hitRec->topic); 
//	OTLN_TopicFlags		flags		= OTLN_GET_TopicP_FLAGS(to);
	Point				thePoint	= hitRec->hit_point;
	Boolean				found		= FALSE;
	M_Rect				theRect;
	
	if (to->daughters) {
		theRect	= OTLN_GetCellRect(ol, OTLN_CellRect_TWIRLY_ARROW, &cellRect);
		if (M_POINT_IN_RECT(thePoint, theRect)) {
			hitRec->where	= OTLN_Where_TWIRLY;
			found			= TRUE;
		}
	}


	if (!found) {
	
		if (OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_HAS_ICON)) {

			theRect = OTLN_GetCellRect(ol, OTLN_CellRect_ICON, &cellRect);
			if (M_POINT_IN_RECT(thePoint, theRect)) {
				hitRec->where	= OTLN_Where_ICON;
				found = TRUE;
			}
			
			if (!found) {
				theRect = OTLN_GetCellRect(ol, OTLN_CellRect_NAME_ICON, &cellRect);
				if (M_POINT_IN_RECT(thePoint, theRect)) {
					hitRec->where	= OTLN_Where_NAME;
					found = TRUE;
				}
			}
		} else {
			theRect = OTLN_GetCellRect(ol, OTLN_CellRect_NAME, &cellRect);
			if (M_POINT_IN_RECT(thePoint, theRect)) {
				hitRec->where	= OTLN_Where_NAME;
				found = TRUE;
			}
		}
	}

	if (found) {
		hitRec->rect	= theRect;
	}

	return(err);
}

/**		OTLN_TestHitTopicCallback	[34]
**/
static	Err		OTLN_TestHitTopicCallback(	
					OTLN_OutlineP				ol, 
					OTLN_TopicP					to, 
					M_Rect						*cellRect, 
					OTLN_GenericCallbackData	*callbackData)
#define		hitData	((TestHitCallbackData *) 	callbackData)
{
	Err						err			= Err_NONE;
	Boolean					found		= FALSE;
	OTLN_Hit_n_Draw_Record	*hitRec		= hitData->hitRec;
	Point					thePoint	= hitRec->hit_point;
	M_Rect					theRect;

	theRect = OTLN_GetCellRect(ol, OTLN_CellRect_CELL, cellRect);
	
	if (M_POINT_IN_RECT(thePoint, theRect)) {
		hitData->done	= TRUE;
		hitRec->topic	= to->self;

		if (to->custom_hit_check) {
			theRect	= OTLN_GetCellRect(ol, OTLN_CellRect_LEFT, cellRect);
			if (M_POINT_IN_RECT(thePoint, theRect)) {
				hitRec->where	= OTLN_Where_LEFT;
				found			= TRUE;
				hitRec->rect	= theRect;
				err				= (*(to->custom_hit_check))(hitRec);
			}
	
			if (!err && !found) {
				theRect	= OTLN_GetCellRect(ol, OTLN_CellRect_CENTER, cellRect);
				if (M_POINT_IN_RECT(thePoint, theRect)) {
					hitRec->where	= OTLN_CellRect_CENTER;
					found			= TRUE;
					hitRec->rect	= *cellRect;
					err				= (*(to->custom_hit_check))(hitRec);
				}
			}
	
			if (!err && !found) {
				theRect	= OTLN_GetCellRect(ol, OTLN_CellRect_RIGHT, cellRect);
				if (M_POINT_IN_RECT(thePoint, theRect)) {
					hitRec->where	= OTLN_Where_RIGHT;
					found			= TRUE;
					hitRec->rect	= theRect;
					err				= (*(to->custom_hit_check))(hitRec);
				}
			}
		} else {
			theRect	= OTLN_GetCellRect(ol, OTLN_CellRect_CENTER, cellRect);
			if (M_POINT_IN_RECT(thePoint, theRect)) {
				hitRec->where	= OTLN_CellRect_CENTER;
				found			= TRUE;
				hitRec->rect	= theRect;
				err				= OTLN_TestHitTopicDefault(hitRec);
			}
		}
	}

	return err;
}
#undef		hitData

/**		OTLN_TestHitTopics		[35]
**/
Err			OTLN_TestHitTopics(
					OTLN_OutlineH			outline, 
					OTLN_Hit_n_Draw_Record	*hitRec)
{
	Err						err = Err_NONE;
	TestHitCallbackData		hitData;
	
	hitRec->action		= OTLN_Action_HIT;
	hitRec->outline		= outline;
	hitRec->topic		= NULL;
	hitRec->where		= OTLN_Where_NONE;
	hitRec->rect.top	= 0;
	hitRec->rect.left	= 0;
	hitRec->rect.bottom	= 0;
	hitRec->rect.right	= 0;
	
	hitData.hitRec		= hitRec;

	err = OTLN_IterateOutline(
		outline, 
		NULL, 
		OTLN_IterateComp_STD_ONSCREEN, 
		OTLN_TestHitTopicCallback, 
		(OTLN_GenericCallbackData *)&hitData
	);
		
	return err;
}

/****************************************************************
			count topics
 ****************************************************************/
typedef	struct {
	OTLN_GenericCallbackDataHeader

	Boolean		countCells;
	long		topics;
} CountTopicsCallbackData;

/**		OTLN_CountTopicCallback	[38]
**/
static	Err		OTLN_CountTopicCallback(	
					OTLN_OutlineP				ol, 
					OTLN_TopicP					to, 
					M_Rect						*cellRect, 
					OTLN_GenericCallbackData	*callbackData)
#define		count	((CountTopicsCallbackData *) callbackData)
{
	if (count->countCells)
		count->topics += to->cell_height_multiple;
	else
		(count->topics)++;

	return Err_NONE;
}
#undef		count

/**		OTLN_CountTopics			[39]
	countCells
		true:	if you want the number of CELLS the outline will occupy
		false:	if you want the number of topics in the outline
**/
Err			OTLN_CountTopics(
	OTLN_OutlineH		outline, 
	OTLN_IterateType	type, 
	Boolean				countCells, 
	long				*total)
{
	Err						err	= Err_NONE;
	CountTopicsCallbackData	count;
	
	U_ASSERT(total);
	*total = 0;
	
	count.countCells	= countCells;
	count.topics		= 0;

	err = OTLN_IterateOutline(
		outline, 
		NULL, 
		type, 
		OTLN_CountTopicCallback, 
		(OTLN_GenericCallbackData *)&count
	);
	
	if (!err)
		*total = count.topics;
	
	return err;
}

/****************************************************************
			Get Collapsed state handle

	the commented out stuff below may be put in if requested
	for now, it is unneeded in current projects
 ****************************************************************/
#define		OTLN_OutlineSaveHeader	\
	unsigned	long	total;
//	unsigned	short	honor_family_invisable	: 1;
//	unsigned	short	honor_topic_invisable	: 1;
//	unsigned	short	the_rest				: 14;

typedef struct {
	OTLN_OutlineSaveHeader
} OTLN_OutlineSaveSizeStruct;

struct OTLN_TopicSave_struct {
	unsigned	short	collapsed				: 1;
	unsigned	short	selected				: 1;
	unsigned	short	not_expandable			: 1;
	unsigned	short	family_invisible		: 1;

	unsigned	short	topic_invisible			: 1;
	unsigned	short	topic_solo				: 1;

	unsigned	short	the_rest				: 10;

	unsigned	short	cell_height_multiple;
};

struct OTLN_OutlineSave_struct {
	OTLN_OutlineSaveHeader
	OTLN_TopicSaveRec		save;	//	array that includes this first element has 'total' elements
};

typedef	struct {
	OTLN_GenericCallbackDataHeader

	unsigned long		total;
	unsigned long		current;
	OTLN_TopicSaveP		curRec;
} SaveTopicsCallbackData;

/**		OTLN_SaveTopicCallback	[45]
**/
static	Err		OTLN_SaveTopicCallback(	
					OTLN_OutlineP				ol, 
					OTLN_TopicP					to, 
					M_Rect						*cellRect, 
					OTLN_GenericCallbackData	*callbackData)
#define	saveData	((SaveTopicsCallbackData *)	callbackData)
{
	if (saveData->current <= saveData->total) {
		
		saveData->curRec->collapsed = 
			OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_COLLAPSED);

		saveData->curRec->selected = 
			OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_SELECTED);
		
		saveData->curRec->not_expandable = 
			!OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_EXPANDABLE);

		saveData->curRec->family_invisible = 
			OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_FAMILY_INVISABLE);
		
		saveData->curRec->topic_invisible = 
			OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_TOPIC_INVISABLE);

		saveData->curRec->topic_solo = 
			OTLN_IS_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_TOPIC_SOLO);
		
		saveData->curRec->cell_height_multiple = to->cell_height_multiple;
		
		(saveData->current)++;
		(saveData->curRec)++;
	} else {
		saveData->done = TRUE;
	}
	
	return Err_NONE;
}
#undef	saveData

/**		OTLN_SaveTopics			[46]
**/
Err			OTLN_SaveTopics(OTLN_OutlineH outline, OTLN_OutlineSaveH *save)
{
	Err						err	= Err_NONE;
	long					total;
	OTLN_OutlineSaveP		os;
	SaveTopicsCallbackData	saveData;
	
	err = OTLN_CountTopics(
		outline, 
		OTLN_Iterate_ALL, 
		FALSE, 
		&total
	);
	
	if (!err) {
		*save = (OTLN_OutlineSaveH)U_ALLOCN_HANDLE_CLR(
					OTLNp_LOC(46), 
					u_char, 
					sizeof(OTLN_OutlineSaveSizeStruct) + sizeof(OTLN_TopicSaveRec) * total, 
					OTLNp_STR(17));
		if (*save == NULL) {
			err = Err_ALLOC;
		}
		
		if (!err) {
			os = U_LOCK_DH(*save);
			os->total			= total;
			
			if (total > 0) {
				saveData.total		= total;
				saveData.current	= 1;
				saveData.curRec		= &(os->save);
				
				err = OTLN_IterateOutline(
					outline, 
					NULL, 
					OTLN_Iterate_ALL, 
					OTLN_SaveTopicCallback, 
					(OTLN_GenericCallbackData *)&saveData
				);
			}
			
			U_UNLOCK_RH(*save);
		}
	}
	
	return err;
}

/****************************************************************
			Get Collapsed state handle
 ****************************************************************/
/**		OTLN_RestoreTopicCallback	[47]
**/
static	Err		OTLN_RestoreTopicCallback(	
					OTLN_OutlineP				ol, 
					OTLN_TopicP					to, 
					M_Rect						*cellRect, 
					OTLN_GenericCallbackData	*callbackData)
#define	saveData	((SaveTopicsCallbackData *)	callbackData)
{
	if (saveData->current <= saveData->total) {

		if (saveData->curRec->collapsed)
			OTLN_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_COLLAPSED);
		else
			OTLN_TopicFlag_CLEAR(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_COLLAPSED);

		if (saveData->curRec->selected)
			OTLN_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_SELECTED);
		else
			OTLN_TopicFlag_CLEAR(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_SELECTED);

		if (!saveData->curRec->not_expandable)
			OTLN_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_EXPANDABLE);
		else
			OTLN_TopicFlag_CLEAR(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_EXPANDABLE);

		if (saveData->curRec->family_invisible)
			OTLN_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_FAMILY_INVISABLE);
		else
			OTLN_TopicFlag_CLEAR(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_FAMILY_INVISABLE);

		if (saveData->curRec->topic_invisible)
			OTLN_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_TOPIC_INVISABLE);
		else
			OTLN_TopicFlag_CLEAR(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_TOPIC_INVISABLE);

		if (saveData->curRec->topic_solo)
			OTLN_TopicFlag_SET(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_TOPIC_SOLO);
		else
			OTLN_TopicFlag_CLEAR(OTLN_GET_TopicP_FLAGS(to), OTLN_TopicFlags_IS_TOPIC_SOLO);

		to->cell_height_multiple = saveData->curRec->cell_height_multiple;

		(saveData->current)++;
		(saveData->curRec)++;
	} else {
		saveData->done = TRUE;
	}
	
	return Err_NONE;
}
#undef	saveData

/**		OTLN_RestoreTopics		[48]
**/
Err			OTLN_RestoreTopics(OTLN_OutlineH outline, OTLN_OutlineSaveH *save)
{
	Err						err	= Err_NONE;
	long					curTotal;
	OTLN_OutlineSaveP		os;
	SaveTopicsCallbackData	saveData;
	
	err = OTLN_CountTopics(
		outline, 
		OTLN_Iterate_ALL, 
		FALSE, 
		&curTotal
	);
	
	if (!err) {
	
		if (curTotal == DH(*save)->total && curTotal > 0) {
			
			os = U_LOCK_DH(*save);
			
			saveData.total		= curTotal;
			saveData.current	= 1;
			saveData.curRec		= &(os->save);

			err = OTLN_IterateOutline(
				outline, 
				NULL, 
				OTLN_Iterate_ALL, 
				OTLN_RestoreTopicCallback, 
				(OTLN_GenericCallbackData *)&saveData
			);
			
			U_UNLOCK_RH(*save);
		}
		
		U_FREE_HANDLE(*save);
	}
	
	return err;
}

/****************************************************************
			test hit top level topics
 ****************************************************************/
typedef	struct {
	OTLN_GenericCallbackDataHeader

	short			hitVpos;

	short			newVpos;
	OTLN_TopicH		afterTopic0;
	
	short			closestPos;
} OTLN_TestTopicHitData;

/**	OTLN_TestTopicHitCB	[56]
**/
static	Err		OTLN_TestTopicHitCB(	
					OTLN_OutlineP				ol, 
					OTLN_TopicP					to, 
					M_Rect						*cellRect, 
					OTLN_GenericCallbackData	*callbackData)
#define		hitData	((OTLN_TestTopicHitData *)	callbackData)
{
	Err					err	= Err_NONE;
	short				delta;
	OTLN_TopicH			mom;
	
	err = OTLN_GetMother(to->self, &mom);
	
	if (!err) {
		if (mom == ol->outline_root) {
			
			delta = M_ABS(hitData->hitVpos - cellRect->top);
			
			if (hitData->hitVpos > cellRect->top) {
				if (delta < hitData->closestPos) {
					hitData->newVpos		= cellRect->top - 1;
					hitData->closestPos		= delta;
					err = OTLN_GetPrevSister(to->self, &hitData->afterTopic0);
				}
			} else
				hitData->done = TRUE;
		}
	}
	
	return(err);
}
#undef		hitData

/**	OTLN_TestTopicHit	[57]
**/
Err		OTLN_TestTopicHit(
	OTLN_OutlineH		outline, 
	short				vPos, 
	OTLN_TopicH			excludeTopic, 
	OTLN_TopicH			*afterTopic, 
	short				*newVpos
) {
	Err						err	= Err_NONE;
	OTLN_TestTopicHitData	hitData;
	OTLN_TopicH				ghostTopic;
	OTLN_TopicH				excludeTopic2;
	Boolean					ghostAdded = FALSE;
	
	*newVpos				= vPos;
	
	hitData.hitVpos			= vPos;
	hitData.newVpos			= OTLN_DRAG_REORDER_SENTINEL;
	hitData.closestPos		= 32000;
	hitData.afterTopic0		= NULL;
	
	err = OTLN_SetRecentTopic(outline, NULL);

	if (!err)
		err = OTLN_AddNewTopic(outline, "ghost", OTLN_AddTopicAs_LAST_DAUGHTER, &ghostTopic);

	if (!err) {
		ghostAdded = TRUE;

		err = OTLN_IterateOutline(
			outline, 
			NULL, 
			OTLN_IterateComp_STD_ONSCREEN, 
			OTLN_TestTopicHitCB, 
			(OTLN_GenericCallbackData *)&hitData
		);
	}
	
	if (!err) {
		ghostAdded = FALSE;
		err = OTLN_RemoveTopic(outline, ghostTopic);
	}
	
	if (!err)
		err = OTLN_DisposeTopic(ghostTopic);
	
	if (!err) {
		*afterTopic = hitData.afterTopic0;
	
		if (excludeTopic) {
			err = OTLN_GetPrevSister(excludeTopic, &excludeTopic2);
			
			if (!err && (excludeTopic == *afterTopic || excludeTopic2 == *afterTopic)) {
				*afterTopic		= NULL;
				hitData.newVpos	= OTLN_DRAG_REORDER_SENTINEL;
			}
		}
	}
	
	if (err) {
		if (ghostAdded) {
			Err		lameErr;
			
			lameErr = OTLN_RemoveTopic(outline, ghostTopic);
			if (!lameErr)
				(void)OTLN_DisposeTopic(ghostTopic);
		}
	};
	
	if (!err)
		*newVpos = hitData.newVpos;
	
	return(err);
}

/**	OTLN_IsVisible	[72]
**/
Err		OTLN_IsVisible(
	OTLN_OutlineH	outline, 
	OTLN_TopicH		topic, 
	Boolean			*is_onscreen
) {
	Err				err = Err_NONE;
	OTLN_TopicH		rootTopic;
	Boolean			done = FALSE;
	
	*is_onscreen = TRUE;
	
	err = OTLN_GetRootTopic(outline, &rootTopic);

	if (!err) {
		//	note: honor_topic_invisable would be checked here if
		//	we ever used it.  it is always assumed to be TRUE
		if (OTLN_IS_TopicFlag_TOPIC_INVISABLE(topic)) {
			*is_onscreen	= FALSE;
		} else do {
			err = OTLN_GetMother(topic, &topic);
			
			if (topic == rootTopic) {
				done = TRUE;
			} else {
				if (
					(
						OTLN_IS_TopicFlag_FAMILY_INVISABLE(topic) 
						&& DH(outline)->honor_family_invisable
					) || OTLN_IS_TopicFlag_COLLAPSED(topic)
				) {
					done			= TRUE;
					*is_onscreen	= FALSE;
				}
			}
		} while (!done);
	}
	
	return err;
}

typedef	struct {
	OTLN_GenericCallbackDataHeader
	M_Rect	empty_rect;
} OTLN_ClearRecentRectsData;

/**	OTLNp_ClearRecentRectsCB	[74]
**/
static	Err		OTLNp_ClearRecentRectsCB(
	OTLN_OutlineP					ol, 
	OTLN_TopicP						to, 	
	M_Rect							*cell_rect, 
	OTLN_ClearRecentRectsData		*clearData)
{
	to->recent_cell = clearData->empty_rect;
	
	return Err_NONE;
}

/**	OTLN_ClearRecentRects	[73]
**/
Err		OTLN_ClearRecentRects(OTLN_OutlineH outline)
{
	Err							err = Err_NONE;
	OTLN_ClearRecentRectsData	clear_rect_data;

	U_MEMCLR(sizeof(M_Rect), &clear_rect_data.empty_rect);
	
	err = OTLN_IterateOutline(
		outline, 
		NULL, 
		OTLN_Iterate_ALL, 
		(OTLN_IterateOutlineCallback)OTLNp_ClearRecentRectsCB, 
		NULL
	);
	
	return err;
}
