implementation module mac_file_selector_carbon;

import StdClass,StdBool,StdChar,StdInt,StdMisc,StdString, StdFile,StdArray;
import	standard_file,files,pointer,quickdraw,memory,appleevents,navigation;

String64 :: String;
String64 = createArray 64 '@';

Error_i	:: !String !Int -> .x;
Error_i string i = abort (string +++ toString i);

Get_name_and_parent_id_of_directory :: !Int !Int !*Toolbox -> (!String,!Int,!*Toolbox);
Get_name_and_parent_id_of_directory volumeNumber directoryId tb
	| osError==0
		= (folderName,parentId,tb1);
		= Error_i "Error code returned by BPGetCatInfo: " osError;
	where {
		(osError,folderName,parentId,tb1) = GetCatInfo2 volumeNumber directoryId String64 tb;
	};

Get_directory_path :: !Int !Int !String !*Toolbox -> (!String, !*Toolbox);
Get_directory_path volumeNumber directoryId path tb
	| directoryId==2
		= (folderName +++ ":" +++ path, tb1);
		= Get_directory_path volumeNumber parentId (folderName +++ ":" +++ path) tb1;
	where {
		(folderName, parentId, tb1) = Get_name_and_parent_id_of_directory volumeNumber directoryId tb;
	};

Find_colon :: !String !Int -> (!Bool,!Int);
Find_colon s p = Find_colon2 s p (dec (size s));

Find_colon2 :: String !Int !Int -> (!Bool,!Int);
Find_colon2 s p l
|	p >= l				= (False,p);
|	s.[p] == ':'	= (True,p);
						= Find_colon2 s (inc p) l;

Get_directory_and_file_name :: !String !*Toolbox -> (!Int,!Int,!String,!*Toolbox);
Get_directory_and_file_name pathName tb
|	not colon					= (sfSaveDisk, curDirStore, pathName,tb1);
|	pathName.[0] == ':'		= Get_directory_and_file_name2 pathName 0 sfSaveDisk curDirStore tb1;
|	0 == result					= Get_directory_and_file_name2 pathName colonPosition volumeNumber 2 tb`;
								= (sfSaveDisk`,curDirStore`,pathName,tb``);
	where {
		(colon,colonPosition)			= Find_colon pathName 0;
		(sfSaveDisk, curDirStore, tb1)	= Get_stored_dir_and_file tb;
		(result,volumeNumber,tb`)		= GetVInfo (pathName % (0, colonPosition)) tb;
		(sfSaveDisk`,curDirStore`,tb``)	= Get_stored_dir_and_file tb`;
	};

Get_stored_dir_and_file :: !*Toolbox -> (!Int,!Int,!*Toolbox);
Get_stored_dir_and_file tb
	=	(sfSaveDisk,curDirStore,tb2);
	where {
		(saveDisk,tb1)		= LoadWord 532 tb;
		sfSaveDisk			= 0 - saveDisk;
		(curDirStore,tb2)	= LoadLong 920 tb1;
	};

Get_directory_and_file_name2 :: !String !Int !Int !Int !*Toolbox -> (!Int,!Int,!String,!*Toolbox);
Get_directory_and_file_name2 pathName p v d tb
	| (p >= l) || (pathName.[p] <> ':')
		= (v,d,pathName % (p, l_sub_1),tb);
	| colon && (0 == result) && (0 <> (16 bitand attrib))
		= Get_directory_and_file_name2 pathName p2 v d2 tb1;
		= (v,d, pathName % (inc p, l_sub_1),tb1);
	where {
		l_sub_1					= dec l;
		(colon,p2)				= Find_colon pathName (inc p);
		(result,attrib,d2,tb1)	= GetCatInfo3 v d (pathName % (inc p, dec p2)) tb;
		l						= size pathName;
	};

do_tb_io :: !*Toolbox !*World -> *World;
do_tb_io _ w = w;

SelectInputFile	:: !*World -> (!Bool,!String,*World);
SelectInputFile w
	# tb = 0;
	# (nav_reply_record,_,tb) = NewPtr NavReplyRecordSize tb;
	# (err,tb) = NavGetFile 0 nav_reply_record 0 0 0 0 0 0 tb;
	# (ok,file_name,tb)=get_or_put_file_selector_result err nav_reply_record tb;
	= (ok,file_name,do_tb_io tb w);

SelectOutputFile:: !String !String !*World -> (!Bool, !String,!*World);
SelectOutputFile prompt originalName w
	# tb = 0;
	# (err,nav_dialog_options,tb) = NavGetDefaultDialogOptions tb;
	| err<>0
		# tb=DisposePtr nav_dialog_options tb;
		= (False,"",do_tb_io tb w);
	# (nav_reply_record,_,tb) = NewPtr NavReplyRecordSize tb;
	# (flags,tb) = LoadLong (nav_dialog_options+NavDialogOptionFlagsOffset) tb;	
	# flags=flags bitor kNavNoTypePopup;
	# tb = StoreLong (nav_dialog_options+NavDialogOptionFlagsOffset) flags tb;
	# tb = copy_string_to_memory originalName (nav_dialog_options+NavDialogOptionSavedFileNameOffset) tb
	# (err,tb) = NavPutFile 0 nav_reply_record nav_dialog_options 0 0 0 /*0x2a2a2a2a **** */ 0 tb;
//	# (err,tb) = NavPutFile 0 nav_reply_record 0 0 0 0 0 tb;
	# (ok,file_name,tb)=get_or_put_file_selector_result err nav_reply_record tb;
	# tb=DisposePtr nav_dialog_options tb;
	= (ok,file_name,do_tb_io tb w);

copy_string_to_memory s p tb
	# tb=StoreByte p (size s) tb;
	= copy_chars 0 (p+1) tb;
	{
		copy_chars i p tb
			| i>=size s
				= tb;
				# tb = StoreByte (p+i) (toInt s.[i]) tb;
				= copy_chars (i+1) p tb;
	}

get_or_put_file_selector_result err nav_reply_record tb
	| err<>0
		# tb=DisposePtr nav_reply_record tb;
		= (False,"",tb);
	# (valid_record,tb) = LoadByte (nav_reply_record+NavReplyValidRecordOffset) tb;
	| valid_record==0
		# (_,tb)=NavDisposeReply nav_reply_record tb;
		# tb=DisposePtr nav_reply_record tb;
		= (False,"",tb);
	# fs_spec=createArray 70 '\0';
	# (r,theAEKeyword,typeCode,actualSize,tb) = AEGetNthPtr (nav_reply_record+NavReplySelectionOffset) 1 KeyFssString fs_spec tb;
	| r<>0 || actualSize<>70
		# (_,tb)=NavDisposeReply nav_reply_record tb;
		# tb=DisposePtr nav_reply_record tb;
		= (False,"",tb);
	# file_name_size=toInt fs_spec.[6]
	# vRefNum=((toInt fs_spec.[0]<<8 bitor toInt fs_spec.[1])<<16)>>16;
	# directoryId=((toInt fs_spec.[2]<<8 bitor toInt fs_spec.[3])<<8 bitor toInt fs_spec.[4])<<8 bitor toInt fs_spec.[5];
	# file_name=fs_spec % (7,6+file_name_size);
	# (path_name,tb)=Get_directory_path vRefNum directoryId file_name tb;
	# (_,tb)=NavDisposeReply nav_reply_record tb;
	# tb=DisposePtr nav_reply_record tb;
	= (True,path_name,tb);
