//	CRenameTextEdit.cpp
#include "IC_Errors.h"
#include "ADFS_Menus.h"
#include "Carbon68kGlue.h"
#include "ADFS_Commands.h"
#include "string.h"
#include "Utils.h"
#include "CRenameTextEdit.h"

/***********************************************/
// static
CRenameTextEdit		*CRenameTextEdit::i_curTextEdit = NULL;

// static
CRenameTextEdit		*CRenameTextEdit::GetCurTextEdit(void)
{
	return i_curTextEdit;
}

// static
void				CRenameTextEdit::FinishRename(void)
{
	if (i_curTextEdit) {
		i_curTextEdit->Finish();
	}
}

/***********************************************/
CRenameTextEdit		*GetNewRenameTextEdit(
	const	char				*text, 
	Rect						*viewRect, 
	ulong						maxBytes, 
	FinishRenameTextEditCB		finishRenameCB, 
	void						*finishRenameData, 
	long						refconL)
{
	CRenameTextEdit		*renameTE = new(CRenameTextEdit);
	
	if (renameTE) {
		if (!renameTE->IRenameTextEdit(
			text, viewRect, maxBytes, 
			finishRenameCB, 
			finishRenameData, 
			refconL)
		) {
			renameTE->Dispose();
			renameTE = NULL;
		}
	}
	
	return renameTE;
}

Boolean		CRenameTextEdit::IRenameTextEdit(
	const char					*text, 
	Rect						*viewRect, 
	ulong						maxBytes, 
	FinishRenameTextEditCB		finishRenameCB, 
	void						*finishRenameData, 
	long						refconL)
{
	Boolean				successB = FALSE;
	Rect				destRect;
	TEHandle			te;
		
	i_maxBytes			= maxBytes;
	i_finishRenameCB	= finishRenameCB;
	i_finishRenameData	= finishRenameData;
	i_refconL			= refconL;
	i_allow_returnB		= FALSE;
	i_doKeyDownCB		= NULL;
	i_doKeyDownRefcon	= NULL;
	i_te				= NULL;

	if (i_curTextEdit) {
		GrafPtr		sp;
		
		GetPort(&sp);
		i_curTextEdit->Finish();
		SetPort(sp);
	}

	destRect		= *viewRect;
	destRect.right	= 32767;
	te = TENew(&destRect, viewRect);

	if (te) {
		i_te = te;
		successB = TRUE;
		
		i_curTextEdit = this;
		
		if (IsADFS()) {
			(**i_te).fontAscent	-= 1;
			(**i_te).lineHeight	-= 1;
		}
		
		SetText((char *)text);
		TESetSelect(0, 32767, i_te);
		TEAutoView(TRUE, i_te);

		{
			Rect		nopRect = { 0, 0, 0, 0 };
			Rect		port_rect;
			CGrafPtr	thePort;
			
			GetPort((GrafPtr *)&thePort);
			ClipRect(&nopRect);
			TEActivate(i_te);
			GetPortBounds(thePort, &port_rect);
			ClipRect(&port_rect);
			
			nopRect = GetViewRectFrame();
			InvalWindowRect(GetWindowFromPort(thePort), &nopRect);
		}
	}
	
	return successB;
}

void	CRenameTextEdit::Dispose(void)
{
	ASSERT(i_curTextEdit == this);
	i_curTextEdit = NULL;

	TEDispose(i_te);
	
	delete this;
}

void	CRenameTextEdit::SetKeyDownCallback(
	DoKeyDown_CB	keyDownCallback,
	void			*keyDownRefcon)
{
	i_doKeyDownCB		= keyDownCallback;
	i_doKeyDownRefcon	= keyDownRefcon;
}

void	CRenameTextEdit::SetCancelCallback(
	CancelRenameTextEditCB	cancelCB, 
	void					*cancelData)
{
	i_cancelCB0		= cancelCB; 
	i_cancelData0	= cancelData;
}

Rect	CRenameTextEdit::GetViewRect(void)
{
	Rect	theRect = (**i_te).viewRect;
	
	return theRect;
}

Rect	CRenameTextEdit::GetViewRectFrame(void)
{
	Rect	theRect = GetViewRect();
	
	InsetRect(&theRect, -2, -2);
	
	return theRect;
}

void	CRenameTextEdit::SetViewRect(Rect *viewRect)
{
	(**i_te).viewRect = *viewRect;
}

void	CRenameTextEdit::Resize(Rect *newRect)
{
	SetViewRect(newRect);
	(**i_te).destRect = *newRect;

	TECalText(i_te);
}

void	CRenameTextEdit::Finish(void)
{
	(*i_finishRenameCB)(i_finishRenameData);
}

void	CRenameTextEdit::Cancel(void)
{
	if (i_cancelCB0) {
		(*i_cancelCB0)(i_cancelData0);
	}
}

long	CRenameTextEdit::TextLength(void)
{
	return (**i_te).teLength;
}

TextHandle	CRenameTextEdit::GetTextH(Boolean lockB)
{
	Handle		textH = TEGetText(i_te);
	
	if (lockB) {
		HLock(textH);
	}
	
	return textH;
}

char	*CRenameTextEdit::GetText(char *text)
{
	long		length	= TextLength();
	TextHandle	textH	= GetTextH();
	
	memcpy(text, *textH, length);
	text[length] = 0;
	
	return text;
}

void	CRenameTextEdit::SetText(char *text)
{
	TESetText(text, strlen(text), i_te);
}

void	CRenameTextEdit::Idle(void)
{
	TEIdle(i_te);
}

ulong	CRenameTextEdit::SelLength(void)
{
	long	length = (**i_te).selEnd - (**i_te).selStart;

	if (length < 0) {
		length = 0;
	}

	return (ulong)length;
}

void	CRenameTextEdit::Set_AllowReturn(Boolean allow_returnB)
{
	i_allow_returnB = allow_returnB;
}

void	CRenameTextEdit::DoKeyDown(char theChar, Byte keyCodeByte, EventRecord *macEvent)
{
//	unsigned short	keyCode = keyCodeByte;

	if (i_doKeyDownCB) {
		(*i_doKeyDownCB)(theChar, keyCodeByte, macEvent, i_doKeyDownRefcon);
	}

	if (theChar == ESC_CLEAR_KEY) {
		Cancel();
	} else if (theChar == ENTER_KEY || (!i_allow_returnB && theChar == RETURN_KEY)) {
		Finish();
	} else {
		char		safety_str[2];
		short		charSize		= 1;
		Boolean		allowKey		= TRUE;
		ulong		selLength		= SelLength();

		/* jgn - 11/9/95
		   The TEKey function has knowledge of and access to the 2nd Byte of incoming
		   DBCs.  So to limit the size we must check if there is room for a DBC here
		*/

		safety_str[0] = theChar;
		safety_str[1] = 0;
		
		if (
			(TextLength() - selLength) + charSize > i_maxBytes
		) {
			allowKey = FALSE;
			
			if (theChar == LEFT_ARROW_KEY || theChar == RIGHT_ARROW_KEY || theChar == DELETE_KEY) {
				allowKey = TRUE;
			}
		}
		
		if (theChar == FWD_DELETE_KEY && selLength == 0) {
			allowKey = (**i_te).selEnd < TextLength();
		}

		if (allowKey) {
			if (theChar == FWD_DELETE_KEY) {
				
				if (selLength == 0) {
					TEKey(RIGHT_ARROW_KEY, i_te);
				}
				
				TEKey(DELETE_KEY, i_te);
			} else {
				TEKey(theChar, i_te);
			}
		} else {
			SysBeep(1);
		}
	}
}

void	CRenameTextEdit::GetTEStats(
	Rect		*view_rect0, 
	Rect		*dest_rect0, 
	ulong		*sel_start0, 
	ulong		*sel_end0, 
	ulong		*text_length0,
	ulong		*line_height0, 
	ulong		*n_lines0)
{
	if (view_rect0) {
		*view_rect0 = GetViewRect();
	}

	if (dest_rect0) {
		*dest_rect0 = (**i_te).destRect;
	}

	if (sel_start0) {
		*sel_start0 = (**i_te).selStart;
	}

	if (sel_end0) {
		*sel_end0 = (**i_te).selEnd;
	}

	if (text_length0) {
		*text_length0 = TextLength();
	}

	if (line_height0) {
		*line_height0 = (**i_te).lineHeight;
	}

	if (n_lines0) {
		char	*text = *((**i_te).hText);

		*n_lines0 = (**i_te).nLines;
		
		if (text[TextLength() - 1] == 0x0D) {
			(*n_lines0)++;
		}
	}
}

//	SBI:U.h
#define U_ALLOCN_PTR_ERR(LOC, TYPE, N, WHAT_Z, P) \
	(P = U_ALLOCN_PTR(LOC, TYPE, N, WHAT_Z)) == NULL ? Err_ALLOC : Err_NONE

void	CRenameTextEdit::InsertText(char *insertZ)
{
	TEDelete(i_te);
	TEInsert(insertZ, strlen(insertZ), i_te);
}

/*
	ulong		insertion_lenLu	= strlen(insertZ);
	ulong		sel_startLu, sel_endLu, str_endLu, final_carat_posLu;
	char		*finalZ, *sourceZ = NULL;
	OSErr		err = noErr;

	//	STR_ENTRY(1571, "text buffer")
	finalZ = TrackNewPtrClear("text buffer", i_maxBytes + i_maxBytes);

	if (finalZ) {
		sourceZ = TrackNewPtrClear("text buffer 2", i_maxBytes);
		
		if (sourceZ) {
			GetText(sourceZ);
			
			sel_startLu			= (**i_te).selStart;
			sel_endLu			= (**i_te).selEnd;
			str_endLu			= strlen(sourceZ);
			final_carat_posLu	= sel_startLu + insertion_lenLu;

			//	copy start of string to sel-start
			memcpy(sourceZ, finalZ, sel_startLu);

			//	copy our text in
			memcpy(insertZ, &(finalZ[sel_startLu]), insertion_lenLu);

			//	copy sel-end to end of string
			memcpy(
				&(sourceZ[sel_endLu]), 
				&(finalZ[final_carat_posLu]), 
				str_endLu - sel_endLu + 1);
			
			//	truncate if necessary;
			if (i_maxBytes + i_maxBytes >= RTE_ABSOLUTE_MAX) {
				finalZ[RTE_ABSOLUTE_MAX] = 0;
			}

			//	set the text-edit to the new constructed string
			SetText(finalZ);

			//	and set the insert carat to just after the insertion
			TESetSelect(final_carat_posLu, final_carat_posLu, i_te);
			
			TrackDisposePtr(sourceZ);
		}
		
		TrackDisposePtr(finalZ);
	};
}
*/

Boolean		CRenameTextEdit::WillHandleCommand(long cmd, RTE_CommandType *te_cmd)
{
	Boolean		handledB = TRUE;

	switch (cmd) {
		
		case cmdCut: {
			*te_cmd = RTE_Command_CUT;
			break;
		}	
		
		case cmdCopy: {
			*te_cmd = RTE_Command_COPY;
			break;
		}	
		
		case cmdPaste: {
			*te_cmd = RTE_Command_PASTE;
			break;
		}	
		
		case cmdClear: {
			*te_cmd = RTE_Command_CLEAR;
			break;
		}	
		
		case cmdSelectAll: {
			*te_cmd = RTE_Command_SELECT_ALL;
			break;
		}	
		
		default: {
			*te_cmd = RTE_Command_NONE;
			handledB = FALSE;
			break;
		}	
	}

	return handledB;
}


void	CRenameTextEdit::DoCommand(RTE_CommandType cmd)
{
	switch (cmd) {

		case RTE_Command_CUT: {
			ClearCurrentScrap();
			TECut(i_te);
			TEToScrap();
			break;
		}

		case RTE_Command_COPY: {
			ClearCurrentScrap();
			TECopy(i_te);
			TEToScrap();
			break;
		}

		case RTE_Command_PASTE: {
			TEFromScrap();
			TEPaste(i_te);
			break;
		}
		
		case RTE_Command_CLEAR: {
			if (SelLength() > 0) {
				TEKey(DELETE_KEY, i_te);
			}
			break;
		}

		case RTE_Command_SELECT_ALL: {
			TESetSelect(0, 32767, i_te);
			break;
		}
	}
}


void		CRenameTextEdit::UpdateMenus(void)
{
	if (SelLength()) {
		EnableCommand(cmdCut);
		EnableCommand(cmdCopy);
		EnableCommand(cmdClear);
	}

	EnableCommand(cmdSelectAll);
	EnableCommand(cmdPaste);
}

Boolean		CRenameTextEdit::DoClick(Point thePoint, short modifierKeys, long when)
{
	Rect		viewRect	= GetViewRect();
	Boolean		clickedB	= FALSE;
	
	if (MacPtInRect(thePoint, &viewRect)) {
		TEClick(thePoint, (modifierKeys & shiftKey) != 0, i_te);
		clickedB = TRUE;
	} else {
		Finish();
	}
	
	return clickedB;
}

void		CRenameTextEdit::Draw(void)
{
	Rect	theRect = GetViewRectFrame();

	EraseRect(&theRect);
	MacFrameRect(&theRect);

	TEUpdate(&theRect, i_te);
}

void	CRenameTextEdit::GetCBData(void **refconPV, long *refconL)
{
	*refconPV	= i_finishRenameData;
	*refconL	= i_refconL;
}

