//	AliasUtils

#ifndef __GNUC__
	#include "AppleEvents.h"
#endif

#include "IC_Errors.h"
#include "AliasUtils.h"

#define	MoreAssertPCG(_x)	(!ASSERT(_x))

enum {
	kFinderFileType			= 'FNDR',
	kFinderCreatorType		= 'MACS',
	kFinderProcessType		= 'FNDR',
	kFinderProcessSignature	= 'MACS'
};

static	pascal OSStatus MoreProcGetProcessInformation(const ProcessSerialNumber *pPSN,ProcessInfoRec *pPIR)
{
	if (!MoreAssertPCG (pPIR))
		return paramErr;

	pPIR->processInfoLength	= sizeof (*pPIR);
	pPIR->processName		= NULL;
	pPIR->processAppSpec	= NULL;

	if (pPSN)
		return GetProcessInformation (pPSN,pPIR);
	else
	{
		ProcessSerialNumber psn = { kNoProcess,kCurrentProcess };
		return GetProcessInformation (&psn,pPIR);
	}
}//end MoreProcGetProcessInformation

static	pascal OSStatus MoreProcFindProcessBySignature(const OSType pCreator,const OSType pType,ProcessSerialNumber *pPSN)
{
	OSStatus err = noErr;

	if (!(MoreAssertPCG (pPSN)))
		err = paramErr;
	else
	{
		pPSN->lowLongOfPSN	= kNoProcess;
		pPSN->highLongOfPSN	= kNoProcess;

		while (!(err = GetNextProcess (pPSN)))
		{
			ProcessInfoRec pir;

			if (!(err = MoreProcGetProcessInformation (pPSN,&pir)))
				if ((pCreator == pir.processSignature) && (pType == pir.processType))
					break;
		}
	}

	return err;
}//end MoreProcFindProcessBySignature

static	pascal void MoreAENullDesc(AEDesc* desc)
{
	MoreAssertPCG(desc != NULL);

	desc->descriptorType = typeNull;
	desc->dataHandle     = NULL;
}//end MoreAENullDesc

static	pascal void MoreAEDisposeDesc(AEDesc* desc)
{
	OSStatus junk;

	MoreAssertPCG(desc != NULL);
	
	junk = AEDisposeDesc(desc);
	MoreAssertPCG(junk == noErr);

	MoreAENullDesc(desc);
}//end MoreAEDisposeDesc

static	pascal	OSStatus	MoreAECreateAppleEventProcessTarget(
						const ProcessSerialNumberPtr psnPtr,
						AEEventClass pAEEventClass,
						AEEventID pAEEventID,
						AppleEvent* pAppleEvent )
{
	OSStatus	anError = noErr;
	AEDesc		targetAppDesc = {typeNull,NULL};
	
	anError = AECreateDesc (typeProcessSerialNumber, psnPtr, sizeof( ProcessSerialNumber ), &targetAppDesc);

	if ( noErr == anError )
	{
		anError = AECreateAppleEvent( pAEEventClass, pAEEventID, &targetAppDesc,
									kAutoGenerateReturnID, kAnyTransactionID, pAppleEvent);
	}
	
	MoreAEDisposeDesc( &targetAppDesc );
	
	return anError;
}//end MoreAECreateAppleEventProcessTarget


static	pascal	OSStatus	MoreAECreateAppleEventSignatureTarget(
	OSType pType,
	OSType pCreator,
	AEEventClass pAEEventClass,
	AEEventID pAEEventID,
	AppleEvent* pAppleEvent )
{
	OSStatus anError = noErr;
	
	ProcessSerialNumber		psn = {0, kNoProcess};
	
	// <12> bug fix, pCreator & pType parameters swapped.
	anError = MoreProcFindProcessBySignature( pCreator, pType, &psn );
	if ( noErr == anError )
	{
		anError = MoreAECreateAppleEventProcessTarget( &psn, pAEEventClass, pAEEventID, pAppleEvent );
	}
	return anError;
}//end MoreAECreateAppleEventSignatureTarget


static	pascal	OSErr	MoreAEOAddAliasParameterFromFSSpec(const FSSpecPtr pFSSpec,
												const DescType pKeyword,
												AERecord *pAERecord )
{
	OSErr			anErr = noErr;
	AliasHandle		tAliasHandle;
	
	anErr = NewAlias( NULL, pFSSpec, &tAliasHandle);
	if ( noErr == anErr  &&  tAliasHandle == NULL) {
		anErr = paramErr;
	}
	
	if ( noErr == anErr ) {
		char	handleState;
		
		handleState = HGetState((Handle) tAliasHandle );
		HLock((Handle) tAliasHandle );
		
		anErr = AEPutParamPtr( pAERecord, pKeyword, typeAlias,
							   *tAliasHandle, GetAliasSize(tAliasHandle));
		
		HSetState( (Handle)tAliasHandle, handleState );
		DisposeHandle( (Handle)tAliasHandle );
	}
		
	return anErr;
}//end MoreAEOAddAliasParameterFromFSSpec

static	pascal	OSStatus	MoreAEGetHandlerError(const AppleEvent* pAEReply)
{
	OSStatus	anError = noErr;
	OSErr		handlerErr;
	
	DescType	actualType;
	long		actualSize;
	
	if ( pAEReply->descriptorType != typeNull )	// there's a reply, so there may be an error
	{
		OSErr	getErrErr = noErr;
		
		getErrErr = AEGetParamPtr( pAEReply, keyErrorNumber, typeShortInteger, &actualType,
									&handlerErr, sizeof( OSErr ), &actualSize );
		
		if ( getErrErr != errAEDescNotFound )	// found an errorNumber parameter
		{
			anError = handlerErr;					// so return it's value
		}
	}
	return anError;
}//end MoreAEGetHandlerError

static	pascal	OSStatus	MoreAESendEventNoReturnValue(
					const AEIdleUPP pIdleProcUPP,
					const AppleEvent* pAppleEvent )
{
	OSStatus	anError = noErr;
	AppleEvent	theReply = {typeNull,NULL};
	AESendMode	sendMode;

	if (NULL == pIdleProcUPP)
		sendMode = kAENoReply;
	else
		sendMode = kAEWaitReply;

	anError = AESend( pAppleEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, pIdleProcUPP, NULL );
	if ((noErr == anError) && (kAEWaitReply == sendMode))
		anError = MoreAEGetHandlerError(&theReply);

	MoreAEDisposeDesc( &theReply );
	
	return anError;
}//end MoreAESendEventNoReturnValue

OSErr	MoreFECreateAliasFile(
	const FSSpecPtr	pSourceFSSPtr,
	const FSSpecPtr	pDestFSSPtr,
	ConstStr63Param	pNewName,
	const AEIdleUPP	pIdleProcUPP)
{
	OSErr		anErr = noErr;
	
	AppleEvent	tAppleEvent = {typeNull,NULL};
	
	anErr = MoreAECreateAppleEventSignatureTarget(kFinderFileType,kFinderCreatorType,
											  kAECoreSuite,kAECreateElement,&tAppleEvent);
	if (noErr == anErr)
	{
		//	put the type of item to make into the Apple event
		OSType	anAliasType = typeAlias;
		
		anErr = AEPutParamPtr(&tAppleEvent,keyAEObjectClass,typeType,&anAliasType,sizeof(OSType));
		if (noErr == anErr)
		{
			//	add an alias that points to the targer for the alias file to be created
			anErr = MoreAEOAddAliasParameterFromFSSpec(pSourceFSSPtr,keyASPrepositionTo,&tAppleEvent);
			if (noErr == anErr)
			{
				//	where should the alias file be created?
				anErr = MoreAEOAddAliasParameterFromFSSpec(pDestFSSPtr,keyAEInsertHere,&tAppleEvent);
				if (noErr == anErr)
				{
					//	add a properties record so we can specify the name of the new alias file.
					AERecord	properties = {typeNull,NULL};
					
					anErr = AECreateList(NULL,0,true,&properties);
					if (noErr == anErr)
					{
						anErr = AEPutKeyPtr(&properties,keyAEName,typeChar,pNewName+1,*pNewName);
						if (noErr == anErr)
						{
							anErr = AEPutParamDesc(&tAppleEvent,keyAEPropData,&properties);
							if (noErr == anErr)
							{
								//	Send the event. In this case we don't care about the reply,but if we did we
								//	would get back an object that describes the alias file just created
								//	(either an object descriptor, an alias, or an FSSpec, depending on what we ask for).
								anErr = MoreAESendEventNoReturnValue(pIdleProcUPP,&tAppleEvent);
							}
						}
						MoreAEDisposeDesc(&properties);
					}
				}
			}
		}
		// always dispose of AEDescs when you are finished with them
		(void) MoreAEDisposeDesc(&tAppleEvent);
	}
	return anErr;
}	// end MoreFECreateAliasFile

