//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: oddataxfer
//
//   CLASSES: none
//
//   ORIGINS: 82,27
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//
// @(#) 1.3 com/src/storage/DragDrp.cpp, oddataxfer, od96nt, odnt9712d 7/15/96 17:52:55 [ 3/21/97 16:45:44 ]
/*
	File:		DragDrp.cpp

	Contains:	Implementation of ODDragAndDrop

	Owned by:	Vincent Lo

	Copyright:	© 1994 - 1995 by Apple Computer, Inc., all rights reserved.

	Change History (most recent first):

		<84>	10/22/95	T‚		1291419 GM: File type set incorrectly for
									Old Mac data dragged to Finder from
									OpenDoc.
		<83>	10/13/95	T‚		1284461 GM: Parts that are created in a
									document should not automatically be given
									names
		<82>	 10/8/95	TJ		Fixes Recomended by Refball
		<81>	 10/4/95	jpa		Added missing ODVolatiles [1285799]
		<80>	 10/4/95	VL		1287367: Added code in MySendDataProc to
									check whether we are dragging to the trash.
									1286642: Removed bogus kODPromiseFlavor.
									Check for nil handle or invalid fsspec in
									GetDropFSSpec. Added gIsResolvingPromise to
									ensure that we know when we are fulfulling
									a promise.
		<79>	 10/3/95	TJ		Changes done by RefBall Team
		<78>	 9/13/95	VL		Removed leftover debugstr from last
									checkin.
		<77>	 9/13/95	VL		1283523: Dragging parts between Documents &
									Finder needs to reflect new behavior. Added
									a lot of apple event handlers.
		<76>	  9/8/95	VL		1275241, 1283463: Use
									ODPlatformDragReference everywhere.
		<75>	  9/8/95	T‚		1281096 FB2:Many constants in ODTypesB
									without kOD prefix!
		<74>	  9/6/95	VL		1255735, 1274572: SetStationery in
									SetFinderInfo. Set up finderFile in
									EnterHandler to get the finder file info.
									Removed CreateNewFile. Changed
									MakeUniqueFilename to use resources for
									localization and to follow the HI
									guidelines.
		<73>	  9/1/95	CC		1273646, 1279220: CloneIntoFile: Use
									kODCloneToFile.
		<72>	 8/30/95	EL		1279832: Storage THROW_IF_NULL problems.
		<71>	 8/29/95	VL		1276864, 1276541: Change result to
									kODDropCopy if the original clone kind is
									copy.
		<70>	 8/29/95	jpa		Univ Hdrs 2.1 fix [1279173]
		<69>	 8/22/95	VL		1265957, 1278381: If a part returns
									kODFalse from DragEnter and DragWithin, try
									the containing facet.
		<68>	 8/22/95	eeh		1276821:
									kOpenDocShellSignature->kODShellSignature
		<67>	 8/21/95	VL		1274367: Removed WARN statement in
									CopyFromDragItemInChunks.
		<66>	 8/17/95	CC		1199356: Turn off paste as attribute on
									drop into background window.
		<65>	 8/17/95	CC		1277777: MyRecieveDropHandler: Set drop
									result to kODDropFail when an exception is
									caught.
									Use ODVolatile(targetPart) or suffer
									refcount error on failure.
		<64>	 8/16/95	jpa		Updated call to ODGetIconFamilyProp
									[1212507]
		<63>	 8/16/95	VL		1244813: removed ASLMBUILD.
		<62>	 8/12/95	T‚		1276812 Need to use TempObjs and TempRefs
									for exception safety and to avoid TRY
									blocks, 1276807 Opt./Bug: use StdTypIO
									routines for portable streaming & smaller
									footprint
		<61>	  8/3/95	RR		#1257260: Collapse B classes. Remove
									somInit methods. Don't call IsInitialized
									or SubclassResponsibility
		<60>	 7/21/95	VL		1270320: Dispose isoType returned from
									GetISOTypeFromPlatformType.
		<59>	 6/28/95	VL		1190962, 1252228: Added code for creating
									non-OD document.
		<58>	 6/26/95	VL		1262622: Call InitDateInfo in SetFinderInfo
									to make sure that the modDate and
									creationDate are set up.
		<57>	 6/25/95	VL		1255300: Added code for roundtrip D&D with
									Finder (SetIconFamily and SetFinderInfo).
		<56>	 6/20/95	VL		1161434, 1194603: Reordered
									AddDragItemFlavor to work around
									interaction problems with Finder.
		<55>	  6/2/95	CC		1255476: MyReceiveDropHandler, EnterWindow,
									InWindow: Release part acquired via
									ODFrame::AquirePart.
									1255474: AcquireStorageUnitOSType restored
									to GetStorageUnitOSType.
									1255474: AcquireSourceFrame restored to
									GetSourceFrame.
									1255474: AcquireSourcePart restored to
									GetSourcePart.
		<54>	 5/26/95	VL		1251403: Multithreading naming support.
		<53>	 5/25/95	jpa		List.h --> LinkList.h [1253324]
		<52>	 5/18/95	CC		1250280: ShowPasteAsDialog throws on
									invalid null arguments. 1238898: Add
									destFrame argument to BeginClone call.
		<51>	 5/17/95	RR		#1250135/1250137/1250143 Getters increment
									refcount
		<50>	 5/11/95	DM		#1246524, #1246529:
									ValueNameSpaceGetEntry() must pass through
									the value allocated.
		<49>	  5/5/95	CC		1246586: CloneIntoFile: Clone content frame
									into document draft and create root frame
									list property.
		<49>	  5/5/95	CC		1246586: CloneIntoFile: Clone content frame
									into document draft and create root frame
									list property.
		<48>	  5/2/95	CC		1207493: MyReceiveDropHandler: Call
									SetDestFacet BEFORE targetFacet->Drop() so
									CMDraft can get the target facet.
		<47>	  5/2/95	VL		1230557: Remove kODPropMouseDownOffset.
		<46>	 4/15/95	VL		1240014: Added TRY-CATCH blocks and turned
									off debug statements.
		<45>	 4/14/95	VL		Temporarily turned on debug printf.
		<44>	 4/10/95	VL		1196870: Preserved HasLeftSourceFrame
									behavior.
		<43>	 3/31/95	VL		1228756: Made dragdrop work with
									non-persistent frame.
		<42>	 3/23/95	VL		1228275: ASSERT for null ODByteArray.
		<41>	 3/22/95	CC		1230322: Changed parameter to
									ShowPasteAsDialog().
		<40>	 3/10/95	VL		1227218: Get rid of system heap.
		<39>	 2/28/95	VL		1194656: Check for existence before adding
									property or value.
		<38>	  2/7/95	CC		1211295:  Pass isMove parameter to
									ShowPasteAsDialog.
		<37>	  2/2/95	CC		1153802:  Added DragItemHasFlavor().
									CopyFromDragItemInChunks() writese data at
									current offset, instead of replacing the
									entire value.
									Automatically generate 'stxt' from
									'styl'+'TEXT'; generate 'styl' from 'stxt'.
		<36>	  2/2/95	CG		#1195019:  ValueNameSpace entries are now
									copied in and out instead of pointers being
									passed around.
		<35>	  2/1/95	VL		1209010: Implemented more err checking.
		<34>	 1/26/95	VL		#???: Use updated Storage Unit Ref API.
		<33>	 1/23/95	CG		#1195019: ValueNameSpace methods now take
									ODByteArray parameter instead of ODPtr.
		<32>	  1/9/95	VL		1195012, 1196957: StartDrag now takes
									ODByteArray. Drag Attributes now returns
									whether the nature of the drop.
		<31>	12/20/94	VL		1195012: Make Storage calls be
									marshallable.
		<30>	12/13/94	VL		1203627,1200603,1203451,1198037,1194537,119
									4755,1186815: Bug fixes.
		<29>	11/14/94	VL		1194890: Enabled fulfulling multiple
									promises.
		<28>	10/19/94	VL		1162335: Now D&D adds a special value if
									the dragged item is a non-OD file.
		<27>	10/12/94	RA		Fix uninitilized variable.
		<26>	 10/4/94	VL		1162335: Added implementation on handling
									non-OD files. Also chewed up MouseUp event
									after drop.
		<25>	 9/29/94	RA		1189812: Mods for 68K build.
		<24>	 9/28/94	JBS		(for VL) 1162335: fixed unitialized
									dataSize
		<23>	 9/27/94	VL		1142048: Do not call DragLeave if there is
									a Drop.
		<22>	 9/26/94	VL		1162335: Enabled dragging from non-od docs.
		<21>	 9/23/94	VL		1155224: Drag to Finder names the drop
									correctly. Also, enable dragging to trash.
		<20>	 9/23/94	VL		1184272: ContainerID is a sequence of
									octets.
		<19>	 9/23/94	CC		1187509 - Implemented ShowPasteAsDialog().
		<18>	 9/15/94	VL		1184871: Fixed SendDataProc to handle
									promises.
		<17>	 8/26/94	VL		1183174: Use updated cloning APIs.
		<16>	 8/17/94	jpa		(forgot bug# for <15>, which is 1181530)
		<15>	 8/17/94	jpa		ODDragAndDropsomUninit was calling parent's
									somUninit twice!!
		<14>	 8/15/94	T‚		#1180922 Removed most obsolete types from
									StdTypes.idl
		<13>	 8/11/94	eeh		bug 1180486: MySendDataProc needs to call
									SetDropResult
		<12>	 8/10/94	JBS		1179919: coordinate system bias changes
		<11>	  8/9/94	VL		1176710: Dragging an alias to OpenDoc
									document now works. 1179857: DragEnter and
									DragWithin return ODBoolean.
		<10>	  8/3/94	VL		1153123: Storage to ODStor.
		 <9>	  8/2/94	CC		#1178169 - ShowPasteAsDialog() takes
									ODFacet* instead of ODFrame*.
		 <8>	 7/29/94	VL		THROW if D&D not installed.
		 <7>	 7/27/94	CC		Touched to accompany .idl checkin.
		 <6>	 7/26/94	VL		Reduced dependency on Bento and got rid of
									DragAndDropStorageUnit.
		 <5>	 7/21/94	VL		Made it run in SOM.
		 <4>	  7/7/94	CC		Removed constants now defined by
									ODTypesB.idl.
		 <3>	  7/5/94	CC		MySendDataProc: Added blocks to case stmts
									that were declaring locals at the scope of
									the switch stmt.
		 <2>	 6/30/94	jpa		Fixed some illegal implicit casts from
									void*.
		 <1>	 6/28/94	VL		first checked in

	To Do:		
	In Progress:
*/

#ifndef _ALTPOINT_
#include "AltPoint.h"			// Use C++ savvy XMPPoint and XMPRect
#endif

#define ODDragAndDrop_Class_Source
#define VARIABLE_MACROS
#include <DragDrp.xih>

#ifndef SOM_ODDragItemIterator_xh
#include <DgItmIt.xh>
#endif

#ifndef _DRAGPRIV_
#include <DragPriv.h>
#endif

#ifndef SOM_Module_OpenDoc_StdProps_defined
#include <StdProps.xh>
#endif

#ifndef SOM_Module_OpenDoc_StdTypes_defined
#include <StdTypes.xh>
#endif

#ifndef SOM_ODSession_xh
#include <ODSessn.xh>
#endif

#ifndef SOM_ODStorageSystem_xh
#include <ODStor.xh>
#endif

#ifndef SOM_ODContainer_xh
#include <ODCtr.xh>
#endif

#ifndef SOM_ODDocument_xh
#include <Document.xh>
#endif

#ifndef SOM_ODDraft_xh
#include <Draft.xh>
#endif

#ifndef SOM_ODFrame_xh
#include <Frame.xh>
#endif

#ifndef SOM_ODFacet_xh
#include <Facet.xh>
#endif

#ifndef SOM_ODWindow_xh
#include <Window.xh>
#endif

#ifndef SOM_ODWindowState_xh
#include <WinStat.xh>
#endif

#ifndef SOM_ODPart_xh
#include <Part.xh>
#endif

#ifndef SOM_ODTransform_xh
#include <Trnsform.xh>
#endif

#ifndef SOM_ODTranslation_xh
#include <Translt.xh>
#endif

#ifndef _ODMEMORY_
#include "ODMemory.h"
#endif

#ifndef _ODNew_
#include "ODNew.h"
#endif

#ifndef _EXCEPT_
#include "Except.h"
#endif

#ifndef _LINKLIST_
#include "LinkList.h"
#endif

#ifndef SOM_ODStorageUnitView_xh
#include <SUView.xh>
#endif

#ifndef _STORDEF_
#include "StorDef.h"
#endif

#ifndef SOM_CMStorageUnit_xh
#include <CMSU.xh>
#endif

#ifndef _PLFMFILE_
#include <PlfmFile.h>
#endif

#ifndef _CONSTDEF_
#include "ConstDef.h"
#endif

#ifndef _PASCLSTR_
#include <PasclStr.h>
#endif

#ifndef SOM_Module_OpenDoc_StdDefs_defined
#include "StdDefs.xh"
#endif

#ifndef _LINKDLGS_
#include "LinkDlgs.h"
#endif

#ifndef __MEMORY__
#include <Memory.h>
#endif

#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif

#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif

#ifndef __ERRORS__
#include <Errors.h>
#endif

#ifndef __SCRIPT__
#include <Script.h>
#endif

#ifndef __PACKAGES__
#include <Packages.h>
#endif

#ifndef __APPLEEVENTS__
#include <AppleEvents.h>
#endif

#ifndef _ISOSTR_
#include <ISOStr.h>
#endif

#ifndef __ALIASES__
#include <Aliases.h>
#endif

#ifndef __FOLDERS__
#include <Folders.h>
#endif

#ifndef _BARRAY_
#include <BArray.h>
#endif

#ifndef SOM_ODNameSpaceManager_xh
#include <NmSpcMg.xh>
#endif

#ifndef SOM_ODValueNameSpace_xh
#include <ValueNS.xh>
#endif

#ifndef _TEMPOBJ_
#include <TempObj.h>
#endif

#ifndef _STORUTIL_
#include "StorUtil.h"
#endif

#include <string.h>

#ifndef _ODDEBUG_
#include "ODDebug.h"
#endif

#ifndef _NMSPCUTL_
#include <NmSpcUtl.h>
#endif

#ifndef _STDTYPIO_
#include <StdTypIO.h>
#endif

#ifndef __DIALOGS__
#include <Dialogs.h>
#endif

#ifndef _INFOUTIL_
#include <InfoUtil.h>
#endif

#ifndef __ICONS__
#include <Icons.h>
#endif

#ifndef __FINDER__
#include <Finder.h>
#endif

#ifndef _POUTILS_
#include <POUtils.h>
#endif

#ifndef _OPENHASH_
#include <OpenHash.h>
#endif

#ifndef _ITEXT_
#include <IText.h>
#endif

#ifndef _USERSRCM_
#include <UseRsrcM.h>
#endif

#ifndef _DLOGUTIL_
#include <DlogUtil.h>
#endif

#ifndef _DRGDPDEF_
#include "DrgDpDef.h"
#endif

#ifndef __DIALOGS__
#include <Dialogs.h>
#endif

static FSSpec gTmpFileFSSpec;
static FSSpec gTargetFSSpec;
static boolean gIsResolvingPromise = kODFalse;

//==============================================================================
// Constants
//==============================================================================

#define kODUserPromiseFlavor	0x66696c65	// 'file'
#define kODBentoFlavor		0x626E746F	// 'bnto'
#define kODPromiseFlavor	0x70726D73	// 'prms'
#define kODPromiseDesc		0x70726D73	// 'prms'
#define kODScrapTypestyl	0x7374796c	// 'styl'
#define kODScrapTypestxt	0x73747874	// 'stxt'
#define kODScrapTypeTEXT	0x54455854	// 'TEXT'

#define kODDropHasLeftSourceFrameMask	~kODDropIsInSourceFrame
#define kODDragHasLeftSourcePartMask	~(kODDropIsInSourceFrame | kODDropIsInSourcePart)

// #define kODDestinationFileSpec 'dfss'
// #define kODSourceFileSpec 'sfss'
// #define kODPreReplaceFileEventID 'prfl'
// const FourCharCode kODReplaceFileEventID = 'rfl ';
// #define kODSession 'sess'

#define kODDestinationFileSpec 'DFSS'
#define kODSourceFileSpec 'SFSS'
#define kODReplaceFileEventID 'RFL '
#define kODSession 'SESS'

const ODULong	kODInitialNumEntries = 8;

#if ODDebug
// #define ODDebug_DragAndDrop 1
#endif

//==============================================================================
// Scalar Types
//==============================================================================

typedef struct {
	ODPart            *sourcePart;
	ODStorageUnitView *destSUView;
} ODPromiseDesc;

#define IsOpenDocDocument(osType) ((osType != 'APPL') && (osType != 'shlb'))
#define SetPasteAsAttribute(self, ev, m) do {if ((m & cmdKey) && IsFrontProcess()) self->SetAttributes(ev, self->GetAttributes(ev) | kODDropIsPasteAs);} while (0)

//==============================================================================
// Prototyping
//==============================================================================

static pascal OSErr MyDragTrackingHandler(
		short message,
		WindowPtr theWindow,
		void* handlerRefCon,
		ODPlatformDragReference theDrag);

static pascal OSErr	MyReceiveDropHandler(
		WindowPtr theWindow,
		void* handlerRefCon,
		ODPlatformDragReference theDrag);

static pascal OSErr  MySendDataProc(
		FlavorType theType,
		void* refCon,
		ItemReference theItem,
		ODPlatformDragReference theDrag);

static OSErr ODPascal ReplaceFileAEHandler(
		const AppleEvent* replaceFileEvent,
		AppleEvent* reply,
		long refCon);
		
static void RespecifyToTempFolder(PlatformFile* file);
static OSErr CreateReplaceFileEvent(Environment* ev, AppleEvent* replaceFileEvent, ODSession* session, ProcessSerialNumber* psn);
static OSErr SetupReplaceFileEvent(Environment* ev, AppleEvent* replaceFileEvent, FSSpec* sourceFileSpec, FSSpec* destFileSpec);
static OSErr SendReplaceFileEvent(AppleEvent* replaceFileEvent, ProcessSerialNumber* psn);
static OSErr DisposeReplaceFileEvent(AppleEvent* replaceFileEvent);
static ODBoolean DragItemHasFlavor(ODPlatformDragReference theDrag, ItemReference itemID, OSType	theType);
static OSErr CloneIntoFile(Environment* ev, ODDragItem* theDragItem, FSSpec dropFSSpec); 
static void CloneIntoFlavor(Environment* ev, ODDragAndDrop* dad, ODDragItem* theDragItem, 
								ODPlatformDragReference theDrag, ItemReference theItem, FlavorType theType,
								FSSpec dropFSSpec);
static boolean MakeUniqueFilename( Environment *ev, ODSession* session, ODStorageUnit *su, FSSpec *spec );
static OSType GetStorageUnitOSType( Environment *ev, ODStorageUnit *su );
static OSErr CopyToDragItemInChunks(Environment* ev,
								FlavorType theType,
								ItemReference theItem,
								ODPlatformDragReference theDrag,
								ODDragItem* theDragItem);
static OSErr CopyFromDragItemInChunks(Environment* ev,
								FlavorType theType,
								ItemReference theItem,
								ODPlatformDragReference theDrag,
								ODStorageUnitView* destSUView);

static void SetFinderInfo(Environment* ev, ODStorageUnit* su, PlatformFile* file);
static void	SetIconFamily(Environment* ev, ODStorageUnit* fromSU, PlatformFile* file);
static OSErr GetDropFSSpec(ODPlatformDragReference theDrag, FSSpec& dropFSSpec);
static boolean IsTrashFolder(FSSpec dropFSSpec);
static boolean IsFrontProcess();

#ifdef ODDebug_DragAndDrop

#ifndef SOM_ODStorageUnitCursor_xh
#include <SUCursor.xh>
#endif

void PrintDragReference(ODPlatformDragReference dragRef, char* header);
void PrintStorageUnit(Environment* ev, ODStorageUnit* su, char* header);
#endif

#pragma segment ODDragAndDrop

#include "DragDrpB.cpp"	// Platform-independent methods, if any


SOM_Scope ODBoolean  SOMLINK ODDragAndDropShowPasteAsDialog(ODDragAndDrop *somSelf, Environment *ev,
		ODBoolean canPasteLink,
		ODPasteAsMergeSetting mergeSetting,
		ODFacet* facet,
		ODTypeToken viewType,
		ODStorageUnit* contentSU,
		ODPasteAsResult* result)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropShowPasteAsDialog");

	SOM_CATCH return kODFalse;

	THROW_IF_NULL(facet, kODErrNullFacetInput);
	THROW_IF_NULL(contentSU, kODErrIllegalNullStorageUnitInput);
	THROW_IF_NULL(result, kODErrNullPasteAsResultInput);

	ODBoolean returnValue = ShowPasteAsDialog(
								canPasteLink, 
								mergeSetting,
								(somSelf->GetDropResult(ev) == kODDropMove),
								contentSU,
								facet, 
								viewType, 
								result);

	return returnValue;
}

SOM_Scope void  SOMLINK ODDragAndDropInitDragAndDrop(ODDragAndDrop *somSelf, Environment *ev,
		ODSession* session)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropInitDragAndDrop");

SOM_TRY

	/* Moved from somInit. SOM itself sets fields to zero
	_fSession = kODNULL;
	_fWindowState = kODNULL;
	_fStorageSystem = kODNULL;

	_fDragItemList = kODNULL;
	_fListFromHandler = false;
	_fDragItemIterator = kODNULL;
	
	_fAttributes = 0;
	_fDragReference = 0;

	_fPrevFacet = kODNULL;
	_fSourceFrame = kODNULL;
	_fSourcePart = kODNULL;
	_fDestFacet = kODNULL;
	
	_fReceiveHandler = kODNULL;
	_fTrackingHandler = kODNULL;
	_fSendDataHandler = kODNULL;
	_fFacetsRejected = kODNULL;
	*/

	_fSession = session;

	somSelf->InitObject(ev);
	
	long  gestaltResult;
	OSErr result;

	// Get the current process for background drag
	_fPSN = (ProcessSerialNumber*) ODNewPtr(sizeof(ProcessSerialNumber));
	GetCurrentProcess(_fPSN);
	
	_fReplaceFileEvent = (AppleEvent*) ODNewPtr(sizeof(AppleEvent));
	CreateReplaceFileEvent(ev,
		_fReplaceFileEvent,
		session,
		_fPSN);

	_fFacetsRejected = new OpenHashTable(OpenHashTable::StdEqual, OpenHashTable::StdHash, kODNULL);
	_fFacetsRejected->Initialize(kODInitialNumEntries,
									sizeof(ODFacet*),
									sizeof(ODFacet*));
		
	// Check if the drag manager is present
	result = Gestalt(gestaltDragMgrAttr, &gestaltResult);
	if (result != noErr)
		THROW_M(result, "Error from Gestalt");

	// The mysterious 31 is the bit position as BitTst uses a convention opposite to MC68000
	if (BitTst(&gestaltResult, (31 - gestaltDragMgrPresent)) == false) {
		THROW_M(kODErrNoDragManager, "No drag manager present");
	}
	else {
		// Install the default tracking handler for this application (session)
		_fTrackingHandler = NewDragTrackingHandlerProc(&MyDragTrackingHandler);
		result = InstallTrackingHandler(_fTrackingHandler, NULL, (void *) somSelf);
		ASSERTM(result == noErr, result, "Error from InstallTrackingHandler");
		
		// Install the default receive handler for this application (session)
		_fReceiveHandler = NewDragReceiveHandlerProc(&MyReceiveDropHandler);
		result = InstallReceiveHandler(_fReceiveHandler, NULL, (void *) somSelf);
		ASSERTM(result == noErr, result, "Error from InstallReceiveHandler");
	
		// Create a UPP for MySendDataProc which we will use later inside ::StartDrag
		_fSendDataHandler = NewDragSendDataProc(MySendDataProc);
	
		_fWindowState = _fSession->GetWindowState(ev);
	
		_fStorageSystem = _fSession->GetStorageSystem(ev);
	
		_fDragItemList = new LinkedList;

		AEEventHandlerUPP theHandlerUPP = NewAEEventHandlerProc( ReplaceFileAEHandler ) ;
		THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
				kODReplaceFileEventID, theHandlerUPP, nil, false));
	}

SOM_CATCH_ALL

	_fWindowState = kODNULL;
	_fStorageSystem = kODNULL;
	if (_fDragItemList)
	{
		delete _fDragItemList;
		_fDragItemList = kODNULL;
	}
	if (_fReceiveHandler)
	{
		RemoveReceiveHandler(_fReceiveHandler, NULL);
		DisposeRoutineDescriptor(_fReceiveHandler);
		_fReceiveHandler = kODNULL;
	}
	if (_fTrackingHandler)
	{
		RemoveTrackingHandler(_fTrackingHandler, NULL);
		DisposeRoutineDescriptor(_fTrackingHandler);
		_fTrackingHandler = kODNULL;
	}
	if (_fSendDataHandler)
	{
		DisposeRoutineDescriptor(_fSendDataHandler);
		_fSendDataHandler = kODNULL;
	}

SOM_ENDTRY
}

SOM_Scope ODULong  SOMLINK ODDragAndDropGetDragAttributes(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDragAttributes");

	if (_fTrackingHandler == kODNULL)
		ODSetSOMException(ev, kODErrNoDragManager);

	return _fAttributes;
}

SOM_Scope ODPlatformDragReference  SOMLINK ODDragAndDropGetDragReference(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDragReference");

	if (_fTrackingHandler == kODNULL)
		ODSetSOMException(ev, kODErrNoDragManager);
		
	return _fDragReference;
}


SOM_Scope ODFacet*  SOMLINK ODDragAndDropFindTargetFacet(ODDragAndDrop *somSelf, Environment *ev,
		ODPlatformWindow theWindow,
		ODPoint* mouse,
		ODPoint* localMouse)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropFindTargetFacet");

	ODFacet   *targetFacet = kODNULL;
	
	if (_fTrackingHandler == kODNULL)
		ODSetSOMException(ev, kODErrNoDragManager);
	else {
		SOM_TRY
			ODFacet   *curFacet;
			GrafPtr		curPort;
			Point		qdLocal;
			
			{	TempODWindow targetWindow = _fWindowState->AcquireODWindow(ev,theWindow);
				if (!targetWindow)
					return kODNULL;
			
				GetPort(&curPort);
				SetPort(theWindow);
				qdLocal = mouse->AsQDPoint();
				GlobalToLocal(&qdLocal);
				*localMouse = qdLocal;
				
				SetPort(curPort);
			
				curFacet = targetWindow->GetFacetUnderPoint(ev, localMouse);
			}
			
			while (curFacet && !targetFacet)
			{
				ODFrame* curFrame = curFacet->GetFrame(ev);
				if (!curFrame->IsDragging(ev) &&
					curFrame->IsDroppable(ev) &&
					!curFrame->IsFrozen(ev) &&
					!_fFacetsRejected->Exists(&curFacet))
				{
					targetFacet = curFacet;
				}
				curFacet = curFacet->GetContainingFacet(ev);
			}
			
		SOM_CATCH_ALL
		SOM_ENDTRY
	}
	return targetFacet;
}

SOM_Scope void  SOMLINK ODDragAndDropGetPromiseFromDragManager(ODDragAndDrop *somSelf, Environment *ev,
		ODPart* sourcePart,
		ODStorageUnitView* destSUView)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetPromiseFromDragManager");

	SOM_TRY
	
	if (_fTrackingHandler == kODNULL)
		THROW(kODErrNoDragManager);

	OSErr			err;
	
	if (sourcePart != kODNULL) {

		ItemReference	dragItemRef;
		err = GetDragItemReferenceNumber(_fDragReference, 1, &dragItemRef);
		ASSERTM(err == noErr, err, "Cannot get drag item reference in GetPromiseFromDragManager");

		ODPromiseDesc	theInfo;
		theInfo.sourcePart = sourcePart;
		theInfo.destSUView = destSUView;
		
		// Set the offset of the suview to the beginning of the value
		destSUView->SetOffset(ev, 0);
				
		AEDesc			dropLocation;
		err = AECreateDesc(kODPromiseDesc, (Ptr) &theInfo, sizeof(theInfo), &dropLocation);
		ASSERTM(err == noErr, err, "Error from AECreateDesc in GetPromiseFromDragManager");
	
		err = SetDropLocation(_fDragReference, &dropLocation);
		ASSERTM(err == noErr, err, "Error from SetDropLocation in GetPromiseFromDragManager");

		gIsResolvingPromise = kODTrue;

		long			resolveResult;
		Size			resolveSize = sizeof(long);
		
		err = GetFlavorData(_fDragReference, dragItemRef, kODPromiseFlavor, &resolveResult, &resolveSize, 0);
		ASSERTM(err == cantGetFlavorErr, err, "Cannot GetFlavorData in GetPromiseFromDragManager");
		
		AEDisposeDesc(&dropLocation);
	
		// Reset the Drop location.

		gIsResolvingPromise = kODFalse;
		
		theInfo.sourcePart = kODNULL;
		theInfo.destSUView = kODNULL;
		
		err = AECreateDesc(kODPromiseDesc, (Ptr) &theInfo, 0, &dropLocation);
		ASSERTM(err == noErr, err, "Error from AECreateDesc in GetPromiseFromDragManager");
		
		err = SetDropLocation(_fDragReference, &dropLocation);
		ASSERTM(err == noErr, err, "Error from SetDropLocation in GetPromiseFromDragManager");
		
		AEDisposeDesc(&dropLocation);
	}
	else {
		ODHandle dataHandle = kODNULL;
		ODType isoType = kODNULL;
		TRY
		
			ODTranslation*	translate  = _fSession->GetTranslation(ev);
			isoType = destSUView->GetType(ev);
			if (ODISOStrNCompare((ODISOStr) isoType,(ODISOStr) kODAppleFileTypePrefix, ODISOStrLength(kODAppleFileTypePrefix)) != 0) {
				ItemReference   theItem;
				OSErr result;
				destSUView->SetOffset(ev,0);
				StorageUnitViewGetValue(destSUView, ev, sizeof(ItemReference), &theItem);			
				ODPlatformType platformType = translate->GetPlatformTypeFromISOType(ev, isoType);			
				if ( platformType == kODScrapTypestxt && !DragItemHasFlavor(_fDragReference, theItem, kODScrapTypestxt) )
				{
					// Create styled text from 'styl' and 'TEXT' flavors
#ifdef ODDebug_DragAndDrop
					somPrintf("GetPromiseFromDragManager: Creating 'stxt' from 'styl' and 'TEXT'\n");
#endif
					destSUView->SetOffset(ev,0);
					result = CopyFromDragItemInChunks(ev, kODScrapTypestyl, theItem, _fDragReference, destSUView);
					destSUView->SetOffset(ev, destSUView->GetSize(ev));
					result = CopyFromDragItemInChunks(ev, kODScrapTypeTEXT, theItem, _fDragReference, destSUView);
				}
				else
				{		
					destSUView->SetOffset(ev,0);
					result = CopyFromDragItemInChunks(ev, platformType, theItem, _fDragReference, destSUView);
				}
			}
			ODDisposePtr(isoType);
		
		CATCH_ALL
		
			if (dataHandle)
				ODDisposeHandle(dataHandle);
			if (isoType)
				ODDisposePtr(isoType);
			RERAISE;
		
		ENDTRY
	}
	
	SOM_CATCH_ALL
	SOM_ENDTRY
}

SOM_Scope void  SOMLINK ODDragAndDropGetDataFromDragManager(ODDragAndDrop *somSelf, Environment *ev,
		ODStorageUnitView*	suView)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDataFromDragManager");
    
	WARN("ODDragAndDropGetDataFromDragManager is obsoleted.\n");
}

SOM_Scope void  SOMLINK ODDragAndDropsomUninit(ODDragAndDrop *somSelf)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropsomUninit");

	if (_fDragItemList)
	{
		_fDragItemList->DeleteAllLinks();
		delete _fDragItemList;
	}
	if (_fDragItemIterator)
		delete _fDragItemIterator;
	if (_fReceiveHandler)
	{
		RemoveReceiveHandler(_fReceiveHandler, NULL);
		DisposeRoutineDescriptor(_fReceiveHandler);
	}
	if (_fTrackingHandler)
	{
		RemoveTrackingHandler(_fTrackingHandler, NULL);
		DisposeRoutineDescriptor(_fTrackingHandler);
	}
	if (_fSendDataHandler)
	{
		DisposeRoutineDescriptor(_fSendDataHandler);
	}
	
	ODDeleteObject(_fFacetsRejected);
	
	ODDisposePtr(_fPSN);
	ODDisposePtr(_fReplaceFileEvent);
}

SOM_Scope void  SOMLINK ODDragAndDropClear(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropClear");

#if ODDebug_DragAndDrop
	somPrintf("In Clear\n");
#endif

	if (_fTrackingHandler == kODNULL)
		ODSetSOMException(ev, kODErrNoDragManager);
	else {
		SOM_TRY
			if (_fDragItemIterator)
			{
				delete _fDragItemIterator;
				_fDragItemIterator = kODNULL;
			}
			_fDragItemList->DeleteAllLinks();
		SOM_CATCH_ALL
		SOM_ENDTRY
	}
}

SOM_Scope ODStorageUnit*  SOMLINK ODDragAndDropGetContentStorageUnit(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetContentStorageUnit");

	ODStorageUnit* contentSU = kODNULL;
	
	if (_fTrackingHandler == kODNULL)
		ODSetSOMException(ev, kODErrNoDragManager);
	else {
		SOM_TRY

			ODMemDragItem	*newItem;
			ODDragLink		*newLink;
		
			newItem = new(ODGetDefaultHeap()) ODMemDragItem(_fStorageSystem, kODFalse);
			ASSERTM(newItem != kODNULL, kODErrCannotAllocateDragItem, "Error allocating drag item");
			newItem->Initialize(ev);
			newLink = new ODDragLink(newItem, kODTrue);
			if (!newLink)
			{
				delete newItem;
				ASSERTM(newLink != kODNULL, kODErrCannotAllocateDragItem, "Error allocating drag link");
			}
			_fDragItemList->AddLast(newLink);
			contentSU = newItem->fSU;
			
		SOM_CATCH_ALL
		SOM_ENDTRY
	}
	return contentSU;
}

SOM_Scope ODDropResult  SOMLINK ODDragAndDropStartDrag(ODDragAndDrop *somSelf, Environment *ev,
		ODFrame* srcFrame,
		ODType imageType,
		ODByteArray* image,
		ODPart** destPart,
		ODByteArray* refCon)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropStartDrag");

	LinkedListIterator *theIter = kODNULL;	ODVolatile(theIter);

SOM_TRY
	if (_fTrackingHandler == kODNULL)
		THROW(kODErrNoDragManager);

	ASSERT(image != kODNULL, kODErrIllegalNullInput);
	ASSERT(refCon != kODNULL, kODErrIllegalNullInput);

	OSErr               result;
	RgnHandle           imageRgn;
	ODTranslation     *translate;
	ODULong            count, index;
	ODType             theISOType;
	ODPlatformType     platformType;
	PromiseHFSFlavor    thePromise;
	ODStorageUnit     *theSU;
	ODDragLink        *theDragLink;

	// Check if we know what the image type is
	ASSERTM(ODISOStrEqual(imageType, kODDragImageRegionHandle), kODErrUnknownDragImageType, "Unknown image type in StartDrag");

	// Set the drop result to kODDropFail. - VL
	_fDropResult = kODDropFail;
	
	// Begin the drag by creating a new drag reference
	result = NewDrag(&_fDragReference);
	ASSERTM(result == noErr, result, "Bad result from NewDrag");
	
#ifdef ODDebug_DragAndDrop
//	PrintDragReference(_fDragReference, "After NewDrag");
#endif

	// Register a send procedure so we don't have to cache any data with the drag manager
	result = SetDragSendProc(_fDragReference, _fSendDataHandler, (void *) somSelf);
	ASSERTM(result == noErr, result, "Bad result from SetDragSendProc");

	// Scan through all items in the drag and add a flavor for each value
	// in the storage unit's kODContents property
	theIter = new LinkedListIterator(_fDragItemList);
	translate = _fSession->GetTranslation(ev);
	imageRgn = *((RgnHandle*) image->_buffer);
	for (theDragLink = (ODDragLink*)theIter->First(); theDragLink; theDragLink = (ODDragLink*)theIter->Next())
	{
		theSU = theDragLink->fItem->fSU;
		ODBoolean	userPromise = ODSUExistsThenFocus(ev, theSU, kODPropContents, kODHFSPromise);
		if (userPromise)
		{
			ODByteArray ba;
			ODPart* dummySourcePart;
			theSU->GetPromiseValue(ev, kODHFSPromise, 0, sizeof(PromiseHFSFlavor), &ba, &dummySourcePart);
			if (ba._buffer)
			{
				ODBlockMove(ba._buffer, &thePromise, ba._length);
				ODDisposePtr(ba._buffer);
			}
			thePromise.promisedFlavor = kODUserPromiseFlavor;
		}
		else {
			// Always promise a file in case somebody wishes to drag this out to the finder
			thePromise.fileType = kODBentoFlavor;
			thePromise.fileCreator = kODShellSignature;
			thePromise.fdFlags = 0;
			thePromise.promisedFlavor = kODBentoFlavor;
		}
		result = AddDragItemFlavor(_fDragReference, (ItemReference)(theDragLink->fItem), flavorTypePromiseHFS,
								   &thePromise, sizeof(PromiseHFSFlavor), 0);
		ASSERTM(result == noErr, result, "Bad result from AddDragItemFlavor");

		result = AddDragItemFlavor(_fDragReference, (ItemReference)(theDragLink->fItem), (userPromise ? kODUserPromiseFlavor : kODBentoFlavor), 0L, 0L, 0);
		ASSERTM(result == noErr, result, "Bad result from AddDragItemFlavor");
		
		result = SetDragItemBounds(_fDragReference, (ItemReference)(theDragLink->fItem), &((**imageRgn).rgnBBox));
		ASSERTM(result == noErr, result, "Bad result from SetDragItemBounds");

#ifdef ODDebug_DragAndDrop
//	PrintStorageUnit(ev, theSU, "DragItem SU");
#endif
		theSU->Focus(ev,kODPropContents, kODPosUndefined, 0, 0, kODPosUndefined);
		count = theSU->CountValues(ev);
		for (index = 1; index <= count; ++index)
		{
			theSU->Focus(ev,kODPropContents, kODPosUndefined, 0, index, kODPosUndefined);
			theISOType = theSU->GetType(ev);
			platformType = translate->GetPlatformTypeFromISOType(ev, theISOType);
			ODDisposePtr(theISOType);
			if (!platformType)
				continue;
			result = AddDragItemFlavor(_fDragReference, (ItemReference)(theDragLink->fItem), platformType, 0L, 0L, 0);
			ASSERTM(result == noErr, result, "Bad result from AddDragItemFlavor");

			// If styled text ('stxt') was just added, also add 'stly' if
			// a 'TEXT' representation will also be written.
			if (     (platformType == kODScrapTypestxt)
				  && theSU->Exists(ev, kODPropContents, kODAppleTEXT, 0)
				  && !theSU->Exists(ev, kODPropContents, kODApplestyl, 0) )
			{
				result = AddDragItemFlavor(_fDragReference, (ItemReference)(theDragLink->fItem), kODScrapTypestyl, 0L, 0L, 0);
				ASSERTM(result == noErr, result, "Bad result from AddDragItemFlavor");
			}
		}
	
		// Always add our special dummy promise to the drag
		result = AddDragItemFlavor(_fDragReference, (ItemReference)(theDragLink->fItem), kODPromiseFlavor, 0L, 0L, 0);
		ASSERTM(result == noErr, result, "Bad result from adding kODPromiseFlavor");
	}

	_fSourceFrame = srcFrame;
	_fSourcePart = srcFrame->AcquirePart(ev);
	TRY
		_fDestFacet = kODNULL;
		_fDragItemIterator = new ODDragItemIterator();
		THROW_IF_NULL(_fDragItemIterator, kODErrOutOfMemory);
		_fDragItemIterator->InitDragItemIterator(ev, theIter);
		_fHasLeftSourceFrame = kODFalse;
		_fHasLeftSourcePart = kODFalse;
		
		#ifdef ODDebug_DragAndDrop
		//	PrintDragReference(_fDragReference, "Before TrackDrag");
		#endif
	
		// Do the drag	
		result = TrackDrag(_fDragReference, *((EventRecord**) refCon->_buffer), imageRgn);
	
		if (_fDestFacet)
			*destPart = _fDestFacet->GetFrame(ev)->AcquirePart(ev);
		else
			*destPart = kODNULL;
	CATCH_ALL
		DisposeDrag(_fDragReference);
		_fDragReference = kODNULL;
		ODReleaseObject(ev, _fSourcePart);
		RERAISE;
	ENDTRY
		
	DisposeDrag(_fDragReference);
	_fDragReference = kODNULL;
	_fSourceFrame = kODNULL;
	ODReleaseObject(ev, _fSourcePart);
	_fDestFacet = kODNULL;
	somSelf->Clear(ev);

	if (_fShouldSendReplaceFileEvent)
	{
		_fShouldSendReplaceFileEvent = kODFalse;
		OSErr err = SetupReplaceFileEvent(ev,
			_fReplaceFileEvent,
			&gTmpFileFSSpec,
			&gTargetFSSpec);
		SendReplaceFileEvent(_fReplaceFileEvent, _fPSN);
		DisposeReplaceFileEvent(_fReplaceFileEvent);
		CreateReplaceFileEvent(ev,
			_fReplaceFileEvent,
			_fSession,
			_fPSN);
	}

SOM_CATCH_ALL

	delete theIter;
	if (_fDragReference)
		DisposeDrag(_fDragReference);
	_fDragReference = kODNULL;
	
SOM_ENDTRY

	if (_fDropResult == kODDropMove)
		return kODDropMove;
	else if (_fDropResult == kODDropCopy)
		return kODDropCopy;
	else
		return kODDropFail;
}


SOM_Scope LinkedList*  SOMLINK ODDragAndDropGetDragItemList(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDragItemList");

	return _fDragItemList;
}

SOM_Scope void  SOMLINK ODDragAndDropSetDragItemList(ODDragAndDrop *somSelf, Environment *ev,
		LinkedList* list)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetDragItemList");

	_fDragItemList = list;
}

SOM_Scope ODBoolean  SOMLINK ODDragAndDropGetListFromHandler(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetListFromHandler");

    return _fListFromHandler;
}

SOM_Scope void  SOMLINK ODDragAndDropSetListFromHandler(ODDragAndDrop *somSelf, Environment *ev,
		ODBoolean listFromHandler)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetListFromHandler");

	_fListFromHandler = listFromHandler;
}

SOM_Scope ODFrame*  SOMLINK ODDragAndDropGetSourceFrame(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetSourceFrame");

	return _fSourceFrame;
}

SOM_Scope void  SOMLINK ODDragAndDropSetSourceFrame(ODDragAndDrop *somSelf, Environment *ev,
		ODFrame* sourceFrame)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetSourceFrame");

	_fSourceFrame = sourceFrame;
}

SOM_Scope ODULong  SOMLINK ODDragAndDropGetAttributes(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetAttributes");

	return _fAttributes;
}

SOM_Scope void  SOMLINK ODDragAndDropSetAttributes(ODDragAndDrop *somSelf, Environment *ev,
		ODULong attr)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetAttributes");

	_fAttributes = attr;
}

SOM_Scope ODPart*  SOMLINK ODDragAndDropGetSourcePart(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetSourcePart");

	return _fSourcePart;
}

SOM_Scope void  SOMLINK ODDragAndDropSetSourcePart(ODDragAndDrop *somSelf, Environment *ev,
		ODPart* sourcePart)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetSourcePart");

	_fSourcePart = sourcePart;
}

SOM_Scope ODDragItemIterator*  SOMLINK ODDragAndDropGetDragItemIterator(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDragItemIterator");

	return _fDragItemIterator;
}

SOM_Scope void  SOMLINK ODDragAndDropSetDragItemIterator(ODDragAndDrop *somSelf, Environment *ev,
		ODDragItemIterator* iter)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetDragItemIterator");

	_fDragItemIterator = iter;
}

SOM_Scope ODSession*  SOMLINK ODDragAndDropGetSession(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetSession");

	return _fSession;
}

SOM_Scope ODStorageSystem*  SOMLINK ODDragAndDropGetStorageSystem(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetStorageSystem");

	return _fStorageSystem;
}

SOM_Scope void  SOMLINK ODDragAndDropSetDragReference(ODDragAndDrop *somSelf, Environment *ev,
		ODPlatformDragReference dragReference)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetDragReference");
	
	_fDragReference = dragReference;
}

SOM_Scope ODFacet*  SOMLINK ODDragAndDropGetPrevFacet(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetPrevFacet");

	return _fPrevFacet;
}

SOM_Scope void  SOMLINK ODDragAndDropSetPrevFacet(ODDragAndDrop *somSelf, Environment *ev,
		ODFacet* prevFacet)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetPrevFacet");

	_fPrevFacet = prevFacet;
}

SOM_Scope ODFacet*  SOMLINK ODDragAndDropGetDestFacet(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDestFacet");

	return _fDestFacet;
}

SOM_Scope void  SOMLINK ODDragAndDropSetDestFacet(ODDragAndDrop *somSelf, Environment *ev,
		ODFacet* destFacet)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetDestFacet");

	_fDestFacet = destFacet;
}

SOM_Scope ODDropResult  SOMLINK ODDragAndDropGetDropResult(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDropResult");

	return _fDropResult;
}

SOM_Scope void  SOMLINK ODDragAndDropSetDropResult(ODDragAndDrop *somSelf, Environment *ev,
		ODDropResult dropResult)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropSetDropResult");

	_fDropResult = dropResult;
}

SOM_Scope ProcessSerialNumber*   SOMLINK ODDragAndDropGetPSN(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDropResult");

	return _fPSN;
}

SOM_Scope AppleEvent*   SOMLINK ODDragAndDropGetReplaceFileEvent(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDropResult");

	return _fReplaceFileEvent;
}

SOM_Scope void   SOMLINK ODDragAndDropSetShouldSendReplaceFileEvent(ODDragAndDrop *somSelf, Environment *ev,
	ODBoolean shouldSend)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropGetDropResult");

	_fShouldSendReplaceFileEvent = shouldSend;
}

ODBoolean DragItemHasFlavor(ODPlatformDragReference theDrag, ItemReference itemID, OSType	theType)
{
	ODBoolean	result = kODFalse;
	ODUShort	count;			
	ODUShort	j;
	OSType		itemType;

	CountDragItemFlavors(theDrag, itemID, &count);
	for (j = 1; j <= count; j++)
	{
		OSErr err = GetFlavorType(theDrag, itemID, j, &itemType);
		if ( err != noErr )
			break;
		if (itemType == theType)
		{
			result = kODTrue;
			break;
		}
	}

	return result;
}

pascal OSErr MyDragTrackingHandler(
		short message,
		WindowPtr theWindow,
		void* handlerRefCon,
		ODPlatformDragReference theDrag)
{
	ODDragAndDrop  *self = (ODDragAndDrop*)handlerRefCon;
	ODPoint			mouse, localMouse;
	OSErr			returnCode = noErr;

	TRY
	
		Environment*	ev = somGetGlobalEnvironment();
	
		switch (message)
		{
			case dragTrackingEnterHandler:
				returnCode = self->EnterHandler(ev, theDrag);
				break;			
			case dragTrackingEnterWindow:
				returnCode = self->EnterWindow(ev, theDrag, theWindow);
				break;
				
			case dragTrackingInWindow:
				returnCode = self->InWindow(ev, theDrag, theWindow);
				break;
				
			case dragTrackingLeaveWindow:
				returnCode = self->LeaveWindow(ev, theDrag, theWindow);
				break;
				
			case dragTrackingLeaveHandler:
				returnCode = self->LeaveHandler(ev);
				break;
		}
	
	CATCH_ALL
	
		returnCode = ErrorCode();
	
	ENDTRY

	return returnCode;
}

pascal OSErr	MyReceiveDropHandler(
		WindowPtr theWindow,
		void* handlerRefCon,
		ODPlatformDragReference theDrag)
{
	ODDragAndDrop	*self = (ODDragAndDrop*)handlerRefCon;
	ODPoint			mouse, localMouse;
	Point			qdMouse;
	ODFacet			*targetFacet;
	OSErr			returnCode = noErr;

#ifdef ODDebug_DragAndDrop
	somPrintf("MyReceiveDropHandler\n");
#endif

	Environment* ev = somGetGlobalEnvironment();

TRY

	GetDragMouse(theDrag, &qdMouse, 0L);
	mouse = qdMouse;
	targetFacet = self->FindTargetFacet(ev, theWindow, &mouse, &localMouse);
		
	if (!targetFacet || !(self->GetDragItemList(ev)->Count()))
		returnCode = dragNotAcceptedErr;
	else
	{
		TempODPart targetPart = targetFacet->GetFrame(ev)->AcquirePart(ev);

		// Assume _fDropResult is kODDropMove
		
		self->SetDropResult(ev, kODDropMove);
		
		// Are we going across Drafts?
		
		ODPart* sourcePart = self->GetSourcePart(ev);
		if ((sourcePart == kODNULL) || 
			(targetPart->GetStorageUnit(ev)->GetDraft(ev) != 
			sourcePart->GetStorageUnit(ev)->GetDraft(ev)))
			self->SetDropResult(ev, kODDropCopy);

		ODSShort	mouseDownModifiers;
		ODSShort	mouseUpModifiers;
				
		GetDragModifiers(self->GetDragReference(ev), 0L, &mouseDownModifiers, &mouseUpModifiers);

		// Check the mandatory modifier keys first
		
		if (mouseUpModifiers & optionKey) {
			self->SetDropResult(ev, kODDropCopy);
			SetPasteAsAttribute(self, ev, mouseUpModifiers);
		}
		else if (mouseUpModifiers & controlKey) {
			self->SetDropResult(ev, kODDropMove);
			SetPasteAsAttribute(self, ev, mouseUpModifiers);
		}
		else if (mouseUpModifiers & cmdKey) {
			SetPasteAsAttribute(self, ev, mouseUpModifiers);
		}

		// Then check the optional modifier keys
		
		else if (mouseDownModifiers & optionKey) {
			self->SetDropResult(ev, kODDropCopy);
			SetPasteAsAttribute(self, ev, mouseDownModifiers);
		}
		else if (mouseDownModifiers & controlKey) {
			self->SetDropResult(ev, kODDropMove);
			SetPasteAsAttribute(self, ev, mouseDownModifiers);
		}
		else if (mouseDownModifiers & cmdKey) {
			SetPasteAsAttribute(self, ev, mouseDownModifiers);
		}
					
		// Check to see whether it is an override by source part.
		ODDragItemIterator* dragItemIter = self->GetDragItemIterator(ev);
		if (dragItemIter)
		{
			ODStorageUnit* su = dragItemIter->First(ev);
			ODDraft* draft = su->GetDraft(ev);
			ODCloneKind cloneKind = GetOriginalCloneKind(ev, draft);
			if (cloneKind == kODCloneCopy)
				self->SetDropResult(ev, kODDropCopy);
		}
		
		// Drop
#ifdef ODDebug_DragAndDrop
	somPrintf("Calling Drop on targetFacet %x\n", targetFacet);
#endif

		self->SetAttributes(ev, self->GetAttributes(ev) | 
				(self->GetDropResult(ev) == kODDropMove ? kODDropIsMove : kODDropIsCopy));
				
		if (targetFacet->GetFrame(ev) == self->GetSourceFrame(ev))
			self->SetAttributes(ev, self->GetAttributes(ev) | (kODDropIsInSourceFrame | kODDropIsInSourcePart));
		else if (targetPart == self->GetSourcePart(ev))
			self->SetAttributes(ev, self->GetAttributes(ev) | kODDropIsInSourcePart);
				
		self->SetDestFacet(ev, targetFacet);
		self->SetPrevFacet(ev, kODNULL);
		ODULong dropResult = targetFacet->Drop(ev, &localMouse, self->GetDragItemIterator(ev), kODNULL);

		if (dropResult == kODDropFail) {
			self->SetDropResult(ev, dropResult);
			returnCode = dragNotAcceptedErr;
		}
		else if ((self->GetDropResult(ev) == kODDropMove) && (dropResult == kODDropCopy)) {
			self->SetDropResult(ev, kODDropCopy);
			returnCode = noErr;
		}
		
		ODDragItemIterator* iter = self->GetDragItemIterator(ev);
		ODSession* destSession = self->GetSession(ev);
		for (ODStorageUnit* su = iter->First(ev); iter->IsNotComplete(ev); su = iter->Next(ev)) {
			ODSession* sourceSession = su->GetSession(ev);
			if ((sourceSession != kODNULL) && (sourceSession != destSession)) {
				ODDragAndDrop* sourceDAD = sourceSession->GetDragAndDrop(ev);
				if (sourceDAD != kODNULL) {
					sourceDAD->SetDropResult(ev, self->GetDropResult(ev));
					sourceDAD->SetDestFacet(ev, targetFacet);
				}
			}
		}
//			ODSession* sourceSession = sourcePart->AcquireStorageUnit(ev)->GetSession(ev);
//			if (sourceSession != self->GetSession(ev)) {
//				ODDragAndDrop* sourceDAD = sourceSession->GetDragAndDrop(ev);
//				sourceDAD->SetDropResult(ev, self->GetDropResult(ev));
//				sourceDAD->SetDestFacet(ev, targetFacet);
//			}
//		}
	}

CATCH_ALL

	self->SetDropResult(ev, kODDropFail);
	returnCode = dragNotAcceptedErr;
#if ODDebug			
	somPrintf("Error in MyReceiveDropHandler.\n");
#endif

ENDTRY

	ODEventData	event;
	WaitNextEvent(mUpMask, (EventRecord*) &event, 0, kODNULL);
#if ODDebug_DragAndDrop			
	somPrintf("message %x when %x where %x modifier %x\n", event.message, event.when, event.where, event.modifiers);
#endif

	return returnCode;
}

pascal OSErr  MySendDataProc(
		FlavorType theType,
		void* refCon,
		ItemReference theItem,
		ODPlatformDragReference theDrag)
{
	ODDragAndDrop	*self = (ODDragAndDrop*)refCon;
	Environment*	ev = somGetGlobalEnvironment();
	OSErr			result = noErr;
	ODType			theISOType;
	ODTranslation	*translate;
	AEDesc			dropDescriptor;
	ODPtr			stylPtr = kODNULL;
	ODULong			stylSize = 0;

ODVolatile(result);
TRY

	LinkedListIterator iter(self->GetDragItemList(ev));
	ODDragLink*		theDragLink = kODNULL;
	ODMemDragItem*	theDragItem = kODNULL;

#ifdef ODDebug_DragAndDrop
	somPrintf("Entering MySendDataProc.\n");
#endif

	for (theDragLink = (ODDragLink*)iter.First(); 
	     theDragLink; theDragLink = (ODDragLink*)iter.Next())
	{
		if (theDragLink->fItem == (ODDragItem*)theItem)
		{
			theDragItem = (ODMemDragItem*) theDragLink->fItem;
			break;
		}
	}
	if (!theDragItem)
	{
		WARN("Item not found in send proc");
		result =  badDragFlavorErr;
	}
	else {
		switch (theType)
		{
			case kODPromiseFlavor:
#ifdef ODDebug_DragAndDrop
	somPrintf("MySendDataProc: kODPromiseFlavor\n");
#endif
				if (gIsResolvingPromise)
				{
					result = GetDropLocation(theDrag, &dropDescriptor);
					if ((result != noErr) || (dropDescriptor.descriptorType != kODPromiseDesc)) {
						WARN("Error from GetDropLocation in send procedure");
					}
					else {
						ODPromiseDesc     theInfo;
						ODBlockMove((Ptr)(*dropDescriptor.dataHandle), (Ptr)&theInfo, sizeof(ODPromiseDesc));
						if (theInfo.sourcePart && theInfo.destSUView)
						{
							TRY
								theInfo.sourcePart->FulfillPromise(ev, theInfo.destSUView);
							CATCH_ALL
								WARN("Error from FulfillPromise.");
							ENDTRY
						}
						result = noErr;
					}
				}
			break;
			case kODUserPromiseFlavor:
#ifdef ODDebug_DragAndDrop
	somPrintf("MySendDataProc: kODUserPromiseFlavor\n");
#endif
				result = noErr;
				ODStorageUnit* contentSU = theDragItem->fSU;
				if ((contentSU != kODNULL) && (contentSU->Exists(ev, kODPropContents, kODHFSPromise, 0)))
				{
					FSSpec dropFSSpec;
					result = GetDropFSSpec(theDrag, dropFSSpec);
					if (result == noErr)
					{
						TRY
							contentSU->Focus(ev, kODPropContents, kODPosUndefined, kODHFSPromise, 0, kODPosUndefined);
							StorageUnitSetPromiseValue(contentSU, ev, kODHFSPromise, 0, sizeof(FSSpec), &dropFSSpec, self->GetSourcePart(ev));
							contentSU->Focus(ev, kODPropContents, kODPosUndefined, kODHFSPromise, 0, kODPosUndefined);
							ODULong size = StorageUnitGetValue(contentSU, ev, sizeof(FSSpec), &dropFSSpec);
							if (size != sizeof(FSSpec))
							{
								self->SetDropResult(ev, kODDropFail);
								result = fnfErr;
							}
							else
							{
								self->SetDropResult(ev, IsTrashFolder(dropFSSpec) ? kODDropMove : kODDropCopy);
								SetDragItemFlavorData(theDrag, theItem, theType, &dropFSSpec, sizeof(FSSpec), 0L);
							}
						CATCH_ALL
							WARN("Error from FulfillPromise.");
						ENDTRY
					}
				}
			break;
			case kODBentoFlavor:
			{
#ifdef ODDebug_DragAndDrop
	somPrintf("MySendDataProc: kODBentoFlavor\n");
#endif
				// Check the drop location (probably from the finder)
				FSSpec dropFSSpec;
				
				result = GetDropFSSpec(theDrag, dropFSSpec);
				if (result == noErr)
				{
					boolean nameFromPart = MakeUniqueFilename(ev, self->GetSession(ev), theDragItem->fSU, &dropFSSpec);
	
					// Drags to the Trash are always a move
					ODULong dropResult;
					boolean isDraggingToTrash = IsTrashFolder(dropFSSpec);
					if( isDraggingToTrash )
						dropResult = kODDropMove;		// Dragged to Trash, so it's a move
					else
						dropResult = kODDropCopy;
					self->SetDropResult(ev, dropResult);
	
					if (isDraggingToTrash)
					{
						TempPlatformFile file = new PlatformFile;
						file->Specify(&dropFSSpec);
	
						if (file->Exists())
						{
							// If the target file exists in trash already,
							// set the fsspec to the temp folder.
							RespecifyToTempFolder(file);
							
							// Clone the data.
							CloneIntoFile(ev, theDragItem, file->GetFileSpec());
							
							// After cloning the data to the file (in temp folder),
							// move to it trash.
							file->MoveToTrash();
							
							// Set the result for Drag Manager.
							SetDragItemFlavorData(theDrag, theItem, theType, &(file->GetFileSpec()), sizeof(FSSpec), 0L);
						}
						else
						{
							CloneIntoFlavor(ev, self, theDragItem,
											theDrag, theItem, theType,
											dropFSSpec);
						}
					}
					else if (!nameFromPart)
					{
						CloneIntoFlavor(ev, self, theDragItem,
										theDrag, theItem, theType,
										dropFSSpec);
					}
					else if (IsFrontProcess())
					{
						TempPlatformFile file = new PlatformFile;
						file->Specify(&dropFSSpec);
	
						if (file->Exists())
						{
							ParamText(dropFSSpec.name, "\p", "\p", "\p");
							if (ODAskUserReplace(ev, self->GetSession(ev)))
							{						
								file->MoveToTrash();
								CloneIntoFlavor(ev, self, theDragItem,
												theDrag, theItem, theType,
												dropFSSpec);
							}
						}
						else
						{
							CloneIntoFlavor(ev, self, theDragItem,
											theDrag, theItem, theType,
											dropFSSpec);
						}
					}
					else
					{
						TempPlatformFile file = new PlatformFile;
						file->Specify(&dropFSSpec);
						
						if (file->Exists())
						{
							FSSpec targetFSSpec = file->GetFileSpec();
							RespecifyToTempFolder(file);
							FSSpec tmpFileFSSpec = file->GetFileSpec();
							CloneIntoFile(ev, theDragItem, tmpFileFSSpec);
							// Not notifying the target through SetDragItemData on purpose becuase we are going all the work.
							
							gTargetFSSpec = targetFSSpec;
							gTmpFileFSSpec = tmpFileFSSpec;
							self->SetShouldSendReplaceFileEvent(ev, kODTrue);
						}
						else
						{
							CloneIntoFlavor(ev, self, theDragItem,
										theDrag, theItem, theType,
										dropFSSpec);
						}				
					}
				}
			}
			break;
			default:
#ifdef ODDebug_DragAndDrop
	somPrintf("MySendDataProc: Default\n");
#endif
				self->SetDropResult(ev, kODDropFail);
				translate = self->GetSession(ev)->GetTranslation(ev);
				theISOType = translate->GetISOTypeFromPlatformType(ev, theType, kODPlatformDataType);
				if (ODSUExistsThenFocus(ev, theDragItem->fSU,kODPropContents, theISOType))
				{
					result = CopyToDragItemInChunks(ev, theType, theItem, theDrag, theDragItem);
					if (result == noErr)
						self->SetDropResult(ev, kODDropCopy);
				}
				else if ( (theType == kODScrapTypestyl) && StorageUnitGetStylFromStyledText(theDragItem->fSU, ev, &stylSize, &stylPtr) )
				{
					result = SetDragItemFlavorData(theDrag, theItem, theType, stylPtr, stylSize, 0L);
					WASSERTM(result == noErr, "Error from SetDragItemFlavorData in send procedure");		
					if (result == noErr)
						self->SetDropResult(ev, kODDropCopy);
					ODDisposePtr(stylPtr);
					stylPtr = kODNULL;
				}
				else
				{
					WARN("Send procedure can not supply this type");		
					result = badDragFlavorErr;
				}
				ODDisposePtr(theISOType);
			}
		}

CATCH_ALL
	self->SetShouldSendReplaceFileEvent(ev, kODFalse);
	result = ErrorCode();
	WARN("MySendDataProc: %d", result); 
ENDTRY
	return result;
}

static void CloneIntoFlavor(Environment* ev, ODDragAndDrop* dad, ODDragItem* theDragItem, 
								ODPlatformDragReference theDrag, ItemReference theItem, FlavorType theType,
								FSSpec dropFSSpec)
{
	OSErr result;
	
	if ((result = CloneIntoFile(ev, theDragItem, dropFSSpec)) == noErr)
	{
		result = SetDragItemFlavorData(theDrag, theItem, theType, &dropFSSpec, sizeof(FSSpec), 0L);
	}
	else
	{
		dad->SetDropResult(ev, kODDropFail);				
	}				
}

static OSErr CloneIntoFile(Environment* ev, ODDragItem* theDragItem, FSSpec dropFSSpec) 
{
	OSErr			err = noErr;
	PlatformFile	file;
	file.Specify(&dropFSSpec);
	
	TRY
		ODStorageUnit* contentSU = theDragItem->fSU;
		ODID targetContentFrameID = kODNULLID;
		OSType	fileType = GetStorageUnitOSType(ev,contentSU);

		file.Create(kODShellSignature, fileType, smSystemScript);
		SetFinderInfo(ev, contentSU, &file);
		SetIconFamily(ev, contentSU, &file);
		TempODContainer targetContainer	= CreateFileContainer(ev, contentSU->GetSession(ev), &file.GetFileSpec());
		TempODDocument	targetDocument	= targetContainer->AcquireDocument(ev, kODDefaultDocument);
		TempODDraft		targetDraft 	= targetDocument->AcquireBaseDraft(ev, kODDPExclusiveWrite);
		TempODStorageUnit 	targetDraftProperties = targetDraft->AcquireDraftProperties(ev);
		TempODStorageUnit	targetSU	= targetDraft->CreateStorageUnit(ev);
		ODSetStrongSURefProp(ev, targetDraftProperties, kODPropRootPartSU,kODStrongStorageUnitRef, targetSU->GetID(ev));
		ODDraft* sourceDraft = contentSU->GetDraft(ev);				
		ODDraftKey cloneKey = 0;
		TRY
			cloneKey = sourceDraft->BeginClone(ev, targetDraft, kODNULL, kODCloneToFile);
			sourceDraft->Clone(ev, cloneKey, contentSU->GetID(ev), targetSU->GetID(ev), 0);				
			ODID contentFrameID = ODGetWeakSURefProp(ev, contentSU, kODPropContentFrame, kODWeakStorageUnitRef);
			if (contentFrameID != kODNULLID) 
			{
				targetContentFrameID = sourceDraft->Clone(ev, cloneKey, contentFrameID, kODNULLID, 0);				
			}		
			sourceDraft->EndClone(ev, cloneKey);
		CATCH_ALL
			sourceDraft->AbortClone(ev, cloneKey);
		ENDTRY
		
		if (targetContentFrameID != kODNULLID)
			ODSetStrongSURefProp(ev, targetDraftProperties, kODPropRootFrameList, kODStrongStorageUnitRefs, targetContentFrameID);

		ODSURemoveProperty(ev, targetSU, kODPropMouseDownOffset);

		targetDraft->Externalize(ev);

				
	CATCH_ALL
	
		file.Delete();		
		err = dragNotAcceptedErr;
		WARN("Error caught in CloneIntoFile.");
	ENDTRY
	
	return err;
}

static boolean MakeUniqueFilename( Environment *ev, ODSession* session, ODStorageUnit *su, FSSpec* spec )
{
	const ODULong kODMaxFileNameSize = 63;
	
	Str255 prefix;
	prefix[0] = 0;
	boolean nameFromPart = false;
	TempPlatformFile file = new PlatformFile;
	file->Specify(spec);
	
	// Get the name of the part
	if (su->Exists(ev, kODPropName, kODMacIText, 0))
	{
		ODIText* rootPartName = ODGetITextProp(ev, su, kODPropName, kODMacIText, kODNULL);
		if (rootPartName)
		{
			GetITextPString(rootPartName, prefix);
			DisposeIText(rootPartName);
			p2cstr(prefix);
			file->SetAsciiName((char*) prefix);	
			nameFromPart = true;
		}
	}

	if (!prefix[0])
	{		
		// Get the category of the part if a name cannot be found.
		
		ODName* categoryName = ODGetCatFromPartSU(ev, su, session->GetNameSpaceManager(ev));
		if (categoryName)
		{
			GetITextPString(categoryName, prefix);
			p2cstr(prefix);
			file->SetAsciiName((char*) prefix);	
			file->UniquifyName(kODNoResourceID,
								kODNULL,
								kODCategoryNumberSuffix,
								kODNULL,
								1,
								kSpecifyNewNameOnly,
								kODForceNewName);
			ODDisposePtr(categoryName);
			nameFromPart = false;
		}
	}
	*spec = file->GetFileSpec();
	
	return nameFromPart;
}

static OSType GetStorageUnitOSType( Environment *ev, ODStorageUnit *su )
{
	OSType	returnType = kODShellSignature;

#if ODDebug_DragAndDrop
	ODULong	numProperties = su->CountProperties(ev);
	su->Focus(ev, kODNULL, kODPosAll, kODNULL, 0, kODPosAll);
	for (ODULong i = 1; i <= numProperties; i++) {
		su->Focus(ev, kODNULL, kODPosNextSib,kODNULL,0,kODPosAll);
		ODPropertyName name = su->GetProperty(ev);
		ODDisposePtr(name);
	}
#endif
	
	returnType = ODGetIconFilePlatformTypeFromPartSU(ev, su);
	
	/*
	//ODGetIconFilePlatformTypeFromPartSU is more correct than the below code:
	
	if (su->Exists(ev, kODPropContents,kODNULL,1)) {
		su->Focus(ev, kODPropContents,kODPosUndefined,kODNULL,1,kODPosUndefined);
		ODType suType = su->GetType(ev);
		if(suType != kODNULL) {
			ODValueNameSpace* osTypeNameSpace = (ODValueNameSpace*)
						su->GetSession(ev)->GetNameSpaceManager(ev)->HasNameSpace(ev,kODKindOldMacOSType);
			if (osTypeNameSpace) {
				ODOSType*   osTypePtr;
				ODOSType	osType;
				ODULong		valueLen;
				ODBoolean	osTypeFound = ValueNameSpaceGetEntry(
											osTypeNameSpace, 
									   ev, 
									   suType, 
										  	(ODPtr*) &osTypePtr,
										    &valueLen);
				if (osTypeFound) {
					osType = *osTypePtr;
					ODDeleteObject( osTypePtr );
					
					WASSERT(valueLen==sizeof(OSType));
					returnType = osType;
				}
				// SS: Begin Code Changes
				else {
					ODTranslation* translate = ODGetSession(ev,su)->GetTranslation(ev);
					ODOSType osType = (ODOSType)translate->GetPlatformTypeFromISOType(ev, suType);
					
					if ( osType != kODNULL )
					{
						returnType = osType;
						((ODUByte*)(&returnType))[0] = kODPlatformKindFileChar1;
					}
				}
				// SS: End Code Changes
			}
		}
	}
	*/
	return returnType;
}


static OSErr CopyToDragItemInChunks(Environment* ev,
								FlavorType theType,
								ItemReference theItem,
								ODPlatformDragReference theDrag,
								ODDragItem* theDragItem) 
{
	const ODULong kCopyBlockSize = 512;
	OSErr	result = noErr;
	ODPtr 	dataPtr = ODNewPtr(kCopyBlockSize);
	ODULong dataSize = theDragItem->fSU->GetSize(ev);
	
	ODULong currentByte = 0;
	while ((currentByte < dataSize) && (result == noErr)) {
		ODULong bytesRead = StorageUnitGetValue(theDragItem->fSU, ev, kCopyBlockSize, dataPtr);
		result = SetDragItemFlavorData(theDrag, theItem, theType, dataPtr, bytesRead, currentByte);
		WASSERTM(result == noErr, "Error from SetDragItemFlavorData in CopyToDragItemInChunks.");		
		currentByte += bytesRead;
	}
	ODDisposePtr(dataPtr);
	WASSERTM(currentByte == dataSize, "Bytes written is NOT equal to dataSize.");		
	
	return result;
}

static OSErr CopyFromDragItemInChunks(Environment* ev,
								FlavorType theType,
								ItemReference theItem,
								ODPlatformDragReference theDrag,
								ODStorageUnitView* destSUView) 
{
	const ODULong kCopyBlockSize = 512;
	OSErr	result = noErr;
	ODPtr 	dataPtr = ODNewPtr(kCopyBlockSize);
	long	dataSize = 0;
	ODULong	totalRead = 0;
	ODULong	oldValueSize = destSUView->GetSize(ev);
	
	result = GetFlavorDataSize(theDrag, theItem, theType, &dataSize);
	while ((totalRead < dataSize) && (result == noErr)) {
		Size bytesRead = dataSize - totalRead;
		if (bytesRead > kCopyBlockSize)
			bytesRead = kCopyBlockSize;
		result = GetFlavorData(theDrag, theItem, theType, dataPtr, &bytesRead, totalRead);
		WASSERTM(result == noErr, "Error from GetFlavorData in CopyFromDragItemInChunks.");		
		StorageUnitViewSetValue(destSUView, ev, bytesRead, dataPtr);
		totalRead += bytesRead;
	}
	ODDisposePtr(dataPtr);

	ODULong newValueSize = destSUView->GetOffset(ev);
	if (oldValueSize > newValueSize)
		destSUView->DeleteValue(ev, oldValueSize - newValueSize);

	return result;
}


#ifdef ODDebug_DragAndDrop
void PrintDragReference(ODPlatformDragReference dragRef, char* header)
{
	unsigned short	items = 0;
	CountDragItems(dragRef, &items);
	somPrintf("%s: fDragReference %x numItems %d\n", header, dragRef, items);
	for (unsigned short i = 1; i <= items; i++) {
		ItemReference	itemRef;
		GetDragItemReferenceNumber(dragRef, i, &itemRef);
		unsigned short numFlavors = 0;
		CountDragItemFlavors(dragRef, itemRef, &numFlavors);
		FlavorType theType;
		Size	dataSize = 0;
		for (unsigned short j = 1; j <= numFlavors; j++) {
			GetFlavorType (dragRef, itemRef, j, &theType);
			GetFlavorDataSize(dragRef, itemRef, theType, &dataSize);
			somPrintf("%s: itemRef %x item %d flavor %d size %d type ", header, itemRef, i, j, dataSize);
			for (short k = 0; k <= 3; k++) {
				somPrintf("%c", ((char*) &theType)[k]);
			}
			somPrintf("\n");
			if ((theType == 'hfs ') && (dataSize > 0)) {
				HFSFlavor hfsFlavor;
				GetFlavorData(dragRef,itemRef,theType,&hfsFlavor,&dataSize,0);
				somPrintf("type %x creator %x name %s\n", hfsFlavor.fileType, hfsFlavor.fileCreator, p2cstr(hfsFlavor.fileSpec.name));
			}
		}
	}
}

void PrintStorageUnit(Environment* ev, ODStorageUnit* su, char* header)
{
	ODStorageUnitCursor* cursor = su->CreateCursorWithFocus(ev);
	
	ODULong numProperties = su->CountProperties(ev);
	su->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosUndefined);
	ODULong numValues = su->CountValues(ev);
	somPrintf("%s: su %x numProperties %d numContentValues %d\n", header, su, numProperties, numValues);
	for (short i = 1; i <= numValues; i++) {
		su->Focus(ev, kODNULL, kODPosSame, kODNULL, i, kODPosUndefined);
		ODValueType type = su->GetType(ev);
		somPrintf("%s: Type %d %s\n", header, i, type);
		ODDisposePtr(type);
	}
	
	su->FocusWithCursor(ev, cursor);
	delete cursor;
}

#endif

SOM_Scope OSErr  SOMLINK ODDragAndDropEnterHandler(ODDragAndDrop *somSelf, Environment *ev,
		ODPlatformDragReference theDrag)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropEnterHandler");

#if ODDebug_DragAndDrop
	somPrintf("In EnterHandler.\n");
#endif		

	OSErr			returnCode = noErr;

	ODVolatile(returnCode);
	SOM_TRY
		OSErr			result = noErr;
		ODDragLink*		newLink = kODNULL;
		ODUShort		items = 0;
		
		CountDragItems(theDrag, &items);
		for (ODUShort i = 1; i <= items; ++i)
		{
			ItemReference	itemID;
			FlavorFlags		theFlags;
			GetDragItemReferenceNumber(theDrag, i, &itemID);
			result = GetFlavorFlags(theDrag, itemID, kODPromiseFlavor, &theFlags);
			if (result == noErr) {
				if (_fDragReference != theDrag)
				{
					_fListFromHandler = kODTrue;
					newLink = new ODDragLink((ODDragItem*)itemID, kODFalse);
					_fDragItemList->AddLast((Link*)newLink);
				}
			}
			else if (result == badDragFlavorErr) {
				ODStorageSystem*	storage = _fStorageSystem;
				ODTranslation*		translate = _fSession->GetTranslation(ev);
				ODDragItem*			newItem = kODNULL;		ODVolatile(newItem);
				
				ODUShort	count;			
				ODUShort	j = 1;
				HFSFlavor	hfsFlavor;
				PlatformFile*	finderFile = kODNULL;
				CountDragItemFlavors(theDrag, itemID, &count);
				for (j = 1; (j <= count) && (newItem == kODNULL); j++) {
					OSType	theType;
					OSErr	err		 = GetFlavorType(theDrag, itemID, j, &theType);
					if ((err == noErr) && (theType == flavorTypeHFS)) {
						Size			dataSize = sizeof(HFSFlavor);
						OSErr err = GetFlavorData(theDrag, itemID, theType, &hfsFlavor, (Size*) &dataSize, 0);
						if (err == noErr)
						{
							FSSpec targetFileSpec = hfsFlavor.fileSpec;
							if ((hfsFlavor.fileCreator == kODShellSignature) &&
								IsOpenDocDocument(hfsFlavor.fileType))
							{
								ODBoolean wasAliased;
								ODBoolean targetIsFolder;
								OSErr err = ResolveAliasFile(&targetFileSpec, TRUE, &targetIsFolder, &wasAliased);
								if ((err == noErr)  && (!targetIsFolder)) {
									FInfo	finderInfo;
									err = FSpGetFInfo(&targetFileSpec, &finderInfo);
									if ((err == noErr) && IsOpenDocDocument(finderInfo.fdType)) {
										ODByteArray*	ba = CreateByteArray(&targetFileSpec, sizeof(FSSpec));
										TRY
											newItem = new(ODGetDefaultHeap()) ODFileDragItem(storage, kODTrue);
											((ODFileDragItem*) newItem)->Initialize(ev, ba);
										CATCH_ALL
											delete newItem;
											newItem = kODNULL;
										ENDTRY
										DisposeByteArray(ba);
									}
								}
							}
							finderFile = new PlatformFile();
							finderFile->Specify(&targetFileSpec);
						}
					}
				}
				if (newItem == kODNULL) {
					newItem = new(ODGetDefaultHeap()) ODMemDragItem(storage, kODTrue);
					((ODMemDragItem*) newItem)->Initialize(ev);
				}
				ODStorageUnit*	su = newItem->fSU;
				if (finderFile)
				{
					GetFinderInfo(ev, su, finderFile);
					GetIconFamilyFromFile(ev, su, finderFile);
					delete finderFile;
				}
				ODSUForceFocus(ev, su, kODPropContents, kODNULL);
				for (j = 1; j <= count; j++) {
					OSType			theType;
					OSErr err = GetFlavorType(theDrag, itemID, j, &theType);
					ODValueType isoType = translate->GetISOTypeFromPlatformType(ev, theType, kODPlatformDataType);
					su->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosUndefined);
					StorageUnitSetPromiseValue(su, ev, isoType, 0, sizeof(ItemReference), &itemID, kODNULL);
					ODDisposePtr(isoType);
					// If theType is 'styl', add a promise for 'stxt'
					if ( theType == kODScrapTypestyl )
					{
						if ( DragItemHasFlavor(theDrag, itemID, kODScrapTypeTEXT) && !DragItemHasFlavor(theDrag, itemID, kODScrapTypestxt) )
							StorageUnitSetPromiseValue(su, ev, kODApplestxt, 0, sizeof(ItemReference), &itemID, kODNULL);
					}
					else if (theType == flavorTypeHFS)
					{
						ODValueType isoType = translate->GetISOTypeFromPlatformType(ev, hfsFlavor.fileType, kODPlatformFileType);
						su->AddValue(ev, isoType);
						ODDisposePtr(isoType);
					}
				}
				_fListFromHandler = kODTrue;
				newLink = new ODDragLink(newItem, kODTrue);
				_fDragItemList->AddLast((Link*)newLink);
			}
			else
			{
				WASSERTM(result == noErr, "Error from GetFlavorFlags in tracking handler");
				returnCode = result;
				break;
			}
		}
		_fDragReference = theDrag;
		_fAttributes = 0;
		if (_fListFromHandler)
		{
			LinkedListIterator*	newIter = new LinkedListIterator(_fDragItemList);
			ODDragItemIterator* tmpIter = new ODDragItemIterator();
			THROW_IF_NULL(tmpIter, kODErrOutOfMemory);
			tmpIter->InitDragItemIterator(ev, newIter);
			_fDragItemIterator = tmpIter;
		}
	
		ODDeleteObject(_fFacetsRejected);
		
	SOM_CATCH_ALL	
	
		returnCode = ErrorCode();
		ODDeleteObject(_fFacetsRejected);
		if (_fDragItemList)
			_fDragItemList->DeleteAllLinks();
		
	SOM_ENDTRY

	_fFacetsRejected = new OpenHashTable(OpenHashTable::StdEqual, OpenHashTable::StdHash, kODNULL);
	_fFacetsRejected->Initialize(kODInitialNumEntries,
									sizeof(ODFacet*),
									sizeof(ODFacet*));
	
	return returnCode;
}

SOM_Scope OSErr  SOMLINK ODDragAndDropEnterWindow(ODDragAndDrop *somSelf, Environment *ev,
		ODPlatformDragReference theDrag,
		ODPlatformWindow theWindow)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropEnterWindow");
	
	// This is a private method called only from MyDragTrackingHandler.
	// It can do without its own SOM_TRY.

#if ODDebug_DragAndDrop
	somPrintf("Enter EnterWindow.\n");
#endif

	ODPoint			mouse, localMouse;
	Point			qdMouse;
	ODFacet*		targetFacet = kODNULL;
	ODBoolean		handled = kODFalse;
	
	GetDragMouse(theDrag, &qdMouse, 0L);
	mouse = qdMouse;
	targetFacet = somSelf->FindTargetFacet(ev, theWindow, &mouse, &localMouse);
	if (!targetFacet)
		_fAttributes &= kODDragHasLeftSourcePartMask;
	else
	{
		while (targetFacet && !handled)
		{
			if ((targetFacet->GetFrame(ev) == _fSourceFrame) && (_fHasLeftSourceFrame == kODFalse)) {
				_fAttributes |= kODDragIsInSourcePart;
				_fAttributes |= kODDragIsInSourceFrame;
			}
			else
			{
				_fHasLeftSourceFrame = kODTrue;
				ODPart* targetPart = targetFacet->GetFrame(ev)->AcquirePart(ev);
				if (targetPart == _fSourcePart)
					_fAttributes = kODDragIsInSourcePart;
				else {
					_fHasLeftSourcePart = kODTrue;
					_fAttributes = 0;
				}
				ODReleaseObject(ev, targetPart);
			}
			handled = targetFacet->DragEnter(ev, &localMouse, _fDragItemIterator, kODNULL);
			if (!handled)
			{
				_fFacetsRejected->ReplaceEntry(&targetFacet, &targetFacet);
				targetFacet = somSelf->FindTargetFacet(ev, theWindow, &mouse, &localMouse);
			}
		}
	}
	_fPrevFacet = targetFacet;
	
	return noErr;
}

SOM_Scope OSErr  SOMLINK ODDragAndDropInWindow(ODDragAndDrop *somSelf, Environment *ev,
		ODPlatformDragReference theDrag,
		ODPlatformWindow theWindow)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropInWindow");

	ODPoint			mouse, localMouse;
	Point			qdMouse;
	ODFacet*		targetFacet = kODNULL;
	ODBoolean		handled = kODFalse;
	
	SOM_TRY
	
		GetDragMouse(theDrag, &qdMouse, 0L);
		mouse = qdMouse;
		targetFacet = somSelf->FindTargetFacet(ev, theWindow, &mouse, &localMouse);
		
		if (!targetFacet) {
			_fAttributes &= kODDragHasLeftSourcePartMask;
			if (_fPrevFacet) {
				_fPrevFacet->DragLeave(ev, &localMouse, kODNULL);
			}
		}
		else
		{	
			while (targetFacet && !handled)
			{
				if ((targetFacet->GetFrame(ev) == _fSourceFrame) && (_fHasLeftSourceFrame == kODFalse)) {
					_fAttributes |= kODDragIsInSourcePart;
					_fAttributes |= kODDragIsInSourceFrame;
				}
				else {
					_fHasLeftSourceFrame = kODTrue;
					ODPart* targetPart = targetFacet->GetFrame(ev)->AcquirePart(ev);
					if (targetPart == _fSourcePart)
						_fAttributes = kODDragIsInSourcePart;
					else {
						_fHasLeftSourcePart = kODTrue;
						_fAttributes = 0;
					}
					ODReleaseObject(ev, targetPart);
				}
				if (_fPrevFacet == targetFacet)  {
					handled = targetFacet->DragWithin(ev, &localMouse, _fDragItemIterator, kODNULL);
				}
				else {
					if (_fPrevFacet) {
						_fPrevFacet->DragLeave(ev, &localMouse, kODNULL);
					}
					handled = targetFacet->DragEnter(ev, &localMouse, _fDragItemIterator, kODNULL);
				}
				if (!handled)
				{
					_fFacetsRejected->ReplaceEntry(&targetFacet, &targetFacet); 
					targetFacet = somSelf->FindTargetFacet(ev, theWindow, &mouse, &localMouse);
				}
			}
		}
		_fPrevFacet = targetFacet;
	
	SOM_CATCH_ALL
	SOM_ENDTRY

	return noErr;
}

SOM_Scope OSErr  SOMLINK ODDragAndDropLeaveWindow(ODDragAndDrop *somSelf, Environment *ev,
		ODPlatformDragReference theDrag,
		ODPlatformWindow theWindow)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropLeaveWindow");

#if ODDebug_DragAndDrop
	somPrintf("In LeaveWindow.\n");
#endif		

	SOM_TRY
		ODPoint			mouse, localMouse;
		Point			qdMouse;
		
		GetDragMouse(theDrag, &qdMouse, 0L);
		mouse = qdMouse;
		ODFacet* dummyTargetFacet = somSelf->FindTargetFacet(ev, theWindow, &mouse, &localMouse);
	
		_fAttributes = 0;
		if (_fPrevFacet) {
			_fPrevFacet->DragLeave(ev, &localMouse, kODNULL);
			_fPrevFacet = kODNULL;
		}
	SOM_CATCH_ALL
	ENDTRY
	
	_fHasLeftSourceFrame = kODTrue;
	_fHasLeftSourcePart = kODTrue;

	return noErr;
}

SOM_Scope OSErr  SOMLINK ODDragAndDropLeaveHandler(ODDragAndDrop *somSelf, Environment *ev)
{
    ODDragAndDropData *somThis = ODDragAndDropGetData(somSelf);
    ODDragAndDropMethodDebug("ODDragAndDrop","ODDragAndDropLeaveHandler");

#if ODDebug_DragAndDrop
	somPrintf("In LeaveHandler.\n");
#endif		
    
	// Now undo the damage done in the dragTrackingEnterHandler section.
	// NOTE: It is OK to blow away the drag items here because at this point
	// the drop handler will already have processed the drop if any.
	if (_fListFromHandler)
	{
		TRY{
			somSelf->Clear(ev);
		}CATCH_ALL{
			// ignore error
		}ENDTRY
		_fListFromHandler = kODFalse;
		_fDragReference = 0;
	}
	_fAttributes = 0;
	
	return noErr;
}

static void	SetIconFamily(Environment* ev, ODStorageUnit* fromSU, PlatformFile* file)
{
	static const ResType			kIconType[6] = {'ICN#','icl4','icl8','ics#','ics4','ics8'};
	static const short				kIconSize[6] = {256,   512,   1024,  64,    128,   256   };
 	ODIconFamily icons = ODGetIconFamilyProp(ev, fromSU, kODPropCustomIcon, kODIconFamily, kAllIconsMask);
	
	if (icons)
	{
		// write icons to the file
		long	i = 6;
		do {
			Handle	icon;
			char	state;
			if ((GetIconFromSuite(&icon, icons, kIconType[--i]) == noErr) && (icon != nil))
			{
				state = HGetState(icon);
				HLock(icon);
				WASSERT(GetHandleSize(icon) == kIconSize[i]);
				file->WriteResourcePtr(kIconType[i], kCustomIconResource, *icon, kIconSize[i]);
				HSetState(icon, state);
			}
		} while (i);
		file->SetCustomIcon(kODTrue);
	}
}

static void SetFinderInfo(Environment* ev, ODStorageUnit* su, PlatformFile* file)
{
	InitDateInfo(ev, su);
	ODULong modDate = ODGetModificationDate(ev, su);
	ODULong creationDate = ODGetCreationDate(ev, su);		
	
	file->CreateResFile();	
	file->SetFileModDate(modDate);
	file->SetFileCreationDate(creationDate);
	file->SetStationery(ODGetSUIsStationery(ev, su));
}

static OSErr GetDropFSSpec(ODPlatformDragReference theDrag, FSSpec &dropFSSpec)
{
	AEDesc	dropDescriptor;

	OSErr result = GetDropLocation(theDrag, &dropDescriptor);
	if ((result != noErr) ||
		(dropDescriptor.descriptorType == typeNull) ||
		(dropDescriptor.dataHandle == nil))
	{
		result = fnfErr;			// Can't create a file unless we know where it goes!
	}
	else
	{
		AEDesc fssDescriptor;
		result = AECoerceDesc(&dropDescriptor, typeFSS, &fssDescriptor);
		AEDisposeDesc(&dropDescriptor);
		if (result == noErr) {		
			ODBlockMove(*fssDescriptor.dataHandle, &dropFSSpec, sizeof(FSSpec));
			AEDisposeDesc(&fssDescriptor);

			// Use PBGetCatInfo to get the directoryID of the target directory.
			CInfoPBRec getInfoPB;
			getInfoPB.dirInfo.ioCompletion = 0L;
			getInfoPB.dirInfo.ioNamePtr = (StringPtr) &(dropFSSpec.name);
			getInfoPB.dirInfo.ioVRefNum = dropFSSpec.vRefNum;
			getInfoPB.dirInfo.ioFDirIndex = 0;
			getInfoPB.dirInfo.ioDrDirID = dropFSSpec.parID;
			result = PBGetCatInfoSync(&getInfoPB);
			if (result == noErr)
			{
				dropFSSpec.parID = getInfoPB.dirInfo.ioDrDirID;
				dropFSSpec.name[0] = 0;
			}
		}
	}
	
	return result;
}

static boolean IsTrashFolder(FSSpec dropFSSpec)
{
	short trashVol;
	long trashDir;

	return (FindFolder(dropFSSpec.vRefNum,kTrashFolderType,kDontCreateFolder,&trashVol,&trashDir) == noErr) && 
			(trashVol==dropFSSpec.vRefNum) && (
			(trashDir==dropFSSpec.parID) );

}

static boolean IsFrontProcess()
{
	ProcessSerialNumber myProcess, frontProcess;
	boolean inFront = false;

	GetCurrentProcess(&myProcess);
	GetFrontProcess(&frontProcess);
	SameProcess(&myProcess, &frontProcess, &inFront);

	return inFront;
}

static OSErr CreateReplaceFileEvent(Environment* ev,
	AppleEvent* replaceFileEvent,
	ODSession* session,
	ProcessSerialNumber* psn)
{
	OSErr			err = noErr;
	AEAddressDesc	targetAddress;
	TempAEDesc		tempTargetAddress = kODNULL;
	
	err = AECreateDesc(typeProcessSerialNumber, psn, sizeof(ProcessSerialNumber), &targetAddress);

	if (err == noErr)
	{
		err = AECreateAppleEvent(kODShellSignature, kODReplaceFileEventID, 
				&targetAddress, kAutoGenerateReturnID, 
				kAnyTransactionID, replaceFileEvent);
		AEDisposeDesc(&targetAddress);
	}
	if ( err == noErr )
		err = AEPutParamPtr(replaceFileEvent, kODSession, typeLongInteger,
							&session, sizeof(ODSession*));
	return err;
}

static OSErr SetupReplaceFileEvent(Environment* ev,
	AppleEvent* replaceFileEvent,
	FSSpec* sourceFileSpec,
	FSSpec* destFileSpec)
{
	OSErr err = noErr;
	if (err == noErr)
	{
		err = AEPutParamPtr(replaceFileEvent, kODSourceFileSpec, typeFSS,
						sourceFileSpec, sizeof(FSSpec));
	}
	if ( err == noErr )
		err = AEPutParamPtr(replaceFileEvent, kODDestinationFileSpec, typeFSS,
							destFileSpec, sizeof(FSSpec));

#ifdef ODDebug					
	if (err != noErr)
	{
		WARN("Error in SetupReplaceFileEvent: %d", err);
	}
#endif

	return err;
}

static OSErr SendReplaceFileEvent(AppleEvent* replaceFileEvent, ProcessSerialNumber* psn)
{
	OSErr		err;
	AppleEvent	replyAppleEvent;
	
	SetFrontProcess(psn);
	
//	TempAEDesc tmpReplaceFileAppleEvent(replaceFileEvent);
	err = AESend(replaceFileEvent, &replyAppleEvent, kAENoReply | kAEInteractWithSelf,
						kAENormalPriority, kAEDefaultTimeout, NULL, NULL);

#ifdef ODDebug					
	if (err != noErr)
	{
		WARN("Error in SendReplaceFileEvent: %d", err);
	}
#endif
							
	return err;
}

static OSErr DisposeReplaceFileEvent(AppleEvent* replaceFileEvent)
{
	return AEDisposeDesc(replaceFileEvent);
}

static OSErr ODPascal ReplaceFileAEHandler(
		const AppleEvent* replaceFileEvent,
		AppleEvent* reply,
		long refCon)
{
	OSErr		err = noErr;
	DescType	returnedType;
	Size		actualSize;
	FSSpec		sourceFileSpec;
	FSSpec		destFileSpec;
	ODSession*	session = kODNULL;
	
	err = AEGetParamPtr(replaceFileEvent, kODSession,
							typeLongInteger, &returnedType,
							&session, sizeof(ODSession*), &actualSize);
	WASSERTM(actualSize == sizeof(ODSession*), "Incorrect kODSession size");
	
	if (err == noErr)
	{
		err = AEGetParamPtr(replaceFileEvent, kODDestinationFileSpec,
								typeFSS, &returnedType,
								&destFileSpec, sizeof(FSSpec), &actualSize);
		WASSERTM(actualSize == sizeof(FSSpec), "Incorrect DestinationFileSpec size");
	}
	
	if (err == noErr)
	{
		Environment* ev = somGetGlobalEnvironment();
		ParamText(destFileSpec.name, "\p", "\p", "\p");
		err = AEInteractWithUser(kAEDefaultTimeout, NULL, NULL);
		if ((err == noErr) && ODAskUserReplace(ev, session))
		{
			err = AEGetParamPtr(replaceFileEvent, kODSourceFileSpec,
									typeFSS, &returnedType,
									&sourceFileSpec, sizeof(FSSpec), &actualSize);
			if (err == noErr)
			{
				WASSERTM(actualSize == sizeof(FSSpec), "Incorrect kODSourceFileSpec size");
				TempPlatformFile sourceFile = new PlatformFile;
				sourceFile->Specify(&sourceFileSpec);
				TempPlatformFile destFile = new PlatformFile;
				destFile->Specify(&destFileSpec);
				
				destFile->MoveToTrash();
				sourceFile->Move(destFileSpec.parID);
			}
		}
	}

#ifdef ODDebug
	if (err != noErr)
		WARN("Error occured in ReplaceFileAEHandler: %d", err);
#endif

	return err;
}

static void RespecifyToTempFolder(PlatformFile* file)
{
	ODSLong	tempDirID;
	FSSpec	fsSpec = file->GetFileSpec();
	
	THROW_IF_ERROR(FindFolder(fsSpec.vRefNum, kTemporaryFolderType, kCreateFolder,
							&(fsSpec.vRefNum), &tempDirID));
	fsSpec.parID = tempDirID;
	file->Specify(&fsSpec);
	if (file->Exists())
		file->Delete();
}
			
