//	COutlineWindow.c

#include "Carbon68kGlue.h"
#include "CRenameTextEdit.h"
#include "ADFS_Prefs.h"
#include "ADFS_Menus.h"
#include "MainEvent.h"
#include "Utils.h"
#include "CEntry.h"
#include "ADFS_LogFile.h"
#include "IC_Errors.h"
#include "ADFS_O_Callbacks.h"
#include "O.h"
#include "CFinderWindowHeader.h"
#include "COutlineWindow.h"

#define	NewObject(object, type, err)		\
	((object = new type) != NULL)			\
		? TRUE								\
		: !ReportError(err = IC_Err_OUT_OF_MEMORY)
		
Boolean		COutlineWindow::IOutlineWindow(
	ADFS_WindowType			windowType, 
	short					resourceID, 
	O_TopicRef				*topicRef 
) {
	OSErr			err = noErr;
	Boolean			success = TRUE;
	
	if (success) {
		if (NewObject(i_header, CFinderWindowHeader, err)) {
			err = i_header->IFinderWindowHeader((CFinderWindow *)this);
		}
		
		if (err != noErr) {
			success = FALSE;
		}
	}
	
	if (success) {
		if (topicRef->cOutline) {
			i_topicRef	= *topicRef;
			i_owner		= FALSE;
		} else {
			i_owner = TRUE;
			
			U_ASSERT(0);
			
			if (NewObject(i_topicRef.cOutline, O_COutline, err)) {
				extern	long	gErr;

				err = i_topicRef.cOutline->O_InitOutline();
				if (!err) err = i_topicRef.cOutline->O_GetRoot(&i_topicRef.cTopic);
			}

			success = err = noErr;
		}
	}
	
	if (success) {
		success	= _inherited::IDocument(windowType, resourceID);	
	}
	
	if (success) {
		err = Prepare();
		success = err == noErr;
	}
	
	if (success) {
		ADFS_FontRec	fontRec;
		
		GetSmallFontRec(&fontRec);
		SetFontRec(&fontRec);
	
		UnPrepare();

		AdjustScrollbars();
	}
	
	i_usingOffscreens		= FALSE;
	i_usingEraseRgns		= TRUE;
	i_dragHitTopic			= NULL;
	
	return success;
}

void		COutlineWindow::Dispose(void)
{
	Prepare();
	
	CRenameTextEdit::FinishRename();
	
	i_header->Dispose();
	
	if (i_topicRef.cOutline && i_owner) {
		i_topicRef.cOutline->O_DisposeOutline();
	}
	
	UnPrepare();
	
	_inherited::Dispose();
}

OSErr		COutlineWindow::Prepare(void)
{
	OSErr	err = noErr;
	short	vScroll = GetControlValue(i_vScrollbar);
	short	hScroll = GetControlValue(i_hScrollbar);
	Rect	theRect = GetWindowRect(WindowRect_ALL);
	
	if (!err) {
		if (*(long *)&theRect != 0) {
			SetOrigin(0, 0);
			ReportError(IC_Err_ORIGIN_NOT_ZERO);
		}
		
		if (i_prepared) {
			ReportError(IC_Err_ALREADY_PREPARED);
		}
	}
	
	if (!err) err = _inherited::Prepare();
	if (!err) err = i_topicRef.cOutline->O_SetCallbackDispatch(S_OutlineWindowDispatchCB);
	if (!err) err = i_topicRef.cOutline->O_SetCustomData(this);
	
	if (!err) {
		SetOrigin(hScroll, vScroll - GetWindowRect(WindowRect_HEADER).bottom);
			
		theRect = GetWindowRect(WindowRect_INTERIOR);
		ClipRect(&theRect);

		i_prepared = TRUE;
	}
	
	return err;
}

void		COutlineWindow::UnPrepare(void)
{
	i_prepared = FALSE;
	SetPort(GetGrafPtr());
	SetOrigin(0, 0);

	OpenClipRect();
}

O_CTopic		*COutlineWindow::GetRootTopic(void)
{
	O_CTopic	*firstTopic = NULL;
			
	if (i_topicRef.cOutline && i_topicRef.cTopic) {
		firstTopic = i_topicRef.cTopic;
	}
	
	return firstTopic;
}

O_CTopic		*COutlineWindow::GetFirstTopic(void)
{
	O_CTopic		*firstTopic = GetRootTopic();
	Err				err = noErr;
			
	if (firstTopic) {
		err = firstTopic->O_GetIndTopic(0, &firstTopic);
	}
	
	if (err) firstTopic = NULL;
	
	return firstTopic;
}

//	thePoint is in global coordinates
Boolean		COutlineWindow::GetWindowHit(
	Point			thePoint, 
	WindowRectType	*pane, 
	short			*subPane, 
	O_CTopic		**topic, 
	Rect			*hitRect
) {
	Err			err = noErr;
	Boolean		hit = FALSE;
	
	err = Prepare();
	
	if (!err) {
		GlobalToLocal(&thePoint);

		for (
			*pane = WindowRect_HEADER; 
			*pane <= WindowRect_INTERIOR; 
			*pane = (WindowRectType)((*pane) + 1)
		) {
			*hitRect = GetWindowRect(*pane);
			
			if (PtInRect(thePoint, hitRect)) {
				hit = TRUE;
				break;
			}
		}
		
		if (!hit) {
			*pane = WindowRect_NONE;
		} else switch (*pane) {
		
			case WindowRect_HEADER: {
				i_header->HitTest(thePoint, pane, subPane, hitRect); 
				break;
			}

			case WindowRect_INTERIOR: {
				O_CTopic		*firstTopic;
				
				*topic = NULL;
				firstTopic = GetFirstTopic();
				
				if (!err && firstTopic) {
					err = firstTopic->O_HitTestFromHere(
						*(Point *)&thePoint, topic
					);
					
					//	if you miss all topics, you hit the root of the window
					//	but you can't hit the root topic.
/*					if (!err) {
						if (*topic == NULL) {
							CEntry		*rootP = GetTopicEntry(i_topicRef.cTopic);
							
//							if (rootP && rootP->i_type != FSObject_DISK_ROOT_FOLDER) {
								//*topic = i_topicRef.cTopic;
//							}
						}
					}
*/
				}

				if (err) {
					*pane = WindowRect_NONE;
				}

				break;
			}
		}
		
		UnPrepare();
	}

	return *pane != WindowRect_NONE;
}

void	COutlineWindow::DoClick(EventRecord *event)
{
	Point			hitPoint = event->where;
	WindowRectType	pane;
	short			subPane;
	O_CTopic		*topic;
	Rect			hitRect;
	
	_inherited::DoClick(event);
		
	if (GetWindowHit(hitPoint, &pane, &subPane, &topic, &hitRect)) {
	
		Prepare();
		GlobalToLocal(&hitPoint);

		switch (pane) {

			case WindowRect_HEADER_STAT_INFO: {
				CRenameTextEdit::FinishRename();
				i_header->DoClick(hitPoint, pane, subPane, &hitRect);
				break;
			}

			case WindowRect_INTERIOR: {
				//if (space bar is down) {
				//	DoPanWithHand(hitPoint);
				
				if (topic) {
					DoTopicClick(topic, hitPoint, event->modifiers);
				} else {
					CRenameTextEdit::FinishRename();
					
					if (gDoubleClick) {
						DoCommand(cmdOpenDisk);
					} else {
						MarqueeSelect(hitPoint, event->modifiers);
					}
				}
				break;
			}
			
			default: {
				CRenameTextEdit::FinishRename();
				break;
			}
		}

		UnPrepare();
	} else {
		CRenameTextEdit::FinishRename();
	}
}

void		COutlineWindow::DoPanWithHand(Point	hitPoint)
{
}

void		COutlineWindow::DeSelectAll(void)
{
	(void)i_topicRef.cOutline->O_SelectAll(FALSE, TRUE, NULL);
}



void		COutlineWindow::DoTopicClick(O_CTopic *cTopic, Point hitPoint, short modifiers)
{
	SysBeep(1);
}

void		COutlineWindow::GetLineAndPageScrolls(
	WindowRectType	scrollbar, 
	short			*line, 
	short			*page
) {
	Rect	interior = GetWindowRect(WindowRect_INTERIOR);

	if (scrollbar == WindowRect_V_SCROLL) {
		*line = O_OutlineCellHeight(i_topicRef.cOutline);
		*page = (interior.bottom - interior.top) - *line;
	} else {
		*line = 15;
		*page = (interior.right - interior.left) - *line;
	}
}

void	COutlineWindow::InvalWindow(WindowRectType windowRect)
{
	Boolean		prepared = i_prepared;
	
	SetPort(GetGrafPtr());
	
	if (prepared) {
		UnPrepare();
	}
	
	_inherited::InvalWindow(windowRect);

	if (prepared) {
		Prepare();
	}
}

void	COutlineWindow::Draw(void)
{
	Err					err = noErr;
	long				bottom = -1;
	
	ADFS_Log("------ Begin Drawing Window\n");
	
	_inherited::Draw();
	
	if (!i_usingOffscreens) {
		i_invalid = TRUE;
	}

	if (i_invalid) {
		i_header->Draw();

		err = Prepare();
		
		PreDraw();

		if (!err) {
			O_CTopic		*topic;

			if ((topic = GetFirstTopic()) != NULL) {
				if (!err) err = topic->O_DrawFromHere(&bottom);
			} else {
				bottom = 0;
			}
		}
		
		PostDraw(bottom);
		
		i_invalid = FALSE;
		UnPrepare();
	}
	
	ADFS_Log("------ End Drawing Window\n");
}

void	COutlineWindow::PreDraw(void)
{
	if ((**gPrefsH).redBackgroundB) {
		Rect	theRect = GetWindowRect(WindowRect_INTERIOR);

		ForeColor(redColor);
		PaintRect(&theRect);
		ForeColor(blackColor);
	}
}

void	COutlineWindow::PostDraw(long bottom)
{
	if (bottom > -1) {
		Rect	theRect = GetWindowRect(WindowRect_INTERIOR);

		theRect.top = bottom;
		EraseRect(&theRect);
	}
}

Boolean	COutlineWindow::DoCommand(long command)
{
	Boolean		handled = FALSE;
	
	switch (command) {
	
		default: {
			handled = _inherited::DoCommand(command);
			break;
		}
	}
	
	return handled;
}

void	COutlineWindow::UpdateMenus(void)
{
	EnableCommand(cmdPreferences);
	EnableCommand(cmdAboutADFS);
	EnableCommand(cmdOpenDisk);
	EnableCommand(cmdNewDisk);
	EnableCommand(cmdQuit);

	_inherited::UpdateMenus();
}


//	static
long		COutlineWindow::S_OutlineWindowDispatchCB(	
	O_TopicRefP	topicRef, 
	O_CBType				cbType, 
	O_CBDataP			cbData
) {
	COutlineWindow		*thiz;
	
	topicRef->cOutline->O_GetCustomData((void **)&thiz);
	return thiz->OutlineWindowDispatchCB(topicRef, cbType, cbData);
}

long		COutlineWindow::OutlineWindowDispatchCB(
	O_TopicRefP			topicRef, 
	O_CBType			cbType, 
	O_CBDataP			cbData
) {
	switch (cbType) {

		case O_CB_GET_FRAME: {
			cbData->frame.frame = GetWindowRect(WindowRect_ALL);
			break;
		}
	}
	
	return 0;
}


Rect	COutlineWindow::GetScrollExtents(void)
{
	Rect		extentsR	= _inherited::GetScrollExtents();
	O_CTopic	*topic;
	
	extentsR.right		= 30 + 5 + kScrollbarWidth;
	
	if ((topic = GetFirstTopic()) != NULL) {
		long	pixels;
		
		topic->O_CountVisCellsFromHere(&pixels);
		
		extentsR.bottom = pixels * O_OutlineCellHeight(i_topicRef.cOutline);
	}
	
	return extentsR;
}

void		COutlineWindow::GetScrollMaxs(
	short	*hMax, 
	short	*vMax
) {
	_inherited::GetScrollMaxs(hMax, vMax);
}

/*
	Err			err			= noErr;
	short		hMin;
	Rect		interior;
	O_CTopic	*topic;
	
	hMin = 30 + 5 + kScrollbarWidth;
	
	interior = GetWindowRect(WindowRect_INTERIOR);
	
	if ((topic = GetFirstTopic()) != NULL) {
		long	pixels;
		
		if (!err) err = topic->O_CountVisCellsFromHere(&pixels);
		
		pixels *= O_OutlineCellHeight(i_topicRef.cOutline);
		
		if (!err) {
			*vMax = pixels - (interior.bottom - interior.top);
			
			if (*vMax < 0)
				*vMax = 0;
		}
	}

	*hMax = hMin - (interior.right - interior.left);
	
	if (*hMax < 0)
		*hMax = 0;
}
*/

void	COutlineWindow::AdjustScrollbars(void)
{
	Boolean		prepared = i_prepared;
	
	SetPort(GetGrafPtr());
	
	if (prepared) {
		UnPrepare();
	}
	
	_inherited::AdjustScrollbars();

	if (prepared) {
		Prepare();
	}
}
	
void	COutlineWindow::DoKeyDown(EventRecord *event)
{
	_inherited::DoKeyDown(event);
}
	
void	COutlineWindow::Idle(void)
{
	_inherited::Idle();
}
	
void	COutlineWindow::UpdateFontInfo(ADFS_FontRec *fontRec)
{
	unsigned char	fontName[256];
	short			heightS;
	
	CopyString(fontRec->fontName, fontName);
	CopyPascalStringToC(fontName, (char *)fontName);
	(void)i_topicRef.cOutline->O_SetFontInfo((char *)fontName, fontRec->fontSize);
	
	(void)i_topicRef.cOutline->O_GetCellHeight(&heightS);
	
	if (heightS < ADFS_MinCellHeight) {
		(void)i_topicRef.cOutline->O_SetCellHeight(ADFS_MinCellHeight);
	}

	_inherited::UpdateFontInfo(fontRec);
}

Rect		COutlineWindow::GetWindowRect(WindowRectType wrType)
{
	Rect		theRect;
	
	switch (wrType) {

		case WindowRect_HEADER_DISK_INFO: {
			theRect = _inherited::GetWindowRect(WindowRect_ALL);
			theRect.bottom = theRect.top + ADFS_HeaderHeight_INFO;
			break;
		}
		
		case WindowRect_HEADER_STAT_INFO: {
			if (i_header->i_showStats) {
				theRect = GetWindowRect(WindowRect_HEADER_DISK_INFO);
				theRect.top		= theRect.bottom;
				theRect.bottom	= theRect.top + ADFS_HeaderHeight_STAT;
			}
			break;
		}

		case WindowRect_HEADER: {
			theRect = GetWindowRect(WindowRect_HEADER_DISK_INFO);
			if (i_header->i_showStats) {
				theRect.bottom += ADFS_HeaderHeight_STAT;
			}
			break;
		}
		
		default: {
			theRect = _inherited::GetWindowRect(wrType);
			break;
		}
	}
	
//	SetOrigin(hScroll, vScroll - GetWindowRect(WindowRect_HEADER).bottom);

	return theRect;
}


