//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: oddataxfer
//
//   CLASSES: none
//
//   ORIGINS: 82,27,94
//
//
//   (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.14 nt/src/storage/WLinkMgr.cpp, oddataxfer, od96nt, odnt9712d 11/7/96 13:00:49 [ 3/21/97 17:14:07 ]
/*
	File:		LinkMgr.cpp

	Contains:	Implementation for ODLinkManager class.

	Owned by:	Craig Carper

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

	Change History (most recent first):

		<44>	 10/8/95	TJ		Fixes Recomended by Refball
		<43>	 10/4/95	jpa		Added missing ODVolatiles [1285799]
		<42>	 10/3/95	TJ		Changes done by RefBall Team
		<41>	 9/27/95	eeh		1284465: use ClipStringToBytes
		<40>	  9/1/95	CC		1278590: Added RequestLinkAEHandler.
									Call SetStatus and UpdateDependents if link
									cannot be established.
									1190727: GetLinkAEHandler: Update Edition
									file if waiting for save.
		<39>	 8/30/95	EL		1279582: Storage ODVolatile problems.
									1279832: Storage THROW_IF_NULL problems.
		<38>	 8/29/95	DM		1221778, 1276165:  add SuspendResume(),
									ShowLinkUpdateAlert(), and _fSuspended-
									UpdateLinks to let LinkMgr do update
									alerts.
		<37>	 8/26/95	T‚		1274606 FB2: Patching Remarks
		<36>	 8/22/95	eeh		1276821:
									kOpenDocShellSignature->kODShellSignature
		<35>	 8/15/95	CC		1275241: Moved declaration of DraftInfo
									struct into LinkMgr.cpp.
		<34>	 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
		<33>	  8/3/95	RR		#1257260: Collapse B classes. Remove
									somInit methods. Don't call IsInitialized
									or SubclassResponsibility
		<32>	 7/28/95	VL		1270320: Do not create draft info in
									DraftSaved if the draft has not been opened
									yet.
		<31>	 7/25/95	CC		1212338: Created class ODObjectCollection;
									inherits from OrderedCollection but
									overrides ElementsMatch to use
									ODObjectsAreEqual macro.
		<30>	 6/26/95	T‚		1242642 BB:Fix refcounting bugs
		<29>	  6/7/95	CC		1242442: CreateLink: Don't add link to
									kODPropImportedLinkSources draft property.
									GetLinkAEHandler: Don' t add linkSource to
									kODPropExportedLinks draft property.
									Removed local function
									AppendStrongReferenceToDraftProperty.
		<28>	  6/2/95	CC		1255474: AcquireLinkAEHandler restored to
									GetLinkAEHandler
									1255474: kODAcquireLinkEventID restored to
									kODGetLinkEventID
		<27>	 5/26/95	VL		1251403: Multithreading naming support.
		<26>	 5/22/95	CC		1251802: Added TruncateFileName.
		<25>	 4/25/95	CC		1242555: DeleteEditionFiles: $5 entered as
									bug 1242448.
									1242555: CreateLink,AcquireLinkAEHandler: $5
									entered as bug 1242442.
									1242625: GetDraftInfo: Use ODDeleteObject
									instead of delete operator.
		<24>	 4/14/95	T‚		#1235279 BB: InfoUtil & StdTypIO functions
									should take Environment* and SU* when
									possible
		<23>	  3/7/95	CC		1224121 ODPart::CreateLink() and
									ODLinkManager::CreateLink() return
									ODLinkSource object.
		<22>	  3/3/95	CC		1223667 ExportOnSave() and DeleteOnSave
									return previous setting as boolean result.
		<21>	 2/24/95	CC		1153783: Made edition name localizable by
									using ReplaceIntoString.
		<20>	 2/15/95	CC		1220327 InitLinkManager: Call
									InitLinkDialogs to set session global.
									1196831 Use PStrToText; remove static
									function NumToText.
									1220318 BuildErrorString calls
									ReplaceIntoString.
		<19>	  2/1/95	CC		1153347, 1154916, 1213004:
									GetSectionFromEvent returns error rather
									than throwing.
									SectionScrollAEHandler: Alert the user via
									the notification manager.
									Added BuildErrorString() and NumToText().
									Support fNMResponseUPP and fNMRecPtr
									fields.
		<18>	 1/27/95	TJ		VL: some stuff.
		<17>	 1/26/95	VL		#???: Use updated Storage Unit Ref API.
		<16>	 1/19/95	CC		1210935, 1207937 Add DeleteOnSave() method.
									1212315 Use shell's signature for Apple
									event class.
									1191890 - Code review changes.
		<15>	12/22/94	CC		1154916  SectionScrollAEHandler: Let part
									make process frontmost.
									1153780 Implemented ReserveSectionID; fixed
									bug in
									AppendStrongReferenceToDraftProperty.
		<14>	12/20/94	VL		1195012: Make Storage calls be
									marshallable.
		<13>	12/15/94	CC		1197221 Changed call to
									ODPart::CreateLink().
		<12>	 12/8/94	CC		1201906 somUninit: fixed parameters to
									AEGetEventHandler.
		<11>	11/28/94	RR		Fix for Eric - check AE errors
		<10>	 10/4/94	CC		1190068 - Add ODLink publishers and
									ODLinkSource subscribers to draft
									properties.
		 <9>	 9/29/94	RA		1189812: Mods for 68K build.
		 <8>	 9/23/94	VL		1184272: ContainerID is now a sequence of
									octets.
		 <7>	 9/19/94	CC		1187316 - somUninit() must call parent
									method last.
		 <6>	 8/19/94	T‚		#1159233 Remove references to j3di
		 <5>	 8/11/94	CC		Call ODDraft::CreateLinkIterator() and
									ODDraft::CreateLinkSourceIterator() rather
									than ugly cast from ODDraft to CMDraft.
		 <4>	 7/31/94	CC		Changed ODDocument parameters to ODDraft
									since document properties have been
									eliminated.
		 <3>	 7/27/94	CC		Added SOM_CATCH; use
									GetOriginatingProcessID() method of
									ODLinkSpec class.
		 <2>	  7/6/94	CC		Temporary work-around for nil result from
									GetODLinkIterator(),
									GetODLinkSourceIterator(), and
									AcquireDocumentProperties().
		 <1>	 6/21/94	CC		first checked in

		------------------- CC ---- Converted to SOM

		 <4>	  5/9/94	MB		#1162181: Changes necessary to install MMM.
		 <3>	  4/4/94	CC		SectionScrollAEHandler: Call link source's
									ShowSourceContent() method for registered
									sections. (1153347)
		 <2>	 3/28/94	CG		1153547: XMPSessn.h renamed to XMPSessM.h
		 <1>	 3/25/94	CC		first checked in

		------------------- CC ---- Moved from Core to Storage subsystem and
									renamed from LinkMgr.cpp

		 <8>	 3/25/94	eeh		bug #1153053: Changes for PPC nativity.
		 <7>	 3/25/94	VL		#1147173: Draft.h to CMDraft.
		 <6>	 3/17/94	CG		#1151392: Moved kOpenDocShellSignature from
									ContsDef.h to StdDefs.h
		 <5>	 3/15/94	MB		Changes to support SCpp/ASLM builds,
									#1150864.
		 <4>	  3/2/94	CC		CreateLink: Increment ref count of returned
									object (1144936).  Removed DebugStrs
									(1144942).
		 <3>	  3/1/94	CC		Declared local functions static.
		 <2>	 2/15/94	CC		Bug #1142928 - Added document parameter to
									ReserveSectionID.
		<12>	  2/8/94	JA		Minor tweaks for CodeWarrior.
		<11>	  2/8/94	T‚		Throw -> THROW & some code clean up
		<10>	  2/7/94	T‚		more fixes to compile with PPC Headers
		 <9>	  2/4/94	T‚		fixes to compile with PPC Universal headers
		 <8>	 1/21/94	CC		Moved InitEditionPack() call into shell;
									ExportOnSave takes doExport parameter; made
									RemoveAllLinksInCollection and
									DeleteEditionFiles non-class functions.
		 <7>	 1/18/94	CC		Added AnyLinkImported(); removed 'j3di'
									literal.
		 <6>	 1/14/94	CC		Added methods UnsavedExportedLinks(),
									DraftOpened(), DraftSaved(), DraftClosed(),
									and private support routines; added
									DraftInfo type and fDraftInfos field.
		 <5>	12/22/93	CC		CreateLink - dispose targetAddress
									descriptor.
		 <4>	12/22/93	CC		Added DraftOpened(); Dispose Apple event
									descriptors in CreateLink().
		 <3>	12/22/93	CC		NextGlobalID() and callers uses XMPDocument
									instead of XMPDraft.  Handle section write
									events by calling links WriteEditionFile()
									method.  Improved error handling in several
									methods.
		 <2>	12/16/93	CC		Install handlers for Edition Manager
									events.  Moved code from
									XMPDraft::AcquireLink() into CreateLink().
									Calls link objects on receiving AcquireLink and
									Edition Manager events.
		 <1>	 12/8/93	CC		first checked in
		 <2>	 12/3/93	T‚		Stop including XMPError.h, it is included
									as ErrorDef.h inside Except.h
		 <1>	11/15/93	CC		first checked in
	To Do:
	In Progress:
*/

#define VARIABLE_MACROS

#define ODLinkManager_Class_Source
#include <LinkMgr.xih>

#ifndef _EXCEPT_
#include <Except.h>
#endif

#ifndef _ODMEMORY_
#include <ODMemory.h>
#endif

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

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

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

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

#ifndef SOM_Module_OpenDoc_StdDefs_defined
#include <StdDefs.xh>
#endif

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

#ifndef SOM_ODSession_xh
#include <ODSessn.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_ODStorageUnit_xh
#include <StorageU.xh>
#endif

#ifndef SOM_ODLink_xh
#include <Link.xh>
#endif

#ifndef SOM_ODLinkSource_xh
#include <LinkSrc.xh>
#endif

#ifndef SOM_ODLinkSpec_xh
#include <LinkSpec.xh>
#endif

#ifndef SOM_ODLinkIterator_xh
#include <LinkItr.xh>
#endif

#ifndef SOM_ODLinkSourceIterator_xh
#include <LkSrcItr.xh>
#endif

#ifndef _LINKDEFS_
#include <LinkDefs.h>
#endif

#ifndef _LINKDLGS_
#include <LinkDlgs.h>
#endif

#ifndef _ORDCOLL_
#include <OrdColl.h>
#endif

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

#ifndef SOM_Module_OpenDoc_Errors_defined
#include <ErrorDef.xh>
#endif

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

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

#ifndef _REFCTCOL_
#include "RefCtCol.h"
#endif

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

#ifndef _STORUTIL_
#include <StorUtil.h>
#endif

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

#ifdef OD_PAGETUNE_H
#include <ODPagtun.h>
#endif

#ifndef _ODUTILW_
#include "ODUtilW.h"
#endif

#ifndef _OLEDATA_H_
#include "OleData.h"
#endif

#ifndef _OLEXFER_H_
#include "OleXfer.h"
#endif

#ifndef _OLEMGRW_ 
#include "OleMgrW.h"   
#endif   

#ifndef SOM_DocumentManager_xh
#include <DocMgr.xh>
#endif

#pragma segment ODLinkManager

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

const Boolean kNotSysHandler = false;

// Apple event constants
#define kODGetLinkEventID		'gtln'
#define kODRequestLinkEventID	'rqln'
#define keyEditionAlias			'edas'
#define kODLinkSourceKey		'lksr'

// Value type
const  ODValueType  kODULongSequence    	= "OpenDoc:Type:ULongSequence";

const	ODUShort	kODStorageUnitRefLen	= 4;
const	ODUShort	kODULongSize			= 4;

//==============================================================================
// Local Function Prototypes
//==============================================================================
	
ODStatic void RegisterPublishingLinks(Environment *ev, ODDraft* draft);
ODStatic void RegisterSubscribingLinks(Environment *ev, ODDraft* draft);

//==============================================================================
// struct DraftInfo
//==============================================================================

struct DraftInfo
{
	ODDraft*      		draft;
	ODRefCntCollection*	linksToExport;
	ODRefCntCollection*	linksToDelete;
	ODRefCntCollection*	newExportedLinks;
	ODBoolean			linksImported;
};

// ODObjectCollection is replaced by ODObjectOrdColl in RefCtCol.h in Utilities

//==============================================================================
// class ODObjectCollection
//==============================================================================
// 
// class ODObjectCollection : public OrderedCollection
// {
// 	public:
// 		ODObjectCollection() : OrderedCollection()	{}
// 		ODVMethod ~ODObjectCollection()				{}
// 
// 		ODMethod ODBoolean ElementsMatch(ElementType v1,ElementType v2) const;
// };

//------------------------------------------------------------------------------
// ODObjectCollection::ElementsMatch (OVERRIDE)
//------------------------------------------------------------------------------

// ODBoolean ODObjectCollection::ElementsMatch(ElementType v1,ElementType v2) const
// {
// 	Environment* ev = somGetGlobalEnvironment();
// 	return ODObjectsAreEqual(ev, (ODObject*) v1, (ODObject*) v2);
// }

//==============================================================================
// Static functions
//==============================================================================

//==============================================================================
// class ODLinkManager
//==============================================================================

//------------------------------------------------------------------------------
// ODLinkManager::InitLinkManager
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkManagerInitLinkManager(ODLinkManager *somSelf, Environment *ev,
		ODSession* session)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","InitLinkManager");

	SOM_TRY

	/* Moved from somInit. SOM itself sets fields to zero
	_fSuspendedUpdateLinks = (ODRefCntCollection*) kODNULL;
	_fDraftInfos = (OrderedCollection*) kODNULL;
	_fNMResponseUPP = (NMUPP) kODNULL;
	_fNMRecPtr = (NMRecPtr) kODNULL;
	*/
	somSelf->InitObject(ev);

	_fDraftInfos = new OrderedCollection;
	_fSession    = session;

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}


//-------------------------------------------------------------------------------------
// ODLinkManager: ShowLinkUpdateAlert
//-------------------------------------------------------------------------------------

SOM_Scope ODLinkUpdateResult  SOMLINK ODLinkManagerShowLinkUpdateAlert(ODLinkManager *somSelf, Environment *ev,
		ODBaseLinkSource* link)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","ShowLinkUpdateAlert");
    
    ODLinkUpdateResult result = kODLinkUpdateContinue; ODVolatile(result);

    SOM_TRY
	{
		ODWindow* activeWindow = _fSession->GetWindowState(ev)->AcquireActiveWindow(ev);
		result = ( ::ShowLinkUpdateAlert(activeWindow->GetPlatformWindow(ev)) ) ?
			kODLinkUpdateContinue : kODLinkUpdateStop;
		activeWindow->Release(ev);
	}

    SOM_CATCH_ALL
	
    SOM_ENDTRY
	
    return result;
}

//------------------------------------------------------------------------------
// ODLinkManager::UnsavedExportedLinks
//------------------------------------------------------------------------------

SOM_Scope ODBoolean  SOMLINK ODLinkManagerUnsavedExportedLinks(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","UnsavedExportedLinks");

	SOM_TRY
  
	DraftInfo* info = somSelf->GetDraftInfo(ev, draft);

	if ( info != (DraftInfo*) kODNULL ) 
	{
		return info->newExportedLinks->Count() > 0;
	}
	else
		return kODFalse;

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return kODFalse;
}

//------------------------------------------------------------------------------
// ODLinkManager::AnyLinkImported
//------------------------------------------------------------------------------

SOM_Scope ODBoolean  SOMLINK ODLinkManagerAnyLinkImported(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","AnyLinkImported");


	SOM_TRY

	DraftInfo* info = somSelf->GetDraftInfo(ev, draft);

	if ( info != (DraftInfo*) kODNULL ) 
	{
		return info->linksImported;
	}
	else
		return kODFalse;

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return kODFalse;
}

//------------------------------------------------------------------------------
// ODLinkManager::DraftOpened
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkManagerDraftOpened(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","DraftOpened");


	SOM_TRY


	DraftInfo* info = somSelf->GetDraftInfo(ev, draft);
	
	if ( info == (DraftInfo*) kODNULL ) 
	{
		somSelf->NewDraftInfo(ev, draft);
		RegisterSubscribingLinks(ev, draft);
		RegisterPublishingLinks(ev, draft);
	}

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLinkManager::DraftSaved
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkManagerDraftSaved(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","DraftSaved");


	SOM_TRY


	DraftInfo* info = somSelf->GetDraftInfo(ev, draft);
	
	if ( info != (DraftInfo*) kODNULL ) 
	{
        	if ( info->linksToExport != kODNULL )
	        {
		  ODRefCntCollectionIterator iter(info->linksToExport);
		  ODLinkKey key;
	
		  for (ODLink* link = (ODLink*) iter.First();
				iter.IsNotComplete();
				link = (ODLink*) iter.Next() )
		    {
		      if ( link->Lock(ev,0,&key) ) 
			{
				TRY
					link->RefreshDataObject(ev, key);
				CATCH_ALL
				ENDTRY
				link->Unlock(ev, key);
			}
		    }
		}
		// old: RemoveAllLinksInCollection(ev, info->linksToExport);
		info->linksToExport->RemoveAndReleaseAll();
		// rrk 2 april 96 - do we need to do anything in place of "DeleteEditionFiles?" No.
		//		DeleteEditionFiles(ev, info->linksToDelete);
		// old: RemoveAllLinksInCollection(ev, info->linksToDelete);
		info->linksToDelete->RemoveAndReleaseAll();

		// old: RemoveAllLinksInCollection(ev, info->newExportedLinks);
		info->newExportedLinks->RemoveAndReleaseAll();
		
		info->linksImported = kODFalse;
	}
	else 
	{
		WARNMSG_DEBUG(WARN_INDEX(-1),"Draft is not opened yet.");
	}

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLinkManager::DraftClosing
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkManagerDraftClosing(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","DraftClosing");

	SOM_TRY

	DraftInfo* info = somSelf->GetDraftInfo(ev, draft);

	if ( info != (DraftInfo*) kODNULL ) 
	{
		// old: RemoveAllLinksInCollection(ev, info->linksToExport);
		// new: info->linksToExport->RemoveAndReleaseAll();
		ODDeleteObject(info->linksToExport); // calls RemoveAndReleaseAll()

		// old: RemoveAllLinksInCollection(ev, info->linksToDelete);
		// new: info->linksToDelete->RemoveAndReleaseAll();
		ODDeleteObject(info->linksToDelete); // calls RemoveAndReleaseAll()

		// rrk 2 april 96 - do we need to do anything in place of "DeleteEditionFiles?" No.
		//DeleteEditionFiles(ev, info->newExportedLinks);
		// old: RemoveAllLinksInCollection(ev, info->newExportedLinks);
		// new: info->newExportedLinks->RemoveAndReleaseAll();
		ODDeleteObject(info->newExportedLinks); // calls RemoveAndReleaseAll()

		_fDraftInfos->Remove(info);
		delete info;
	}

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLinkManager::ExportOnSave
//------------------------------------------------------------------------------

SOM_Scope ODBoolean  SOMLINK ODLinkManagerExportOnSave(ODLinkManager *somSelf, Environment *ev,
		ODLink* link,
		ODBoolean doExport)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","ExportOnSave");

	ODBoolean wereToExport = kODFalse;

	SOM_TRY

	DraftInfo* info = somSelf->GetDraftInfo(ev, link->GetStorageUnit(ev)->GetDraft(ev));
	if ( info != (DraftInfo*) kODNULL ) 
	{
		wereToExport = info->linksToExport->Contains(link);
		if ( wereToExport && !doExport ) 
		{
			info->linksToExport->RemoveAndRelease(link);
			// link->Release(ev);
		}
		else if ( !wereToExport && doExport ) 
		{
			info->linksToExport->AddLastAndAcquire(link);
			// link->Acquire(ev);
		}
	}

	return wereToExport;

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return kODFalse;
}

//------------------------------------------------------------------------------
// ODLinkManager::DeleteOnSave
//------------------------------------------------------------------------------

SOM_Scope ODBoolean  SOMLINK ODLinkManagerDeleteOnSave(ODLinkManager *somSelf, Environment *ev,
		ODLink* link,
		ODBoolean doDelete)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","DeleteOnSave");

	ODBoolean wereToDelete = kODFalse;


	SOM_TRY

	DraftInfo* info = somSelf->GetDraftInfo(ev, link->GetStorageUnit(ev)->GetDraft(ev));
	if ( info != (DraftInfo*) kODNULL ) 
	{
		wereToDelete = info->linksToDelete->Contains(link);
		if ( wereToDelete && !doDelete ) 
		{
			info->linksToDelete->RemoveAndRelease(link);
			// link->Release(ev);
		}
		else if ( !wereToDelete && doDelete )
		{
			info->linksToDelete->AddLastAndAcquire(link);
			// link->Acquire(ev);
		}
	}

	return wereToDelete;

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return kODFalse;
}

//------------------------------------------------------------------------------
// ODLinkManager::CreateLink
//------------------------------------------------------------------------------

SOM_Scope ODLinkSource*  SOMLINK ODLinkManagerCreateLink(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft,
		ODLinkSpec* linkSpec)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","CreateLink");

	ODLinkKey 		  key;
	IMoniker		  *pmkFull;
	ODLinkSource	  *linkSource;
		
	SOM_TRY
	  if (linkSpec)
	    {
	      /* Get the moniker from the link specification
	       */
	      pmkFull	= (LPMONIKER)linkSpec->GetMoniker(ev);
	      if (pmkFull)
		{
		  /* Create a link source object in this process
		   */
		  linkSource = draft->CreateLinkSource(ev,(ODPart*) kODNULL);
		  if (linkSource->Lock(ev,0,&key))
		    {
		      TRY
			linkSource->UseMoniker(ev,pmkFull,key);
		      CATCH_ALL
			linkSource->Unlock(ev,key);
		      RERAISE;
		      ENDTRY
			linkSource->Unlock(ev,key);
		      
		      /* Return the link source object
		       */
		      if (linkSource)
			linkSource->Acquire(ev);
		      return linkSource;
		    }
		}
	    }

	SOM_CATCH_ALL
	
		ODSafeReleaseObject(linkSource);

	SOM_ENDTRY
	return NULL;

}

//------------------------------------------------------------------------------
// ODLinkManager::NewDraftInfo
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkManagerNewDraftInfo(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","NewDraftInfo");

	SOM_TRY

	// Create a new info structure for this draft
	DraftInfo* info = new DraftInfo;

	info->draft = draft;
	info->linksToExport = new ODRefCntCollection(ev);
	info->linksToDelete = new ODRefCntCollection(ev);
	info->newExportedLinks = new ODRefCntCollection(ev);
	info->linksImported = kODFalse;
	_fDraftInfos->AddLast(info);

	SOM_CATCH_ALL

	SOM_ENDTRY
	  return;
}

//------------------------------------------------------------------------------
// ODLinkManager::GetDraftInfo
//------------------------------------------------------------------------------

SOM_Scope DraftInfo*  SOMLINK ODLinkManagerGetDraftInfo(ODLinkManager *somSelf, Environment *ev,
		ODDraft* draft)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","GetDraftInfo");

	OrderedCollectionIterator* iter = kODNULL; ODVolatile(iter);
	
	DraftInfo* result = (DraftInfo*) kODNULL;
	
	if ( draft && _fDraftInfos )
	{
		TRY
			iter = _fDraftInfos->CreateIterator();

			for (DraftInfo* info = (DraftInfo*) iter->First();
					iter->IsNotComplete();
					info = (DraftInfo*) iter->Next() )
			{
				if ( info && draft->IsEqualTo(ev, info->draft) ) 
				{
					result = info;
					break;
				}
			}
		CATCH_ALL
		ENDTRY

		ODDeleteObject(iter);
	}

	return result;
}

//------------------------------------------------------------------------------
// ODLinkManager::DeleteDraftInfos
//------------------------------------------------------------------------------

// SOM_Scope void  SOMLINK ODLinkManagerDeleteDraftInfos(ODLinkManager *somSelf, Environment *ev)
// {
//     ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
//     ODLinkManagerMethodDebug("ODLinkManager","DeleteDraftInfos");
// 
// 	SOM_CATCH return;
// 	
// 	if (_fDraftInfos != (OrderedCollection*) kODNULL)
// 	{
// 		DraftInfo* info;
// 		while ((info = (DraftInfo*) _fDraftInfos->First()) != (DraftInfo*) kODNULL)
// 		{
// 			ODDeleteObject(info->linksToExport);
// 			ODDeleteObject(info->linksToDelete);
// 			ODDeleteObject(info->newExportedLinks);
// 			_fDraftInfos->RemoveFirst();
// 			delete info;
// 		}
// 		ODDeleteObject(_fDraftInfos);
// 	}
// }

//------------------------------------------------------------------------------
// ODLinkManager::somUninit
//------------------------------------------------------------------------------

SOM_Scope void  SOMLINK ODLinkManagersomUninit(ODLinkManager *somSelf)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
    ODLinkManagerMethodDebug("ODLinkManager","somUninit");

	// somSelf->DeleteDraftInfos(ev);
	// It is incorrect to call methods on somSelf inside somUninit, 
	// a subclass may have already been somUninited.  See OpenDoc Building Code for details.
	// Instead the implementation of DeleteDraftInfos has been copied here.
	
	// BEGIN copy of DeleteDraftInfos implementation
	if (_fDraftInfos != (OrderedCollection*) kODNULL )
	{
		Environment* ev = somGetGlobalEnvironment();
		DraftInfo* info;
		while ((info = (DraftInfo*) _fDraftInfos->First()) != (DraftInfo*) kODNULL)
		{
			ODDeleteObject(info->linksToExport);
			ODDeleteObject(info->linksToDelete);
			ODDeleteObject(info->newExportedLinks);
			_fDraftInfos->RemoveFirst();
			delete info;
		}
		ODDeleteObject(_fDraftInfos);
	}
	// END copy of DeleteDraftInfos implementation

	if ( _fSuspendedUpdateLinks != (ODRefCntCollection*) kODNULL ) 
	{
		// _fSuspendedUpdateLinks->RemoveAndReleaseAll();
		ODDeleteObject(_fSuspendedUpdateLinks);
	}

    parent_somUninit(somSelf);
}

//------------------------------------------------------------------------------
// RegisterSubscribingLinks
//------------------------------------------------------------------------------

ODStatic void RegisterSubscribingLinks(Environment *ev, ODDraft* draft)
{
	// Internalize all link source objects; each link subscribing to an edition
	// file will register with the edition manager.

	ODLinkSourceIterator* iter = kODNULL;

	SOM_TRY

	iter = draft->CreateLinkSourceIterator(ev);

	for (ODLinkSource* linkSource = iter->First(ev);
			iter->IsNotComplete(ev);
			linkSource = iter->Next(ev) )
	{
		linkSource->Release(ev);
	}

	delete iter;

	SOM_CATCH_ALL
          {
	    ODDeleteObject(iter);
	  }
	SOM_ENDTRY
	    return;

}

//------------------------------------------------------------------------------
// RegisterPublishingLinks
//------------------------------------------------------------------------------
ODStatic void RegisterPublishingLinks(Environment *ev, ODDraft* draft)
{
	// Internalize all link objects; each link publishing an edition file will 
	// register with the edition manager.

	ODLinkIterator* iter = kODNULL;

	SOM_TRY

	iter = draft->CreateLinkIterator(ev);

	for (ODLink* link = iter->First(ev);
			iter->IsNotComplete(ev);
			link = iter->Next(ev) )
	{
		link->Release(ev);
	}

	delete iter;

	SOM_CATCH_ALL
          {
	    ODDeleteObject(iter);
	  }
	SOM_ENDTRY
	    return;
}

/* METHOD: FetchLink
 *
 * DESCRIPTION:
 *   Bind the OLE item moniker to the appropriate link source within this
 *   draft.
 */
SOM_Scope ODLink* SOMLINK ODLinkManagerFetchLink(
	ODLinkManager	*somSelf,
	Environment		*ev,
	ODDraft			*draft,
	char		    *pszItemName)
{
    ODLinkManagerData *somThis = ODLinkManagerGetData(somSelf);
	ODLink			  *link	   = NULL;

	/* LATER: Find the link by using the link enumerator, in case one already
	 * exists.
	 */

	/* If the link wasn't located then bind the given link using its item name	
	 */
	// rrk 27 aug 96
#ifdef ODDebugClipboard
        PRINT("RRK: ODLinkManager FetchLink; item name is %s.\n",pszItemName);
#endif
	ODLinkIterator* iter = kODNULL;

	char* currentName = ODOLEManager::GetShell()->GetActiveDocumentManager(ev)->GetFileName(ev);
#ifdef ODDebugClipboard
        PRINT("RRK: ODLinkManager FetchLink; document name is %s.\n", currentName);
#endif
	iter = draft->CreateLinkIterator(ev);
        char* tempJunk;
	int i = 0;
#ifdef ODDebugClipboard
        PRINT("RRK: ODLinkManager FetchLink; entering iterator.\n");
#endif
	for (ODLink* tempLink = iter->First(ev);
			iter->IsNotComplete(ev);
			tempLink = iter->Next(ev) )
	{
	        tempJunk = tempLink->GetItemName(ev);
#ifdef ODDebugClipboard
                PRINT("RRK: ODLinkManager FetchLink; in iterator, item name for link %d is %s.\n", i++, tempJunk);
#endif
		if ((tempJunk) && !strncmp(tempJunk, pszItemName,strlen(pszItemName))) {
		  link = tempLink;
		  break;
		}
	}

#ifdef ODDebugClipboard
        PRINT("RRK: ODLinkManager FetchLink; link is %x.\n", link);
#endif
	delete iter;
	if (!link)
	{
		ODLinkSpec	*ls = new ODLinkSpec;
		ls->UseItemName(ev,pszItemName);
		TRY
			link = draft->AcquireLink(ev,(ODStorageUnitID)kODNULL, ls);
		CATCH_ALL
		ENDTRY

		/* Now register as a dependent of the link
		 */
		if (link)
		{
			link->UseItemName(ev,pszItemName);
			// rrk 6 jun 96 This line blows up because the link really expects ODPart*, not NULL!
			//              Anyway, the "design" says this call may not be needed?
			//			link->RegisterDependent(ev,NULL,kODUnknownChange/* LATER? */);
		}

		delete ls;
	}

	return	link;
}
