/*	
Service Routines for CustomGetFile:

e.g:
	CustomGetFile(
				(FileFilterYDUPP)GetRoutineAddress(MyCustomFileFilter),
				-1, *(SFTypeList *)&MyTypeList.typeList,
				&mySFR,
				CustomGetFileDLOG,
				sfgfpos,
				 (DlgHookYDUPP)GetRoutineAddress(MySFGetDlgHook),
				nil,
				activeList,
				nil,
				(void *) &MyTypeList
				);


*/

#include <Folders.h>
#include <Aliases.h>
#include <sound.h>
#include <string.h>

/* #include "ZipGUI.h" */
#include "helpers.h"
#include "macstuff.h"
#include "GetFold.h"

/* constants */

#define kListItemBox        7
#define	kShowAnyButton		10
#define kSelectAnyItem		11
#define kTitleString		12
#define kEntryFilename		13
#define kShowInvisiblesButton 14
#define	CustomGetFileDLOG	160
#define	CustomGetVolumeDLOG	161

/*
**	The SFData record contains the "global" data that the dialog hook function,
**	the file filter function, or the modal-dialog filter need to access.
*/

struct SFData
{
	StandardFileReply *SFRPtr;		/* Pointer to reply record */
	FSSpec	oldChoice;				/* The selection seen last by the dialog hook */
	Boolean	showInvisibles;			/* If TRUE, show invisible folders */
	Boolean showVolumesOnly;		/* If TRUE, show Volumes */
	Boolean showFolders;			/* If TRUE, show Folders */
	Boolean showFiles;				/* If TRUE, show Files */
	short	numTypes;
	OSType	typeList[5];
	Boolean	ShowAny;
	Boolean	Inited;
	unsigned char *pTitleString;
	unsigned char *pFileName;
};
typedef struct SFData SFData;
typedef SFData *SFDataPtr;


/* globals */
short	activeList[3] = {2,kEntryFilename,kListItemBox};
Point	sfgfpos = { -1, -1 };  /* center dialog */


/* prototypes */
pascal Boolean	MyCustomFileFilter(CInfoPBPtr myCInfoPBPtr, SFDataPtr myDataPtr);
pascal short  MySFGetDlgHook( short MySFitem, DialogPtr dlgPtr, SFDataPtr myDataPtr);
static	void	ActivateButton(DialogPtr theDlgPtr, short buttonID);
static	void	InactivateButton(DialogPtr theDlgPtr, short buttonID);

/*
 * CustomGetFile
 */
 
/*****************************************************************************/
/*
**	ActivateButton makes the button active.
*/

static	void	ActivateButton(DialogPtr theDlgPtr, short buttonID)
{
	short	itemType;
	Handle	item;
	Rect	box;

	Assert_it(theDlgPtr,"theDlgPtr == NULL","") 	

	GetDialogItem(theDlgPtr, buttonID, &itemType, &item, &box);
	HiliteControl((ControlHandle)item, 0);
}

/*****************************************************************************/
/*
**	InactivateButton makes the button inactive.
*/

static	void	InactivateButton(DialogPtr theDlgPtr, short buttonID)
{
	short	itemType;
	Handle	item;
	Rect	box;

	Assert_it(theDlgPtr,"theDlgPtr == NULL","") 

	GetDialogItem(theDlgPtr, buttonID, &itemType, &item, &box);
	HiliteControl((ControlHandle)item, 255);
}



/*****************************************************************************/
/*
**	MyCustomFileFilter filters all items.
*/

pascal Boolean	MyCustomFileFilter(CInfoPBPtr myCInfoPBPtr, SFDataPtr myDataPtr)
{
Boolean result = true;
short	i;

Assert_it(myDataPtr,"myDataPtr == NULL","") 

if (myDataPtr->showVolumesOnly)
	{
	/* List visible volumes only */
	if ( (myCInfoPBPtr->dirInfo.ioDrParID == fsRtParID) &&
		 ((myCInfoPBPtr->dirInfo.ioFlAttrib & ioDirMask) != 0) &&
		 ((myCInfoPBPtr->dirInfo.ioDrUsrWds.frFlags & kIsInvisible) != 0) )
	{
		 result = false;
	}
return ( result );
}


if (((myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdFlags & fInvisible) != 0) &&
	!myDataPtr->showInvisibles )
	return true;


if (myDataPtr->showFolders && myDataPtr->showFiles )
	{
	if (( myDataPtr->ShowAny ) ||
		(((myCInfoPBPtr->hFileInfo.ioFlAttrib>>4) & 0x01) == 1)	)
		{
		result = false;
	}
	else
	{
	for(i=0, result = FALSE; i<	myDataPtr->numTypes ; i++)
		{
			if ( result = (	myDataPtr->typeList[i] ==  
							myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType ))
			break;									
		}
		result = !result;
	}
return ( result );
}


if (myDataPtr->showFolders)
	{
	/* is this a directory? */
	if ( (myCInfoPBPtr->hFileInfo.ioFlAttrib & ioDirMask) != 0 )
	{
		if ( myDataPtr->showInvisibles )
			result = false;	/* show invisibles, too */
		else
			/* filter out invisibles */
			result = ((myCInfoPBPtr->dirInfo.ioDrUsrWds.frFlags & kIsInvisible) != 0);
	}

return ( result );
}

return true;
}



/*****************************************************************************/
/*
**	MySFGetDlgHook 
*/

pascal short  MySFGetDlgHook( short MySFitem, DialogPtr dlgPtr,SFDataPtr myDataPtr )
{
	short	result = MySFitem;
	short	value;
	short	iType;
	Handle	iHandle;
	Rect	iRect;
	
Assert_it(myDataPtr,"myDataPtr == NULL","") 
Assert_it(dlgPtr,"dlgPtr == NULL","") 

if ( GetWRefCon(dlgPtr) == sfMainDialogRefCon )
	{
	switch(MySFitem)
	{
		case sfHookFirstCall:
			GetDialogItem( dlgPtr, kTitleString, &iType, &iHandle, &iRect);
			SetDialogItemText( iHandle, myDataPtr->pTitleString ); 

			GetDialogItem( dlgPtr, kEntryFilename, &iType, &iHandle, &iRect);
			SetDialogItemText( iHandle, myDataPtr->pFileName ); 

			if (myDataPtr->showFiles == true)
				{ 
				GetDialogItem(	dlgPtr, kShowAnyButton, &iType, &iHandle, &iRect);
				SetControlValue( (ControlHandle) iHandle, (short) myDataPtr->ShowAny );

				GetDialogItem(	dlgPtr, kShowInvisiblesButton, &iType, &iHandle, &iRect);
				SetControlValue( (ControlHandle) iHandle, (short) myDataPtr->showInvisibles );
				} 
			else
				{
				InactivateButton(dlgPtr, kShowInvisiblesButton);
				InactivateButton(dlgPtr, kShowAnyButton);
				result = sfHookGoToDesktop; 
				}
		break;

		case sfHookLastCall:			
		break;
					
		case kShowAnyButton:				
			GetDialogItem(	dlgPtr, kShowAnyButton, &iType, &iHandle, &iRect);
									
			value = !GetControlValue( (ControlHandle) iHandle );
			SetControlValue( (ControlHandle) iHandle , value );
					
			myDataPtr->ShowAny = (Boolean) value;
						
			result = sfHookRebuildList;		
			break;


		case kShowInvisiblesButton:
			GetDialogItem(	dlgPtr, kShowInvisiblesButton, &iType, &iHandle, &iRect);
								
			value = !GetControlValue( (ControlHandle) iHandle );
			SetControlValue( (ControlHandle) iHandle , value );
					
			myDataPtr->showInvisibles = (Boolean) value;
					
			result = sfHookRebuildList;		
			break;

		case kSelectAnyItem: 
			GetDialogItem( dlgPtr, kEntryFilename, &iType, &iHandle, &iRect);
			GetDialogItemText( iHandle, myDataPtr->pFileName ); 
			/* Leave with the chosen folder. */
			result = sfItemOpenButton;
			break;

		case kListItemBox: 
			break;

		case sfHookGoToDesktop:		/* Map cmd-D to a NullEvent */
			if (myDataPtr->showVolumesOnly) result = sfHookNullEvent;
			break;
		case sfHookChangeSelection:	/* sfHookRebuildList will work also */
			if (myDataPtr->showVolumesOnly) result = sfHookGoToDesktop;
			break;
		case sfHookGoToNextDrive:	/* Map cmd-left Arrow to a NullEvent */
			if (myDataPtr->showVolumesOnly) result = sfHookNullEvent;
			break;
		case sfHookGoToPrevDrive:	/* Map cmd-right Arrow to a NullEvent */
			if (myDataPtr->showVolumesOnly) result = sfHookNullEvent;
			break;
		case sfItemOpenButton:
		case sfHookOpenFolder:		/* return the open button's value */
			if (myDataPtr->showVolumesOnly) result = sfItemOpenButton;
			break;

		default:	
            /*  
			if (myDataPtr->SFRPtr->sfFile.name[0] != 0)
				{
				ActivateButton(dlgPtr, kSelectAnyItem);
				}
			else InactivateButton(dlgPtr, kSelectAnyItem);
            */
			break;
	}
 } else SysBeep(30);

return(result);
}




#if GENERATINGCFM || USESROUTINEDESCRIPTORS
#  define CreateRoutineDescriptor(info, proc)									\
		RoutineDescriptor g##proc##RD = BUILD_ROUTINE_DESCRIPTOR(info, proc)
#  define GetRoutineAddress(proc)	(&g##proc##RD)
#else
#  define GetRoutineAddress(proc)	proc
#endif

#if GENERATINGCFM || USESROUTINEDESCRIPTORS
	CreateRoutineDescriptor(uppFileFilterYDProcInfo, MyCustomFileFilter);
	CreateRoutineDescriptor(uppDlgHookYDProcInfo, MySFGetDlgHook);
#endif




void myCustomGetFile( StandardFileReply *mySFR, 
                      OSType *typeList, 
                      short numTypes, 
					  unsigned char *thePrompt,
                      unsigned char *ReturnedFileName, 
                      Boolean ShowAny,
					  Boolean ShowFiles)
{
SFDataPtr myDataPtr;
short	count;
long 	theDirID;
Boolean isDirectory;

Assert_it(ReturnedFileName,"ReturnedFileName == NULL","") 
Assert_it(thePrompt,"thePrompt == NULL","") 
Assert_it(typeList,"typeList == NULL","") 
Assert_it(mySFR,"mySFR == NULL","") 

myDataPtr = (SFDataPtr)NewPtrClear(sizeof(SFData));
Assert_it(myDataPtr,"myDataPtr == NULL","") 

	if ( myDataPtr != NULL )
		{

		myDataPtr->numTypes	= numTypes; 

		for (count = 0; count != numTypes; count++)
			{
			myDataPtr->typeList[count] = typeList[count];
			}

		myDataPtr->ShowAny			= ShowAny;
		myDataPtr->showInvisibles	= false;
		myDataPtr->Inited			= false; 

		myDataPtr->pTitleString 	= thePrompt;

		myDataPtr->showFolders		= true;	
		myDataPtr->showFiles		= ShowFiles;	
		myDataPtr->showVolumesOnly	= false;	

		/* point the user data parameter at the reply record so we can get to it later */
		myDataPtr->SFRPtr = mySFR;

		myDataPtr->pFileName 		= ReturnedFileName;

		CustomGetFile(
					(FileFilterYDUPP)GetRoutineAddress(MyCustomFileFilter),
					-1, typeList,
					mySFR,
					CustomGetFileDLOG,
					sfgfpos,
					 (DlgHookYDUPP)GetRoutineAddress(MySFGetDlgHook),
					nil,
					activeList,
					nil,
					myDataPtr
					);

		FSpGetDirectoryID( &mySFR->sfFile, &theDirID, &isDirectory);
		if (!isDirectory) ReturnedFileName[0] = 0;

		DisposePtr((Ptr)myDataPtr);
	}

}



void myCustomGetVolume( StandardFileReply *mySFR, unsigned char *thePrompt)
{
SFDataPtr 	myDataPtr;
SFTypeList	mySFTypeList;

myDataPtr = (SFDataPtr)NewPtrClear(sizeof(SFData));
	if ( myDataPtr != NULL )
		{

		myDataPtr->ShowAny			= false;
		myDataPtr->showInvisibles	= false;
		myDataPtr->Inited			= false; 

		myDataPtr->pTitleString 	= thePrompt;

		myDataPtr->showFolders		= false;	
		myDataPtr->showFiles		= false;	
		myDataPtr->showVolumesOnly	= true;	

		/* point the user data parameter at the reply record so we can get to it later */
		myDataPtr->SFRPtr = mySFR;

		CustomGetFile(
					(FileFilterYDUPP)GetRoutineAddress(MyCustomFileFilter),
					-1, mySFTypeList,
					mySFR,
					CustomGetFileDLOG,
					sfgfpos,
					 (DlgHookYDUPP)GetRoutineAddress(MySFGetDlgHook),
					nil,
					nil,
					nil,
					myDataPtr
					);

		DisposePtr((Ptr)myDataPtr);
	}

}
