//	CDialogCopy.c

#include "O.h"
#include "stdio.h"
#include "string.h"
#include "MainEvent.h"
#include "CDialog.h"
#include "ADFS_LogFile.h"
#include "IC_Errors.h"
#include "Utils.h"
#include "ADFS_Prefs.h"

#include "CDialogCopy.h"

/********************************************************/

DGI_ItemRec		gCpy_ItemTable[DCpy_ItemStr_MAX] = {
	{	kCopy_ITEM_REMAIN_STAT,		"Items remaining to be copied:",	teJustRight,	normal	},
	{	kCopy_ITEM_REMAIN_VERB,		"",									teJustRight,	normal	},
	{	kCopy_TIME_REMAIN_STAT,		"Time Remaining:",					teJustRight,	normal	},
	{	kCopy_COPYING_STAT,			"Copying:",							teJustRight,	normal	},
	{	kCopy_FROM_STAT,			"From:",							teJustRight,	normal	},
	{	kCopy_TO_STAT,				"To:",								teJustRight,	normal	},
	{	kCopy_BYTES_COPIED_STAT,	"Bytes Copied:",					teJustRight,	normal	},
	{	kCopy_COPYING_VERB,			"",									teJustLeft,		normal	},
	{	kCopy_FROM_VERB,			"",									teJustLeft,		normal	},
	{	kCopy_TO_VERB,				"",									teJustLeft,		normal	}
};

/********************************************************/

#define		kCopyWindowCollapsedHeight		 86
#define		kCopyWindowExpandedHeight		174

CDialogCopy		*ShowCopyDialog(void)
{
	CDialogCopy		*copyP = new CDialogCopy;
	
	if (copyP) {
		if (!copyP->IDialogCopy()) {
			copyP->Dispose();
			copyP = NULL;
		}
	}

	return copyP;
}

void		DoFakeCopy(void)
{
	CDialogCopy		*copyDialogP = ShowCopyDialog();
	
	if (copyDialogP) {
		#define			kMaxProgress	((ulong)(662144))
		ulong			curBytes = 0;
		Boolean			doneB = FALSE;

		copyDialogP->SetItemRemain(1);
		copyDialogP->SetMaxProgress(kMaxProgress);
		copyDialogP->SetProgStrings("Nothing", "Nowhere", "Nowhere");
		
		do {} while (TickCount() < copyDialogP->i_startTicks + 60);
		
		do {
			doneB = copyDialogP->SetProgress(++curBytes) != noErr;
			
			if (!doneB) {
				doneB = curBytes == kMaxProgress;
			}
		} while (!doneB);
		
		copyDialogP->HideCopyDialog();
	}
}

/********************************************************/

void		CDialogCopy::HideCopyDialog(void)
{
	if (i_showingB && !i_cancelB) {
		(void)SetProgress(i_maxBytesUL);
	}

	Dispose();
}


Boolean		CDialogCopy::IDialogCopy(void)
{
	Boolean		success = TRUE;
	
	//	get it hidden, then show
	success = _inherited::IDialog(ADFS_Window_MODAL_DIALOG, 202);
	
	if (success) {
		i_itemRemainUL	= 0;
		i_maxBytesUL	= 100;
		i_curBytesUL	= 0;
		i_startTicks	= 0;
		i_twirledDownB	= FALSE;
		i_cancelB		= FALSE;
		i_showingB		= FALSE;
		
		GetSmallFontRec(&i_fontRec);
		i_fontRec.fontSize		= 10;

		memcpy(
			i_itemStrTable, gCpy_ItemTable, 
			sizeof(DGI_ItemRec) * DCpy_ItemStr_MAX);

		SetDlgItemUseStdDrawGroup(kCopy_ITEM_REMAIN_STAT, kCopy_BYTES_COPIED_VERB);
	}

	if (success) {
		WindowRef	copyWindP = GetWindowRef();
		Rect		windR = (**gPrefsH).windA[PREF_Wind_COPY];
		
		SetTitle("Copy");

		if (!EmptyRect(&windR)) {
			MoveWindow(
				copyWindP, 
				windR.left, 
				windR.top, 
				FALSE);
		}
		
		SizeWindow(
			copyWindP, 
			kCopyWindowWidth, 
			(**gPrefsH).copyTwirledDown 
				? kCopyWindowExpandedHeight 
				: kCopyWindowCollapsedHeight, 
			TRUE);
	}
	
	if (success) {
		SetModalUp(TRUE);
	}

	return success;
}

void		CDialogCopy::Dispose(void)
{
	_inherited::Dispose();
	SetModalUp(FALSE);
}

//	pass a negative numItems to hide the "items remaining" number
//	assumes you'll update the "items remain" string during 
//	IncrementProgress().  If you pass a positive number, you have
//	the option of passing NULL during IncrementProgress() for the
//	string
void		CDialogCopy::SetAsProgress(Boolean delayB, short numItems)
{
	Rect	theRect;

	SizeWindow(
		GetWindowRef(), 
		kCopyWindowWidth, 
		kCopyWindowCollapsedHeight, 
		FALSE);
	
	HideDlogItem(kCopy_TWIRLY);
	
	if (numItems < 0) {
		numItems = -numItems;
		HideDlogItem(kCopy_ITEM_REMAIN_VERB);
		i_itemStrTable[DCpy_ItemStr_ITEM_REMAIN_STAT].justifyS = teJustLeft;

		GetDlogItemRect(kCopy_ITEM_REMAIN_STAT, &theRect);
		theRect.right = kCopyWindowWidth - theRect.left;
		SetDlogItemRect(kCopy_ITEM_REMAIN_STAT, &theRect);
	} else {
		i_itemRemainUL = numItems;
	}

	HideDlogItem(kCopy_STOP_BUTTON);
	
	GetDlogItemRect(kCopy_PROGRESS_BAR, &theRect);
	theRect.right = kCopyWindowWidth - theRect.left;
	SetDlogItemRect(kCopy_PROGRESS_BAR, &theRect);

	i_maxBytesUL	= numItems;
	
	if (!delayB) {
		i_showingB		= TRUE;
		ShowWindow(GetWindowRef());
	}
}

void		CDialogCopy::IncrementProgress(Boolean delayB, char *progZ)
{
	if (progZ) {
		ADFS_Log(progZ);
		ADFS_Log("\n");

		strcpy(
			i_itemStrTable[DCpy_ItemStr_ITEM_REMAIN_STAT].itemStr, 
			progZ);

		if (!delayB) {
			InvalDialogItem(kCopy_ITEM_REMAIN_STAT);
		}
	}
	
	i_itemRemainUL--;

	if (!delayB) {
		InvalDialogItem(kCopy_ITEM_REMAIN_VERB);
		InvalDialogItem(kCopy_PROGRESS_BAR);
		InvalDialogItem(kCopy_TIME_REMAIN_VERB);
	}

	SetProgress(i_curBytesUL + 1);
	
//	WaitNTicks(120);
}

void	CDialogCopy::DoKeyDown(EventRecord *event)
{
	char		ch			= VirtualASCII(event);
	Boolean		disposeB	=
		ch == ESC_CLEAR_KEY
		|| (
			BitAnd(event->modifiers, cmdKey)
			&& (ch == '.')
		);

	if (disposeB) {
		SimulateClick(kCopy_STOP_BUTTON);
		i_cancelB = TRUE;
	} else {
		_inherited::DoKeyDown(event);
	}
}

void	CDialogCopy::DoClick(EventRecord *event)
{
	if (FrontWindow() != GetWindowRef()) {
		_inherited::DoClick(event);
	} else {
		DialogRef		theDialog;
		short			itemHit;
		
		DialogSelect(event, &theDialog, &itemHit);

		switch (itemHit) {
		
			case kCopy_STOP_BUTTON: {
				i_cancelB = TRUE;
				break;
			}
		
			case kCopy_TWIRLY: {
			    DialogItemType		itemType;
			    Handle				item;
			    Rect				theRect;
				Boolean				twirledDownB = !(**gPrefsH).copyTwirledDown;
				
				GetDialogItem(theDialog, kCopy_TWIRLY, &itemType, &item, &theRect);

				if (TrackMouse1(&theRect, O_HiliteTwirly, NULL, &twirledDownB)) {					
					(**gPrefsH).copyTwirledDown = twirledDownB;
					O_TwirlArrow(&theRect, twirledDownB);
					SavePrefs();
					
					SizeWindow(
						GetWindowRef(), 
						kCopyWindowWidth, 
						(**gPrefsH).copyTwirledDown 
							? kCopyWindowExpandedHeight 
							: kCopyWindowCollapsedHeight, 
						TRUE);
					
					InvalDialogItem(kCopy_TWIRLY);
					InvalDialogItem(kCopy_BEVEL_LINE);
				}
				break;
			}
		}
	}
}

void	CDialogCopy::Move(EventRecord *event)
{
	_inherited::Move(event);
	(**gPrefsH).windA[PREF_Wind_COPY] = GetWindowRect(WindowRect_ALL_GLOBAL);
	SavePrefs();
}

void	CDialogCopy::DialogItemStandardDrawProc(
	DialogItemIndex	itemNo, 
	Rect			*itemRectP)
{
	char				str1[256], str2[256], str3[256];
//	unsigned char		*str1P = (unsigned char *)str1;
	Boolean				drawStringB = TRUE;
	short				justifyS = teJustLeft;
	
	Prepare();

	if (
		itemNo == kCopy_COPYING_STAT
		|| itemNo >= kCopy_COPYING_VERB
	) {
		if (!(**gPrefsH).copyTwirledDown) {
			drawStringB = FALSE;
		}
	}

	switch (itemNo) {
		
		case kCopy_BEVEL_LINE: {
			drawStringB = FALSE;
			
			if ((**gPrefsH).copyTwirledDown) {
				EraseRect(itemRectP);
			}
			break;
		}
		
		case kCopy_PROGRESS_BAR: {
			FrameRect(itemRectP);
			InsetRect(itemRectP, 1, 1);

			itemRectP->right = LERP(
				itemRectP->left, itemRectP->right, 
				i_curBytesUL, 0, i_maxBytesUL);
			
			PaintRect(itemRectP);
			
			if (i_curBytesUL == 0) {
				//	barber poles
			}
			
			drawStringB = FALSE;
			break;
		}

		case kCopy_TWIRLY: {
			O_BlitTwirly(
				(**gPrefsH).copyTwirledDown 
					? O_kTwirl_DOWN 
					: O_kTwirl_UP, 
				itemRectP);
			
			drawStringB = FALSE;
			break;
		}

		case kCopy_TIME_REMAIN_VERB: {
			str1[0] = 0;
			
			if (i_startTicks) {
				ulong		curTime = TickCount();
				
				//	wait two seconds to get an idea
				if ((curTime - i_startTicks) > 120) {
					ulong	finalTime;
					ulong	remainTime;
					
					finalTime = LERP(i_startTicks, curTime, 
						i_maxBytesUL, 0, i_curBytesUL);
					
					remainTime = finalTime - curTime;
					
					FormatTicks(remainTime, str1);
				}
			}
			
			if (str1[0] == 0) {
				strcpy(str1, "Calculating");
			}
			break;
		}

		case kCopy_ITEM_REMAIN_VERB:
			sprintf(
				i_itemStrTable[DCpy_ItemStr_ITEM_REMAIN_VERB].itemStr, 
				"%lu", i_itemRemainUL);
			//	no BREAK

		case kCopy_ITEM_REMAIN_STAT:
			TextFont(FMGetFontFamilyFromName("\pCharcoal"));
			TextSize(10);
			//	no BREAK

		case kCopy_TO_VERB:
		case kCopy_FROM_VERB:
		case kCopy_COPYING_VERB:
		case kCopy_TIME_REMAIN_STAT:
		case kCopy_COPYING_STAT:
		case kCopy_FROM_STAT:
		case kCopy_TO_STAT:
		case kCopy_BYTES_COPIED_STAT: {
			short	tableIndex = GetItemTableIndex(
				i_itemStrTable, itemNo, DCpy_ItemStr_MAX);
			
			strcpy(str1, i_itemStrTable[tableIndex].itemStr);
			justifyS = i_itemStrTable[tableIndex].justifyS;
			TextFace(i_itemStrTable[tableIndex].face);
			break;
		}

		case kCopy_BYTES_COPIED_VERB: {
			FormatSize(i_curBytesUL, str2);
			FormatSize(i_maxBytesUL, str3);
			sprintf(str1, "%s of %s", str2, str3);
			break;
		}
	}

	if (drawStringB) {
		DrawCStringInRect(str1, itemRectP, justifyS);
	}
}

void		CDialogCopy::SetItemRemain(ulong itemRemainUL)
{
	i_itemRemainUL = itemRemainUL;
	InvalDialogItem(kCopy_ITEM_REMAIN_VERB);
	SetProgress(i_curBytesUL);
}

void		CDialogCopy::SetMaxProgress(ulong maxBytesUL)
{
	i_maxBytesUL = maxBytesUL;
	SetProgress(i_curBytesUL);
}

void		CDialogCopy::SetDelayTicks(ulong delayTicksL)
{
	i_delayTicksL = delayTicksL;
}

OSErr		CDialogCopy::SetProgress(ulong curBytesUL)
{
	OSErr		err = noErr;
	
	if (i_cancelB) {
		HideCopyDialog();
		err = 1;
	} else {
		ulong		curTicks = TickCount();
		
		if (i_startTicks == 0) {
			i_startTicks		= curTicks;
			i_lastProgressTicks	= 0;
			i_lastTimeEstTicks	= 0;
		}
		
		i_curBytesUL = curBytesUL;

		//	wait N second before even showing the dialog
		if (!i_showingB) {
			ulong		delayTicks	= ProgressDelayMenuToTicks((**gPrefsH).prefProgMenuS);
			
			if (curTicks > i_startTicks + delayTicks) {
				i_showingB = TRUE;
				ShowWindow(GetWindowRef());
			}
		}

		//	if we're at the end, be sure to update the progress 
		//	bar right now
		if (i_curBytesUL == i_maxBytesUL) {
			curTicks += 260;
		}
		
		//	wait every 1/4 second to update progress
		if (curTicks > i_lastProgressTicks + (i_delayTicksL > 15 ? i_delayTicksL : 15)) {
			i_lastProgressTicks = curTicks;
			InvalDialogItem(kCopy_PROGRESS_BAR);
			InvalDialogItem(kCopy_BYTES_COPIED_VERB);
			InvalDialogItem(kCopy_ITEM_REMAIN_STAT);
			InvalDialogItem(kCopy_ITEM_REMAIN_VERB);
		}
		
		//	wait every 1 second to update time estimate
		if (curTicks > i_lastTimeEstTicks + (i_delayTicksL > 60 ? i_delayTicksL : 60)) {
			i_lastTimeEstTicks = curTicks;
			InvalDialogItem(kCopy_TIME_REMAIN_VERB);
		}

		FlushUpdates();
	}

	return err;
}

void		CDialogCopy::SetProgStrings(
	char	*copyingZ, 
	char	*fromZ, 
	char	*toZ)
{
	char				str1[256];
	short				tableIndex;
	
	tableIndex = GetItemTableIndex(
		i_itemStrTable, kCopy_COPYING_VERB, DCpy_ItemStr_MAX);
	strcpy(i_itemStrTable[tableIndex].itemStr, copyingZ);

	tableIndex = GetItemTableIndex(
		i_itemStrTable, kCopy_FROM_VERB, DCpy_ItemStr_MAX);
	strcpy(i_itemStrTable[tableIndex].itemStr, fromZ);

	tableIndex = GetItemTableIndex(
		i_itemStrTable, kCopy_TO_VERB, DCpy_ItemStr_MAX);
	strcpy(i_itemStrTable[tableIndex].itemStr, toZ);

	sprintf(str1, "Copy to Ò%sÓ", toZ);
	SetTitle(str1);

	InvalDialogItem(kCopy_COPYING_VERB);
	InvalDialogItem(kCopy_FROM_VERB);
	InvalDialogItem(kCopy_TO_VERB);

	SetProgress(i_curBytesUL);
}

void		CDialogCopy::FlushUpdates(void)
{
	if (i_showingB && !i_cancelB) {
		EventRecord		theEvent;
		Boolean			availB;
		
		do {
			availB = EventAvail(everyEvent, &theEvent);

			if (availB) {
				HandleOneEvent(0);
				HandleOneEvent(0);
			}
		} while (availB);

		HandleOneEvent(0);
		HandleOneEvent(0);
	}
}
