#include "IC_FileIO.h"
#include "Carbon68kGlue.h"
#include "IC_Errors.h"
#include "Open_Save.h"

void		ReportFreeSpace(unsigned long neededMem);
/*
	    kNavCBEvent                 = 0,                            // an event has occurred (update, idle events, etc.) *
	    kNavCBCustomize             = 1,                            // protocol for negotiating customization space *
	    kNavCBStart                 = 2,                            // the navigation dialog is starting up *
	    kNavCBTerminate             = 3,                            // the navigation dialog is closing down *
	    kNavCBAdjustRect            = 4,                            // the navigation dialog is being resized *
	    kNavCBNewLocation           = 5,                            // user has chosen a new location in the browser *
	    kNavCBShowDesktop           = 6,                            // user has navigated to the desktop *
	    kNavCBSelectEntry           = 7,                            // user has made a selection in the browser *
	    kNavCBPopupMenuSelect       = 8,                            // signifies that a popup menu selection was made *
	    kNavCBAccept                = 9,                            // user has accepted the navigation dialog *
	    kNavCBCancel                = 10,                           // user has cancelled the navigation dialog *
	    kNavCBAdjustPreview         = 11,                           // preview button was clicked or the preview was resized *
	    kNavCBOpenSelection         = (long)0x80000000              // user has opened or chosen an object, v2.0 or greater *
*/
void		HandleUpdate(EventRecord *theEvent);

static pascal void MyNavEventCallback(
	NavEventCallbackMessage callBackSelector, 
	NavCBRecPtr callBackParms, 
	NavCallBackUserData callBackUD)
{
	#pragma unused(callBackUD)
		
	switch (callBackSelector) {
	
		case kNavCBEvent: {
			EventRecord		*thisEvent = ((callBackParms->eventData).eventDataParms).event;
	
			switch (thisEvent->what) {
			
				case updateEvt: {
					HandleUpdate(thisEvent);
					break;
				}
			}
			break;
		}
	}
}


static	FileFilterCB	S_FilterCB;

static	pascal Boolean MyNavObjectFilterCallback(
    AEDesc			*theItem, 
    void			*info, 
    void			*callBackUD, 
    NavFilterModes	filterMode
) {
	#pragma unused(callBackUD)
	#pragma unused(filterMode)
//	OSErr					theErr = noErr;
	Boolean					displayB = TRUE;
	NavFileOrFolderInfo		*theInfo = (NavFileOrFolderInfo*)info;
	
	if (theItem->descriptorType == typeFSS && !theInfo->isFolder && theInfo->visible) {
		OSType		fileType	= theInfo->fileAndFolder.fileInfo.finderInfo.fdType;
		FSSpec		fsSpec;
		OSErr		err;
		
		displayB = FALSE;

		err = AEGetDescData(theItem, &fsSpec, sizeof(FSSpec));
		
		if (!err && S_FilterCB && (*S_FilterCB)(
			fsSpec.name, 
			theInfo->fileAndFolder.fileInfo.dataSize, 
			fileType)
		) {
			displayB = TRUE;
		}
	}
				
	return displayB;
}

OSErr		AEGet1FSSpec(AEDescList *docListP, FSSpec *fsSpecP)
{
	OSErr	anErr = noErr;
	long	count;
	
	anErr = AECountItems(docListP, &count);

	if (anErr == noErr) {
		AEKeyword	theKeyword;
		DescType	actualType;
		Size		actualSize;
		
		// Get a pointer to selected file
		anErr = AEGetNthPtr(
			docListP, 1,
			typeFSS, &theKeyword,
			&actualType, fsSpecP,
			sizeof(FSSpec),
			&actualSize);
	}
	
	return anErr;
}

static	Boolean	IsTextFile(
	StringPtr			fileName, 
	unsigned long		fileSize, 
	OSType				fileType)
{
	return fileType == 'TEXT';
}

Boolean		GetFileOrFolder(
	Nav_FileSelectType	selectType, 
	StringPtr			promptStr, 
	FSSpec				*documentFSSpec, 
	FileFilterCB		FilterProcP0)
{
	NavEventUPP			eventProc;
	NavObjectFilterUPP  filterProc;
	OSErr				anErr		= noErr;
	Boolean				successB	= FALSE;
	unsigned long		neededMem	= 200 * 1024;
	
	PurgeMem((long)neededMem);
	CompactMem((long)neededMem);

	eventProc	= NewNavEventUPP(MyNavEventCallback);
	
	S_FilterCB	= FilterProcP0;
	filterProc	= NewNavObjectFilterUPP(MyNavObjectFilterCallback);

	if (eventProc && filterProc) {
		NavDialogOptions	dialogOptions = { 0 };
		NavReplyRecord		reply = { 0 };

		//  Specify default options for dialog box
		anErr = NavGetDefaultDialogOptions(&dialogOptions);
		if (anErr == cfragNoClientMemErr) {
			anErr = memFullErr;
		}
		
		if (anErr == noErr) {
			
			//  Adjust the options to fit our needs
			//  Set default location option
			dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation | kNavNoTypePopup;
			
			//  Clear preview option
			dialogOptions.dialogOptionFlags ^= kNavAllowPreviews;
			
			CopyStringA("\pADFS", &dialogOptions.clientName);
			CopyStringA(promptStr, &dialogOptions.message);

			switch (selectType) {
			
				case Nav_FileSelect_TEXT_FILE:
					S_FilterCB = IsTextFile;				
				case Nav_FileSelect_SPECIFIC_FILE: {
					anErr = NavChooseFile(
						NULL, &reply, &dialogOptions,
						eventProc, NULL, filterProc,
						NULL, NULL);
					break;
				}

				case Nav_FileSelect_ANY_FILE: {
					anErr = NavChooseFile(
						NULL, &reply, &dialogOptions,
						eventProc, NULL, NULL,
						NULL, NULL);
					break;
				}
					
				case Nav_FileSelect_FOLDER: {
					anErr = NavChooseFolder(
						NULL, &reply, &dialogOptions,
						eventProc, filterProc, NULL);
					break;
				}
			}
			
			if (anErr == noErr && reply.validRecord) {
			
				anErr = AEGet1FSSpec(&reply.selection, documentFSSpec);

				if (anErr == noErr) {
					successB = TRUE;
				}
				
				//  Dispose of NavReplyRecord, resources, descriptors
				anErr = NavDisposeReply(&reply);
			}
		}
		
		DisposeNavEventUPP(eventProc);
		DisposeNavObjectFilterUPP(filterProc);
	} else {
		anErr = memFullErr;
	}
	
	if (anErr == memFullErr) {
		ReportFreeSpace(neededMem);
	}

	return successB;
}

Boolean		NavSaveFile(StringPtr promptStr, StringPtr defaultStr, FSSpec *documentFSSpec)
{
	NavEventUPP			eventProc	= NewNavEventUPP(MyNavEventCallback);
	NavObjectFilterUPP  filterProc	= NewNavObjectFilterUPP(MyNavObjectFilterCallback);
	Boolean				successB	= FALSE;
	
	if (eventProc && filterProc) {
		NavDialogOptions	dialogOptions = { 0 };
		NavReplyRecord		reply = { 0 };
		OSErr				anErr = noErr;
		
		//  Specify default options for dialog box
		anErr = NavGetDefaultDialogOptions(&dialogOptions);
		
		if (anErr == noErr) {
			//  Adjust the options to fit our needs
			//  Set default location option
			dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation | kNavNoTypePopup;
			
			//  Clear preview option
			dialogOptions.dialogOptionFlags ^= kNavAllowPreviews;
			
			CopyStringA(IsADFS() ? "\pADFS" : "\pRose", &dialogOptions.clientName);
			CopyStringA(promptStr, &dialogOptions.message);
			CopyStringA(defaultStr, &dialogOptions.savedFileName);
			
			anErr = NavPutFile(
				NULL, &reply, &dialogOptions, eventProc,
				'PICT', 'ogle', NULL);

			if (anErr == memFullErr) {
				PurgeMem(100 * 1024);
				CompactMem(100 * 1024);

				anErr = NavPutFile(
					NULL, &reply, &dialogOptions, eventProc,
					'PICT', 'ogle', NULL);
			}

			if (anErr == noErr && reply.validRecord) {
				anErr = AEGet1FSSpec(&reply.selection, documentFSSpec);

				if (anErr == noErr) {
					successB = TRUE;
				}

				// Always call NavCompleteSave() to complete
				(void)NavCompleteSave(&reply, kNavTranslateInPlace);

				//  Dispose of NavReplyRecord, resources, descriptors
				(void)NavDisposeReply(&reply);
			} else if (anErr == memFullErr) {
				ReportFreeSpace(100 * 1024);
			}
		}
	} else {
		ReportFreeSpace(100 * 1024);
	}
	
	if (eventProc) {
		DisposeNavEventUPP(eventProc);
	}
	
	if (filterProc) {
		DisposeNavObjectFilterUPP(filterProc);
	}

	return successB;
}

/*
static	void	GetEnclosingFolderPath(MenuHandle theMenu, FSSpec *fileSpec)
{
	short	loop, levels = CountMenuItems(theMenu);
	Str255	pathString, tempString;
	
	pathString[0] = 0;
	
	if (levels == 1) {
		short	foundVRefNum;
		long	foundDirID;
		
		FindFolder(
			fileSpec->vRefNum, kDesktopFolderType, 
			kCreateFolder, &foundVRefNum, &foundDirID
		);
		
		FSMakeFSSpec(fileSpec->vRefNum, foundDirID, pathString, fileSpec);
	} else {
		for (loop = (short)(levels - 1); loop >= 1; loop--) {
			GetMenuItemText(theMenu, loop, tempString);
			Concat(&pathString, &tempString, &pathString);
			Concat(&pathString, &"\p:", &pathString);
		}
		
		FSMakeFSSpec(0, 0, pathString, fileSpec);
	}
}

static	ControlHandle	GetDialogButton(
	DialogPtr	theDialog, 
	short		theItem
) {
	short		iType;
	Handle		iHandle;
	Rect		iRect;
	
	GetDItem(theDialog, theItem, &iType, &iHandle, &iRect);
	
	return (ControlHandle)iHandle;
}
	

static	void	SetDlgButtonText(
	DialogPtr	theDialog, 
	short		theItem, 
	Str255		theString
) {
	Str255	finalString;
	
	Concat("\pUse Ò", theString, finalString);
	Concat(finalString, "\pÓ", finalString);
	
	SetCTitle(GetDialogButton(theDialog, theItem), finalString);
}

static	void	AbleDlgButton(
	DialogPtr	theDialog, 
	short		theItem, 
	Boolean		enabled
) {
	HiliteControl(GetDialogButton(theDialog, theItem), enabled ? 0 : 255);
}

static	pascal	Boolean	A2PX_FileFilterYDProc(
	CInfoPBPtr	pb, 
	void		*yourDataPtr
) {
	A2PX_GetFolderRec	*gfRec			= (A2PX_GetFolderRec *)yourDataPtr;
	Boolean				hideThisFile	= TRUE;

	if (IsVisible(pb)) {
	
		if (IsFolder(pb)) {
			hideThisFile = FALSE;
		} else {
			StringPtr	theName		= pb->hFileInfo.ioNamePtr;
			long		fileType	= pb->hFileInfo.ioFlFndrInfo.fdType;
		
			if ((
					gfRec->select != kSelectFolder
				) && (
					fileType == a2pixType
					|| fileType == a2pixType2
				) && (
					!HAS_AUX(theName)
				) && (
					IS_SINGLE_SIZE(pb->hFileInfo.ioFlLgLen)
					|| IS_DOUBLE_SIZE(pb->hFileInfo.ioFlLgLen)
				)
			) {
				hideThisFile = FALSE;
				
				if (
					gfRec->select == kSelectAllFiles
				) {
					AddFileToList(theName);
				}
			}
		}
	}
		
	return hideThisFile;
}

FSSpec	gFinalSpec;

static	pascal short	A2PX_DlgHookYDProc(
	short		item, 
	DialogPtr	theDialog, 
	void		*yourDataPtr
) {
	A2PX_GetFolderRec	*gfRec		= (A2PX_GetFolderRec *)yourDataPtr;
	
	if (gfRec->select == kSelectAllFiles) {
		if (
			item == sfHookOpenFolder
			|| item == sfHookOpenFolder
			|| item == sfHookGoToDesktop
			|| item == sfHookGoToAliasTarget
			|| item == sfHookGoToParent
			|| item == sfHookGoToNextDrive
			|| item == sfHookGoToPrevDrive
		) {
			KillFileList(&gFileList);
		}
	} else if (gfRec->select == kSelectFolder) {
		MenuHandle			theMenu		= GetMenuRef(-4000);
		Str255				curFolder;
		
		if (theMenu) {
			GetMenuItemText(theMenu, 1, curFolder);
			
			//	first deal with the enclosing folder
			if (!EqualString(curFolder, gfRec->enclosingFolder)) {
				CopyString(curFolder, gfRec->enclosingFolder);
				SetDlgButtonText(theDialog, kEnclosingFolderButton, curFolder);
			}
			
			//	then deal with the selected folder
			if (gfRec->sfReply->sfIsFolder || gfRec->sfReply->sfIsVolume) {
				if (!gfRec->selFoldEnabled) {
					gfRec->selFoldEnabled = TRUE;
					AbleDlgButton(theDialog, kSelectedFolderButton, TRUE);
				}

				if (!EqualString(gfRec->sfReply->sfFile.name, gfRec->selectedFolder)) {
					CopyString(gfRec->sfReply->sfFile.name, gfRec->selectedFolder);
					SetDlgButtonText(theDialog, kSelectedFolderButton, gfRec->selectedFolder);
				}
			} else if (gfRec->selFoldEnabled) {
				gfRec->selFoldEnabled = FALSE;
				AbleDlgButton(theDialog, kSelectedFolderButton, FALSE);
			}
		}
		
		switch (item) {

			case kEnclosingFolderButton: {
				GetEnclosingFolderPath(theMenu, &gfRec->sfReply->sfFile);
				//	***	NO BREAK!
			}

			case kSelectedFolderButton: {
				item = sfItemOpenButton;
				gFinalSpec = gfRec->sfReply->sfFile;
				break;
			}
		}
	}
	
	return item;
}

Boolean		GetFileOrFolder(A2PX_FileSelect select, StandardFileReply *sfReply)
{
	Point				thePoint	=	{	-1, -1	};
	SFTypeList			theTypeList	=	{	0, 0, 0, 0	};
	A2PX_GetFolderRec	gfRec;
	
	if (DialogHookCB == NULL) {
		FileFilterCB	= NewFileFilterYDProc(A2PX_FileFilterYDProc);
		DialogHookCB	= NewDlgHookYDProc(A2PX_DlgHookYDProc);
	}
	
	gfRec.select				= select;
	gfRec.sfReply				= sfReply;
	gfRec.enclosingFolder[0]	= 0;
	gfRec.selFoldEnabled		= FALSE;
	gfRec.selectedFolder[0]		= 0;
	
	CustomGetFile(
		FileFilterCB, 0, theTypeList, sfReply, 
		select == kSelectFolder ? 130 : sfGetDialogID,
		thePoint, DialogHookCB, NULL, 
		NULL, NULL, &gfRec
	);
	
	if (select == kSelectFolder) {
		sfReply->sfFile = gFinalSpec;
	}
	
	return sfReply->sfGood;
}
*/
