// PurgeDialog.cpp  (Plug-Ins\ExternalSrc\Shipping\Classic\Purge)
//     UNKNOWN_PROJECT file
//
// Copyright 2000 Diehl Graphsoft, Inc.
// All Rights Reserved.
//
// Layout Manager implementation of the Purge Objects Dialog
//
// Started by Sean Flaherty on 4/21/00.
//
// SourceSafe information for this revision:
//    $Revision: 2 $
//    $Date: 7/20/00 12:24 PM $
//    $Author: Sean $


#include <VWSDK.h>
#include "TArray.h"
#include "PurgeDialog.h"
#include <iostream>

DEFINE_NOPOP_TLARGEARRAY(long);
DEFINE_NOPOP_TARRAY(Handle);

const short			kWarningStringsID	= 11000;
const OSType kSketchStyleContainer = 'SKST';	// Hidden format container used for storing sketch style resources

const short kDialogItemStrsID	= 11002;
const short kDialogHelpStrsID	= 11001;
const short kOKID				= 1;
const short kCancelID			= 2;
const short kClassesID			= 3;
const short kGradientsID		= 4;
const short kHatchesID			= 5;
const short kImagesID			= 6;
const short kLayersID			= 7;
const short kRecordsID			= 8;
const short kRWBackgroundsID	= 9;
const short kSketchStylesID		= 10;
const short kSymbolsID			= 11;
const short kSymbolFoldersID	= 12;
const short kTexturesID			= 13;
const short kWallStylesID		= 14;
const short kDialogNameID		= 15;
const short kAllID				= 16;
const short kNoneID				= 17;

Str255 settingVal;

// prototypes to avoid warnings - these functions cannot be static
extern "C" void DoDeleteUnusedLayers(Handle h, CallBackPtr cbp, void*);
extern "C" void DoCreateRecordFormatTable(Handle h, CallBackPtr cbp, void* voidEnv);
extern "C" void DoCreateSymbolTable(Handle h, CallBackPtr cbp, void* voidEnv);
extern "C" void DoCreateClassTable(Handle h, CallBackPtr cbp, void* voidEnv);
extern "C" void DoCreateHatch_Gradient_ImageFillTable(Handle h, CallBackPtr cbp, void* voidEnv);
extern "C" void DoCreateTextureTable(Handle h, CallBackPtr cbp, void* voidEnv);
extern "C" void DoCreateRWBackgroundTable(Handle h, CallBackPtr cbp, void* voidEnv);
extern "C" void DoCreateSketchStyleTable(Handle h, CallBackPtr cbp, void *voidEnv);
extern "C" void DoCreateWallStyleTable(Handle h, CallBackPtr cbp, void *voidEnv);

struct PurgeEnvType	{
	PurgeOptionsType	dialogPurgeOptions;
	bool				texturesEnabled;
};

inline Str255& Num2Str(double d)
{
	GS_DoubleToString(gCBP, 1, 1, 0, d, settingVal);
	return settingVal;
}

inline void GetFromSavedSetting(Boolean &b, const PStr255 &cat, const PStr255 &setting)
{
	struct SavedSettingStruct		savedSettingStruct;
	b = false;

	savedSettingStruct.sCatelog = cat;
	savedSettingStruct.sItem = setting;
	
	double doubleVal = 0.0;
	if (GS_Kludge(gCBP, kGetSavedSettingKludge, &savedSettingStruct, NULL))
	{
		GS_StringToDouble(gCBP, nsFixDecimal, savedSettingStruct.sValue, doubleVal);
		b = (doubleVal == 1.0) ? true : false;
	}
}

inline void SetFromSavedSetting(Boolean bCheck, const PStr255 &cat, const PStr255 &setting)
{
	struct SavedSettingStruct		savedSettingStruct;

	savedSettingStruct.sCatelog = cat;
	savedSettingStruct.sItem = setting;
	
	if (bCheck)
	{
		savedSettingStruct.sValue = Num2Str(1);
	}
	else
	{
		savedSettingStruct.sValue =Num2Str(0);
	}

	GS_Kludge(gCBP, kSetSavedSettingKludge, &savedSettingStruct, NULL);
}

extern "C" void DoDeleteUnusedLayers(Handle h, CallBackPtr cbp, void*)
	//If a layer has no objects in it, delete it
{
	GSCalledRoutineSetup (cbp);

	if (h && GS_GetObjectType(cbp, h) == layerNode && GS_GetObjectType(cbp, GS_FirstMemberObj(cbp, h)) == termNode) { 
		if (h != GS_GetCurrentLayer(cbp)) {
			GS_DeleteObject(cbp, h, false);   // false indicates that this object should not be kept around for undo purposes
			GS_NotifyLayerChange(cbp);
		}
		else
		{
			// B064503: Give user option to not display this warning again [ZHP 2/22/08]
			const TXString emptyStr = "";
			const TXString category = "PurgeUnusedObjects", item = "CannotPurgeActiveLayer";
			Str255 message = "";
			GS_GetResourceString(cbp, kWarningStringsID, 2, message);

			GS_AlertInform(cbp, message, emptyStr, false, category, item, emptyStr);
			//GS_PostNoteAlert(cbp, kWarningStringsID, 2);
		}
	}

#if BUG
	if (!h)
		DMSG((kBruce, "h is nil!!!\n"));
#endif
}

extern "C" void DoCreateRecordFormatTable(Handle h, CallBackPtr cbp, void* voidEnv)
	//
	// Fill RecordFormatTable with the Record Format Definitions of the
	// record instances on auxlist of objects found by ForEachObject.
	// JAK 4/12/00 Fix bug. Add loop to look at all recordNodes on the object's auxlist.
	//
{
	GSCalledRoutineSetup (cbp);

	THandleArray *recFormatTable = (THandleArray*)voidEnv;
	Boolean			found;
	Handle			recFormat;
	Handle			recHdle;
	
	if (h) {
		recHdle = GS_FindAuxObject(cbp, h, recordNode);
		while (recHdle) {
			found = false;
			recFormat = GS_GetDefinition(cbp, recHdle);
			if (recFormat) {
				for (short i = 0; i < recFormatTable->NumItems(); i++) 
					if (recFormat == (*recFormatTable)[i])
						found = true;
				if (!found) {
					DMSG((kBruce, "Record instance found and added to recFormatTable!!\n"));
					recFormatTable->PushData(recFormat);
				}
				else
					DMSG((kBruce, "Record instance found and not added to recFormatTable!!\n"));
			}
			// Step to next recordNode object in the auxlist.
			recHdle = GS_NextObject(cbp, recHdle);					// step to next object
			recHdle = GS_NextAuxObject(cbp, recHdle, recordNode);	// keep stepping till you get a recordNode.
		}
	}
}

extern "C" void DoCreateHatch_Gradient_ImageFillTable(Handle h, CallBackPtr cbp, void* voidEnv)
	//Fill Hatch_Gradient_ImageFillTable with the Hatch, Gradient & Image Fill
	//definitions of the instances found by ForEachObject
{
	GSCalledRoutineSetup (cbp);

	THandleArray *hatchGradientImageFillTable = (THandleArray*)voidEnv;
	Boolean			found;
	
	if (h) {
		InternalIndex fill = GS_GetFillPat(cbp, h);
		if (fill < 0) {
			InternalName name;
			InternalIndex id = -1 * fill;
			GS_InternalIndexToNameN(cbp, id, name);
			Handle def = GS_GetNamedObject(cbp, name);
			found = false;
			for (short i = 0; i < hatchGradientImageFillTable->NumItems(); i++) {
				if (def == (*hatchGradientImageFillTable)[i])
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Hatch, gradient or image fill %d not found and added to table!!!\n", id));
				hatchGradientImageFillTable->PushData(def);
			}
			else
				DMSG((kBruce, "Hatch, gradient or image fill %d found but already exists in table!!!\n", id));
		}
		// If the object is a viewport node, then go through each class and see if the viewport has an override
		// for that class.  If it does, see if the class override uses a hatch gradient or image file for its
		// fill style
		if (GS_GetObjectType(cbp, h) == kViewportNode) {
			InternalIndex i;
			InternalIndex maxID = GS_MaxClassID(cbp);
			for (i = 0; i <= maxID; i++) {
				if (GS_ValidClass(cbp, i)) {
					if (GS_VPClassHasOverride(cbp, h, i)) {
						InternalIndex classOverrideFill = GS_GetVPClassFillStyle(cbp, h, i);
						if (classOverrideFill < 0) {
							InternalName fillName;
							GS_InternalIndexToNameN(cbp, (-1 * classOverrideFill), fillName);
							Handle fillDef = GS_GetNamedObject(cbp, fillName);
							found = false;
							for (short j = 0; j < hatchGradientImageFillTable->NumItems(); j++) {
								if (fillDef == (*hatchGradientImageFillTable)[j])
									found = true;
							}
							if (!found) {
								DMSG((kBruce, "Hatch, gradient or image fill %d not found and added to table!!!\n", (-1*classOverrideFill)));
								hatchGradientImageFillTable->PushData(fillDef);
							}
							else
								DMSG((kBruce, "Hatch, gradient or image fill %d found but already exists in table!!!\n", (-1*classOverrideFill)));
						}
					}
				}
			}			
		}
	}
}


// added by Drew Stanton 9/29/04	
extern "C" void DoCreateSketchStyleTable(Handle h, CallBackPtr cbp, void* voidEnv)
	// Fill SketchStyleTable with the Sketch Style definitions of the
	// instances found by ForEachObject
{
	GSCalledRoutineSetup (cbp);

	TLargelongArray *sketchStyleTable = (TLargelongArray*)voidEnv;
	TVariableBlock	getValue;
	InternalIndex	sketchStyleSysName;
	Boolean			found;
	
	if (h) {
		found = false;
		
		// necessary in order to get the sketch value of each object
		GS_GetObjectVariable(cbp, h, ovSketchStyle, getValue);
		getValue.GetSint32(sketchStyleSysName);
		
		// looking through table to see if sketch type is already in there
		for (long i = 0; i < (long)sketchStyleTable->NumItems(); i++) {
			if (sketchStyleSysName == (*sketchStyleTable)[i] || sketchStyleSysName == 1)
				found = true;
		}
		
		if (!found) 
			sketchStyleTable->PushData(sketchStyleSysName); // add to the table
		else
			; // do nothing at all
	}
}


void CheckTexture(CallBackPtr cbp, Handle h, short partID, THandleArray* textureTable)
// Adds partID texture to table if not added already
{
	InternalIndex textureRef = GS_GetTextureRef(cbp, h, partID, true);

	if (textureRef > 0) {
		InternalName textureName;
		GS_InternalIndexToNameN(cbp, textureRef, textureName);

		Handle textureDef = GS_GetNamedObject(cbp, textureName);
		
		Boolean found = false;
		for (short i = 0; i < textureTable->NumItems(); i++) {
			if (textureDef == (*textureTable)[i])
				found = true;
		}
		
		if (!found)
			textureTable->PushData(textureDef);
	}
}


extern "C" void DoCreateTextureTable(Handle h, CallBackPtr cbp, void* voidEnv)
	//Fill TextureTable with the texture definitions of the
	//texture instances found by ForEachObject
{
	GSCalledRoutineSetup (cbp);

	THandleArray *textureTable = (THandleArray*)voidEnv;
	Boolean		found;
	short		j, k;
	
	if (h) {

		// We don't check old texture parts anymore because a side effect of looking for old parts is that
		// texture space nodes are created causing unnecessary file bloat B073680.  -DLD 2/27/2009

		CheckTexture(cbp, h, kTexturePart_Overall, textureTable);
		
		short objType = GS_GetObjectType(cbp, h);

		if (objType == kExtrudeNode || objType == kSweepNode) {
			CheckTexture(cbp, h, kTexturePart_ExtrudeSweep_Top, textureTable);
			CheckTexture(cbp, h, kTexturePart_ExtrudeSweep_Bottom, textureTable);
			CheckTexture(cbp, h, kTexturePart_ExtrudeSweep_Sides, textureTable);
		}
		else if (objType == kWallNode || objType == kRoundWallNode) {
			CheckTexture(cbp, h, kTexturePart_Wall_Left, textureTable);
			CheckTexture(cbp, h, kTexturePart_Wall_Right, textureTable);
			CheckTexture(cbp, h, kTexturePart_Wall_StartCap, textureTable);
			CheckTexture(cbp, h, kTexturePart_Wall_EndCap, textureTable);
			CheckTexture(cbp, h, kTexturePart_Wall_Top, textureTable);
			CheckTexture(cbp, h, kTexturePart_Wall_Bottom, textureTable);
			CheckTexture(cbp, h, kTexturePart_Wall_Holes, textureTable);
		}
		else if (objType == kSlabNode) {
			CheckTexture(cbp, h, kTexturePart_Slab_Top, textureTable);
			CheckTexture(cbp, h, kTexturePart_Slab_Bottom, textureTable);
			CheckTexture(cbp, h, kTexturePart_Slab_Sides, textureTable);
		}
		else if (objType == kRoofContainerNode) {
			CheckTexture(cbp, h, kTexturePart_Roof_Top, textureTable);
			CheckTexture(cbp, h, kTexturePart_Roof_Bottom, textureTable);
			CheckTexture(cbp, h, kTexturePart_Roof_Sides, textureTable);
			CheckTexture(cbp, h, kTexturePart_Roof_Walls, textureTable);
			CheckTexture(cbp, h, kTexturePart_Roof_Fascia, textureTable);
			CheckTexture(cbp, h, kTexturePart_Roof_Attic, textureTable);
			CheckTexture(cbp, h, kTexturePart_Roof_Soffit, textureTable);
		}
		
		// If the object is a viewport node, then go through each class and see if the viewport has an override
		// for that class.  If it does, see if the class override uses any textures
		if (GS_GetObjectType(cbp, h) == kViewportNode) {
			InternalName textureName;
			InternalIndex index;
			InternalIndex maxID = GS_MaxClassID(cbp);
			for (index = 0; index <= maxID; index++) {
				if (GS_ValidClass(cbp, index)) {
					if (GS_VPClassHasOverride(cbp, h, index)) {
						InternalIndex classTexture[7];
						classTexture[0] = GS_GetVPClassGenTexture(cbp, h, index);
						GS_GetVPClassRoofTextures(cbp, h, index, classTexture[1], classTexture[2], classTexture[3]);
						GS_GetVPClassWallTextures(cbp, h, index, classTexture[4], classTexture[5], classTexture[6]);
						for (j = 0; j < 7; j++)
							if (classTexture[j] > 0) {
								GS_InternalIndexToNameN(cbp, classTexture[j], textureName);
								Handle textureDef = GS_GetNamedObject(cbp, textureName);
								found = false;
								for (k = 0; k < textureTable->NumItems(); k++) {
									if (textureDef == (*textureTable)[k])
										found = true;
								}
								
								if (!found)
									textureTable->PushData(textureDef);
							}
					}
				}
			}			
		}
	}
}

extern "C" void DoCreateSymbolTable(Handle h, CallBackPtr cbp, void* voidEnv)
	//Fill SymTable with the Symbol Instances found by ForEachObject
{
	GSCalledRoutineSetup (cbp);

	THandleArray *symbolTable = (THandleArray*)voidEnv;
	Handle			symbolDef;
	Boolean			found;
	
	if (h) {
		if (GS_GetObjectType(cbp, h) == symNode) {
			found = false;
			symbolDef = GS_GetDefinition(cbp, h);
			for (short i = 0; i < symbolTable->NumItems(); i++) {
				if (symbolDef == (*symbolTable)[i])	
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Symbol instance not found and added to symTable!!!\n"));
				symbolTable->PushData(symbolDef);
			}
			else
				DMSG((kBruce, "Symbol instance found and not added to symbolTable!!!\n"));
		}
		else if (GS_GetObjectType(cbp, h) == kRoofContainerNode) {
			InternalIndex symName;
			short edgeIndex;
			WorldCoord cornerOffset, perpOffset;
			short numAdorners = GS_GetNumRoofElements(cbp, h);
			for (short i = 0; i < numAdorners; i++) {
				if (GS_GetSkylight(cbp, h, i, edgeIndex, cornerOffset, perpOffset, symName)) {
					symbolDef = GS_InternalIndexToHandle(cbp, symName);
					if (symbolDef != nil) {
						found = false;
						for (short j = 0; j < symbolTable->NumItems(); j++) {
							if (symbolDef == (*symbolTable)[j])
								found = true;
						}
						if (!found) {
							DMSG((kBruce, "Symbol instance not found and added to symTable!!!\n"));
							symbolTable->PushData(symbolDef);
						}
						else
							DMSG((kBruce, "Symbol instance found and not added to symbolTable!!!\n"));
					}
				}
			}
		}
	}
}

extern "C" void DoCreateClassTable(Handle h, CallBackPtr cbp, void* voidEnv)
	//Fill ClassTable with the Class IDs of each object found by ForEachObject
{
	GSCalledRoutineSetup (cbp);

	TLargelongArray *classTable = (TLargelongArray*)voidEnv;
	InternalIndex	classID;
	Boolean			found;
	
	if (h) {
		found = false;
		classID = GS_GetObjectClass(cbp, h);
		for (InternalIndex i = 0; i < (long)classTable->NumItems(); i++) {
			if (classID == (*classTable)[i])
				found = true;
		}
		if (!found) {
			DMSG((kBruce, "Class %d found and added to classTable!!!\n", classID));
			classTable->PushData(classID);
		}
		else
			DMSG((kBruce, "Class %d found but already exists in classTable!!!\n", classID));

		if (GS_GetObjectType(cbp, h) == kViewportNode) {  // add section vp referenced classes
			TVariableBlock	getVal1, getVal2, getVal3, getVal4;
			GS_GetObjectVariable(cbp, h, ovSectionVP2DAttributeClass, getVal1);
			GS_GetObjectVariable(cbp, h, ovSectionVP2DOtherAttribClass, getVal2);
			GS_GetObjectVariable(cbp, h, ovSectionVP3DFillStyleClass, getVal3);
			GS_GetObjectVariable(cbp, h, ovSectionVP3DLineStyleClass, getVal4);


			found = false;
			getVal1.GetSint32(classID);
			for (InternalIndex i = 0; i < (long)classTable->NumItems(); i++) {
				if (classID == (*classTable)[i])
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Class %d found and added to classTable!!!\n", classID));
				classTable->PushData(classID);
			}
			else
				DMSG((kBruce, "Class %d found but already exists in classTable!!!\n", classID));


			found = false;
			getVal2.GetSint32(classID);
			for (InternalIndex i = 0; i < (long)classTable->NumItems(); i++) {
				if (classID == (*classTable)[i])
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Class %d found and added to classTable!!!\n", classID));
				classTable->PushData(classID);
			}
			else
				DMSG((kBruce, "Class %d found but already exists in classTable!!!\n", classID));

			found = false;
			getVal3.GetSint32(classID);
			for (InternalIndex i = 0; i < (long)classTable->NumItems(); i++) {
				if (classID == (*classTable)[i])
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Class %d found and added to classTable!!!\n", classID));
				classTable->PushData(classID);
			}
			else
				DMSG((kBruce, "Class %d found but already exists in classTable!!!\n", classID));

			found = false;
			getVal4.GetSint32(classID);
			for (InternalIndex i = 0; i < (long)classTable->NumItems(); i++) {
				if (classID == (*classTable)[i])
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Class %d found and added to classTable!!!\n", classID));
				classTable->PushData(classID);
			}
			else
				DMSG((kBruce, "Class %d found but already exists in classTable!!!\n", classID));
		}
	}
}

extern "C" void DoCreateRWBackgroundTable(Handle h, CallBackPtr cbp, void* voidEnv)
// Fill RenderWorks Background table with the sysnames of each one found by ForEachLayer
{
	GSCalledRoutineSetup (cbp);

	TLargelongArray *rwBackgroundTable = (TLargelongArray*)voidEnv;
	TVariableBlock	getVal, getAnotherVal;
	InternalIndex	rwBackSysName;
	Boolean			found;

	if (h) {
		found = false;

		if (GS_GetObjectType(cbp, h) == kViewportNode) {
			GS_GetObjectVariable(cbp, h, ovViewportRenderBackground, getVal);
			GS_GetObjectVariable(cbp, h, ovViewportHDRIBackground, getAnotherVal);
		}
		else if (GS_GetObjectType(cbp, h) == kLayerNode) {
			GS_GetObjectVariable(cbp, h, ovLayerRWBackground, getVal);
			GS_GetObjectVariable(cbp, h, ovLayerHDRIBackground, getAnotherVal);
		}
		else
			return;

		getVal.GetSint32(rwBackSysName);
		for (long i = 0; i < (long)rwBackgroundTable->NumItems(); i++) {
			if (rwBackSysName == (*rwBackgroundTable)[i])
				found = true;
		}
		if (! found) {
			DMSG((kBruce, "RW Background %d found and added to table!!!\n", rwBackSysName));
			rwBackgroundTable->PushData(rwBackSysName);
		}
		else
			DMSG((kBruce, "RW Background %d found and added to table!!!\n", rwBackSysName));

		found = false;
		getAnotherVal.GetSint32(rwBackSysName);
		for (long i = 0; i < (long)rwBackgroundTable->NumItems(); i++) {
			if (rwBackSysName == (*rwBackgroundTable)[i])
				found = true;
		}
		if (! found) {
			DMSG((kBruce, "RW Background %d found and added to table!!!\n", rwBackSysName));
			rwBackgroundTable->PushData(rwBackSysName);
		}
		else
			DMSG((kBruce, "RW Background %d found and added to table!!!\n", rwBackSysName));
	}
}

extern "C" void DoCreateWallStyleTable(Handle h, CallBackPtr cbp, void* voidEnv)
// Fill WallStyleTable with the Wall Styles of the walls and round walls found by ForEachObject
{
	GSCalledRoutineSetup (cbp);

	THandleArray *wallStyleTable = (THandleArray*)voidEnv;
	Boolean			found;
	
	if (h) {
		InternalIndex wallStyle = 0;
		GS_GetWallStyle(cbp, h, wallStyle);
		if (wallStyle > 0) {
			InternalName name;
			GS_InternalIndexToNameN(cbp, wallStyle, name);
			Handle def = GS_GetNamedObject(cbp, name);
			found = false;
			for (short i = 0; i < wallStyleTable->NumItems(); i++) {
				if (def == (*wallStyleTable)[i])
					found = true;
			}
			if (!found) {
				DMSG((kBruce, "Wall Style %d not found and added to table!!!\n", wallStyle));
				wallStyleTable->PushData(def);
			}
			else
				DMSG((kBruce, "Wall Style %d found but already exists in table!!!\n", wallStyle));
		}
	}
}

static bool FoundInTable(Handle h, THandleArray* array)
// Created this function because its algorithm was used in almost every
// routine in this file.  -DLD
{
	bool found = false;

	if (array) {
		for (short i = 0; i < array->NumItems() && !found; i++) {

			if (h == (*array)[i])
				found = true;
		}
	}

	return found;
}

static bool FoundInTable(long l, TLargelongArray* array)
// Created this function because its algorithm was used in almost every
// routine in this file!  -DLD
{
	bool found = false;

	if (array) {
		for (long i = 0; i < (long)array->NumItems() && !found; i++) {

			if (l == (*array)[i])
				found = true;
		}
	}

	return found;
}

static void DoDeleteUnusedRWBackgrounds(CallBackPtr cbp, TLargelongArray *rwBackgroundTable)
	//Search the classTable for each class ID found
	//here and delete those that are not in the table
{
	InternalName	rwBackName;
	InternalIndex	rwBackIndex;

	
	Handle dwgHdr = GS_GetDrawingHeader(cbp);
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kRenderBackgroundNode) {

				GS_GetObjectName(cbp, dataObj, rwBackName);
				if (GS_NameToInternalIndexN(cbp, rwBackName, rwBackIndex)) {
					
					if (!FoundInTable(rwBackIndex, rwBackgroundTable)) {
						DMSG((kBruce, "RW Background %s not found and deleted!!!\n", rwBackName));
						GS_DeleteObject(cbp, dataObj, false);
					}
					else
						DMSG((kBruce, "Class found and not deleted!!!\n"));
				}
			}
			dataObj = nextObj;
		}
	}
}

static int DeleteUnusedSymbolDefs(CallBackPtr cbp, Handle symbolLibHdr, THandleArray *symbolTable)
	//Search the symbolTable for each Symbol Definition found
	//here and delete those that are not in the table
{
	int				numObjectsDeleted = 0;
	Handle			firstMemObj;
	Handle			nextObj;

	firstMemObj = GS_FirstMemberObj(cbp, symbolLibHdr);
	if (firstMemObj) {
		do {
			nextObj = GS_NextObject(cbp, firstMemObj);

			if (GS_GetObjectType(cbp, firstMemObj) == symDefNode) {

				if (!FoundInTable(firstMemObj, symbolTable)) {
					DMSG((kBruce, "symDefNode found and deleted!!!\n"));
					GS_DeleteObject(cbp, firstMemObj, false);   // false indicates that this object should not be kept around for undo purposes
					numObjectsDeleted++;
				}
				else
					DMSG((kBruce, "symDefNode found and not deleted!!!\n"));
			}
			else if (firstMemObj && GS_GetObjectType(cbp, firstMemObj) == kFolderNode) {
				DMSG((kBruce, "Recursive Call\n"));
				numObjectsDeleted += DeleteUnusedSymbolDefs(cbp, firstMemObj, symbolTable);
			}
			else if (firstMemObj && GS_GetObjectType(cbp, firstMemObj) == termNode) {
				break;
			}
			firstMemObj = nextObj;
		} while (nextObj != nil);
	}

	return numObjectsDeleted;	// return the number of symbols removed.
}


static void DeleteAllUnusedSymbolDefs(CallBackPtr cbp)
	// Call DeleteUnusedSymbolDefs until all unused symbols have been remove.
	// This is to prevent orphaning that occurs when a symbol contains a symbol. See B062453
{
	Handle	symbolLibHdr;

	symbolLibHdr = GS_GetSymbolLibraryHeader(cbp);

	if (symbolLibHdr) {

		int numObjectsDeleted = 0;

		do {
			THandleArray	symbolTable;

			GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateSymbolTable, &symbolTable);
			numObjectsDeleted = DeleteUnusedSymbolDefs(cbp, symbolLibHdr, &symbolTable);
		} while(numObjectsDeleted > 0);
	}
}


static void DeleteUnusedSymbolFolders(CallBackPtr cbp, Handle symbolLibHdr, THandleArray *symbolTable)
	// Loops through all symbols looking for folders, after finding one, function calls itself,
	// upon return, checks to see if folder is empty(has no children), if so, it is deleted.
{
	Handle			firstMemObj;
	Handle			nextObj;
	Handle			childMemObj;

	firstMemObj = GS_FirstMemberObj(cbp, symbolLibHdr);
	if (firstMemObj) {
		do {
			nextObj = GS_NextObject(cbp, firstMemObj);

			if (GS_GetObjectType(cbp, firstMemObj) == kFolderNode) {
				InternalName	symbolName;
				GS_GetObjectName(cbp, firstMemObj, symbolName);

				// recurse into it
				DeleteUnusedSymbolFolders(cbp, firstMemObj, symbolTable);

				// now check to see if the folder is empty, if so, delete it
				childMemObj = GS_FirstMemberObj(cbp, firstMemObj);
				if (childMemObj != nil) {
					// if folder has no children
					if(GS_GetObjectType(cbp, childMemObj) == termNode) {
						// delete it
						GS_DeleteObject(cbp, firstMemObj, false);   // false indicates that this object should not be kept around for undo purposes
						DMSG((kBruce, "Symbol Folder %s is empty and has been deleted\n", symbolName));
					}
				}
			}
			else if (firstMemObj && GS_GetObjectType(cbp, firstMemObj) == termNode) {
				break;
			}
			firstMemObj = nextObj;
		} while (nextObj != nil);
	}
}


static void DeleteUnusedWallStyles(CallBackPtr cbp, Handle dwgHdr, THandleArray *wallStyleTable)
	//Search the wallStyleTable for each Wall Style found
	//here and delete those that are not in the table
{
	
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kWallStyleNode) {
		
				if (!FoundInTable(dataObj, wallStyleTable)) {
					DMSG((kBruce, "Wall Style not found and deleted!!!\n"));
					GS_DeleteObject(cbp, dataObj, false);
				}
				else
					DMSG((kBruce, "Wall Style found and not deleted!!!\n"));
			}
			dataObj = nextObj;
		}
	}
}

static void AddWallStyleClassToClassTable(CallBackPtr cbp, Handle dwgHdr, TLargelongArray* classTable)
// Checks the Wall Style definitions for hatch, gradient & image fill instances.
{
	
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kWallStyleNode) {
				InternalIndex wallStyleClass;
				TVariableBlock value;
				GS_GetObjectVariable(cbp, dataObj, ovWallStyleClass, value);
				value.GetSint32(wallStyleClass);
				if (wallStyleClass > 0) {
					Boolean found = false;
					for (unsigned long i = 0; i < classTable->NumItems(); i++) {
						if (wallStyleClass == (*classTable)[i])
							found = true;
					}
					if (!found) {
						DMSG((kBruce, "Class %d found and added to classTable!!!\n", wallStyleClass));
						classTable->PushData(wallStyleClass);
					}
					else
						DMSG((kBruce, "Class %d found but already exists in classTable!!!\n", wallStyleClass));
				}
			}
			dataObj = nextObj;
		}
	}
}

static void DoDeleteUnusedClasses(CallBackPtr cbp, TLargelongArray *classTable)
	//Search the classTable for each class ID found
	//here and delete those that are not in the table
{
	InternalName	className;
	InternalIndex	classID;

	Handle dwgHdr = GS_GetDrawingHeader(cbp);
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kClassDefNode) {

				GS_GetObjectName(cbp, dataObj, className);
				if (GS_NameToInternalIndexN(cbp, className, classID)) {
					
					if (!FoundInTable(classID, classTable)) {
						DMSG((kBruce, "Class %s not found and deleted!!!\n", className));
						GS_DeleteClass(cbp, className);
					}
					else
						DMSG((kBruce, "Class found and not deleted!!!\n"));
				}
			}
			dataObj = nextObj;
		}
	}
}

static void AddClassTexturesToTextureTable(CallBackPtr cbp, THandleArray* textureTable)
// Checks the class definitions for texture instances.
{
	short j, k;
	InternalIndex i;
	InternalIndex maxID = GS_MaxClassID(cbp);
	for (i = 0; i <= maxID; i++)
		if (GS_ValidClass(cbp, i)) {
			InternalIndex texture[7];
			texture[0] = GS_GetClGenTexture(cbp, i);
			GS_GetClRoofTextures(cbp, i, texture[1], texture[2], texture[3]);
			GS_GetClWallTextures(cbp, i, texture[4], texture[5], texture[6]);
			for (j = 0; j < 7; j++)
				if (texture[j] > 0) {
					InternalName	textureName;
					GS_InternalIndexToNameN(cbp, texture[j], textureName);
					Handle textureDef = GS_GetNamedObject(cbp, textureName);
					Boolean found = false;
					for (k = 0; k < textureTable->NumItems(); k++) {
						if (textureDef == (*textureTable)[k])
							found = true;
					}
					if (!found) {
						DMSG((kBruce, "Texture %d found and added to textureTable!!!\n", texture[j]));
						textureTable->PushData(textureDef);
					}
					else
						DMSG((kBruce, "Texture %d found but already exists in textureTable!!!\n", texture[j]));
				}
		}
}

static void AddWallStyleTexturesToTextureTable(CallBackPtr cbp, Handle dwgHdr, THandleArray* textureTable)
// Checks the Wall Style definitions for texture instances.
{
	
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kWallStyleNode) {
				InternalIndex texture[3];
				TVariableBlock value;
				GS_GetObjectVariable(cbp, dataObj, ovWallStyleLeftTexture, value);
				value.GetSint32(texture[0]);
				GS_GetObjectVariable(cbp, dataObj, ovWallStyleCenterTexture, value);
				value.GetSint32(texture[1]);
				GS_GetObjectVariable(cbp, dataObj, ovWallStyleRightTexture, value);
				value.GetSint32(texture[2]);
				for (int i = 0; i < 3; i++)
					if (texture[i] > 0) {
						InternalName textureName;
						GS_InternalIndexToNameN(cbp, texture[i], textureName);
						Handle textureDef = GS_GetNamedObject(cbp, textureName);
						Boolean found = false;
						for (int j = 0; j < textureTable->NumItems(); j++) {
							if (textureDef == (*textureTable)[j])
								found = true;
						}
						if (!found) {
							DMSG((kBruce, "Texture %d found and added to textureTable!!!\n", texture[i]));
							textureTable->PushData(textureDef);
						}
						else
							DMSG((kBruce, "Texture %d found but already exists in textureTable!!!\n", texture[i]));
					}
			}
			dataObj = nextObj;
		}
	}
}

static void DeleteUnusedTextures(CallBackPtr cbp, Handle drwgHdr, THandleArray *textureTable)
	//Search the textureTable for each Texture definition found
	//here and delete those that are not in the table
{
	Handle			dataHdle;
	Handle			firstMemObj;
	Handle			nextObj;
	Handle			auxHdle;
	
	if (drwgHdr) {
	
		// XXX: I believe these traversal routines could rewritten to be much more concise.  -DLD 1/10/2001
		auxHdle = GS_FirstAuxObject(cbp, drwgHdr);
		if (auxHdle) {
			while (auxHdle && GS_GetObjectType(cbp, auxHdle) != dataNode)
				auxHdle = GS_NextObject(cbp, auxHdle);
				
			if (auxHdle && GS_GetObjectType(cbp, auxHdle) == dataNode)
				dataHdle = auxHdle;
			else
				dataHdle = 0;
		}
			
		if (dataHdle) {
			firstMemObj = GS_FirstMemberObj(cbp, dataHdle);
			
			if (firstMemObj) {			
				
				do {
				
					nextObj = GS_NextObject(cbp, firstMemObj);
					
					if (GS_GetObjectType(cbp, firstMemObj) == kMaterialNode) {

						if (!FoundInTable(firstMemObj, textureTable)) {
							DMSG((kBruce, "Texture not found and deleted!!!\n"));		
							GS_DeleteObject(cbp, firstMemObj, false);   // false indicates that this object should not be kept around for undo purposes
						}
						else
							DMSG((kBruce, "Texture found and not deleted!!!\n"));
					}
					else if (firstMemObj && GS_GetObjectType(cbp, firstMemObj) == termNode) {
					
						return;
					}
					
					firstMemObj = nextObj;
				} while (nextObj != nil);
			}
			else
				DMSG((kBruce, "First Member of DataNode is nil!!!\n"));
		}
	}
}

static void DeleteUnusedRecordFormats(CallBackPtr cbp, Handle drwgHdr, THandleArray *recFormatTable)
	//Search the recFormatTable for each Record Format found
	//here and delete those that are not in the table
{
	Handle			dataHdle;
	Handle			firstMemObj;
	Handle			nextObj;
	Handle			auxHdle;
	
	// XXX: I believe these traversal routines could rewritten to be much more concise.  -DLD 1/10/2001
	if (drwgHdr) {
		//dataHdle = FindAuxObject(cbp, drwgHdr, dataNode);
		auxHdle = GS_FirstAuxObject(cbp, drwgHdr);
		if (auxHdle) {
			while (auxHdle && GS_GetObjectType(cbp, auxHdle) != dataNode)
				auxHdle = GS_NextObject(cbp, auxHdle);
				
			if (auxHdle && GS_GetObjectType(cbp, auxHdle) == dataNode)
				dataHdle = auxHdle;
			else
				dataHdle = 0;
		}
			
		if (dataHdle) {
			firstMemObj = GS_FirstMemberObj(cbp, dataHdle);
			
			if (firstMemObj) {			
				do {
					nextObj = GS_NextObject(cbp, firstMemObj);
					if (GS_GetObjectType(cbp, firstMemObj) == formatNode) {
						
						bool usedByPlugin = false;
						
						if (GS_IsPluginFormat(cbp, firstMemObj)) {
						
							InternalName name;
							EVSPluginType type;
							GS_GetObjectName(cbp, firstMemObj, name);
							Boolean success = GS_GetPluginType(cbp, name, type);
							// If the format node is used by a plugin menu item or tool or
							// by an unknown type of plugin, set found to true so it will
							// not be deleted
							if (! success || type == kVSPluginMenu || type == kVSPluginTool)
								usedByPlugin = true;
						}
						
						if (!usedByPlugin && !FoundInTable(firstMemObj, recFormatTable))  {
						
							DMSG((kBruce, "Record format found and deleted!!!\n"));		
							GS_DeleteObject(cbp, firstMemObj, false);   // false indicates that this object should not be kept around for undo purposes
						}
						else
							DMSG((kBruce, "Record format found and not deleted!!!\n"));
					}
					else if (firstMemObj && GS_GetObjectType(cbp, firstMemObj) == termNode)
						return;

					firstMemObj = nextObj;

				} while (nextObj != nil);
			}
			else
				DMSG((kBruce, "First Member of DataNode is nil!!!\n"));
		}
	}
}

static void AddToHatch_Gradient_ImageFillTable(CallBackPtr cbp, THandleArray* hatchGradImFillTable)
// Checks the class definitions for hatch, gradient & image fill instances.
{
	short j;
	InternalIndex i;
	InternalIndex maxID = GS_MaxClassID(cbp);
	for (i = 0; i <= maxID; i++)
		if (GS_ValidClass(cbp, i)) {
			InternalIndex fill = GS_GetClFillPat(cbp, i);
			if (fill < 0) {
				InternalName name;
				InternalIndex id = -1 * fill;
				GS_InternalIndexToNameN(cbp, id, name);
				Handle def = GS_GetNamedObject(cbp, name);
				Boolean found = false;
				for (j = 0; j < hatchGradImFillTable->NumItems(); j++) {
					if (def == (*hatchGradImFillTable)[j])
						found = true;
				}
				if (!found) {
					DMSG((kBruce, "Hatch, gradient or image fill %d found and added to table!!!\n", id));
					hatchGradImFillTable->PushData(def);
				}
				else
					DMSG((kBruce, "Hatch, gradient or image fill %d found but already exists in table!!!\n", id));
			}
		}
}

static void AddWSToHatch_Gradient_ImageFillTable(CallBackPtr cbp, Handle dwgHdr, THandleArray* hatchGradImFillTable)
// Checks the Wall Style definitions for hatch, gradient & image fill instances.
{
	
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kWallStyleNode) {
				InternalIndex resource;
				TVariableBlock value;
				GS_GetObjectVariable(cbp, dataObj, ovWallStyleFill, value);
				value.GetSint32(resource);
				if (resource < 0) {
					resource = -resource;
					InternalName resourceName;
					GS_InternalIndexToNameN(cbp, resource, resourceName);
					Handle resourceDef = GS_GetNamedObject(cbp, resourceName);
					Boolean found = false;
					for (int i = 0; i < hatchGradImFillTable->NumItems(); i++) {
						if (resourceDef == (*hatchGradImFillTable)[i])
							found = true;
					}
					if (!found) {
						DMSG((kBruce, "Hatch, gradient or image fill %d found and added to textureTable!!!\n", resource));
						hatchGradImFillTable->PushData(resourceDef);
					}
					else
						DMSG((kBruce, "Hatch, gradient or image fill %d found but already exists in textureTable!!!\n", resource));
				}
				short numComponents = 0;
				GS_GetNumberOfComponents(cbp, dataObj, numComponents);
				for (short i = 0; i < numComponents; i++) {
					GS_GetComponentFill(cbp, dataObj, i, resource);
					if (resource < 0) {
						resource = -resource;
						InternalName resourceName;
						GS_InternalIndexToNameN(cbp, resource, resourceName);
						Handle resourceDef = GS_GetNamedObject(cbp, resourceName);
						Boolean found = false;
						for (int i = 0; i < hatchGradImFillTable->NumItems(); i++) {
							if (resourceDef == (*hatchGradImFillTable)[i])
								found = true;
						}
						if (!found) {
							DMSG((kBruce, "Hatch %d found and added to textureTable!!!\n", resource));
							hatchGradImFillTable->PushData(resourceDef);
						}
						else
							DMSG((kBruce, "Hatch %d found but already exists in textureTable!!!\n", resource));
					}
				}
			}
			dataObj = nextObj;
		}
	}
}

static void DeleteUnusedHatches(CallBackPtr cbp, Handle drwgHdr, THandleArray *hatchTable)
	//Search the hatchTable for each Hatch definition found
	//here and delete those that are not in the table
{
	Handle			hatchHdle;
	Handle			firstMemObj;
	Handle			nextObj;
	Handle			auxHdle;
	
	// XXX: I believe these traversal routines could rewritten to be much more concise.  -DLD 1/10/2001
	if (drwgHdr) {
		auxHdle = GS_FirstAuxObject(cbp, drwgHdr);
		if (auxHdle) {
			while (auxHdle && GS_GetObjectType(cbp, auxHdle) != hatchContainerNode)
				auxHdle = GS_NextObject(cbp, auxHdle);
				
			if (auxHdle && GS_GetObjectType(cbp, auxHdle) == hatchContainerNode)
				hatchHdle = auxHdle;
			else
				hatchHdle = 0;
		}
			
		if (hatchHdle) {
			firstMemObj = GS_FirstMemberObj(cbp, hatchHdle);
			
			if (firstMemObj) {			
				do {
					nextObj = GS_NextObject(cbp, firstMemObj);
					if (GS_GetObjectType(cbp, firstMemObj) == hatchDefNode) {
						
						if (!FoundInTable(firstMemObj, hatchTable)) {
							DMSG((kBruce, "Hatch not found and deleted!!!\n"));		
							GS_DeleteObject(cbp, firstMemObj, false);   // false indicates that this object should not be kept around for undo purposes
						}
						else
							DMSG((kBruce, "Hatch found and not deleted!!!\n"));
					}
					else if (firstMemObj && GS_GetObjectType(cbp, firstMemObj) == termNode) {

						return;
					}
						
					firstMemObj = nextObj;

				} while (nextObj != nil);
			}
			else
				DMSG((kBruce, "First Member of HatchContainerNode is nil!!!\n"));
		}
	}
}

static void DeleteUnusedGradients(CallBackPtr cbp, Handle dwgHdr, THandleArray *gradientTable)
	//Search the gradientTable for each gradient definition found
	//here and delete those that are not in the table
{
	
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kGradientDefNode) {
		
				if (!FoundInTable(dataObj, gradientTable)) {
					DMSG((kBruce, "Gradient definition not found and deleted!!!\n"));
					GS_DeleteObject(cbp, dataObj, false);
				}
				else
					DMSG((kBruce, "Gradient definition found and not deleted!!!\n"));
			}
			dataObj = nextObj;
		}
	}
}

static void DeleteUnusedImageFills(CallBackPtr cbp, Handle dwgHdr, THandleArray *imageFillTable)
	//Search the imageFillTable for each image fill definition found
	//here and delete those that are not in the table
{
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)
		aux = GS_NextObject(cbp, aux);

	if (GS_GetObjectType(cbp, aux) == dataNode) {

		Handle dataObj = GS_FirstMemberObj(cbp, aux);
		while (dataObj) {

			Handle nextObj = GS_NextObject(cbp, dataObj);
			if (GS_GetObjectType(cbp, dataObj) == kImageDefNode) {
		
				if (!FoundInTable(dataObj, imageFillTable)) {
					DMSG((kBruce, "Image definition not found and deleted!!!\n"));
					GS_DeleteObject(cbp, dataObj, false);
				}
				else
					DMSG((kBruce, "Image definition found and not deleted!!!\n"));
			}
			dataObj = nextObj;
		}
	}
}

// added by Drew Stanton 9/29/04	
static void DeleteUnusedSketchStyles(CallBackPtr cbp, Handle dwgHdr, TLargelongArray *sketchStyleTable)
	// Search the sketchStyleTable for each sketch style definition found
	// here and delete those that are not in the table
{
	TVariableBlock		value;
	InternalName		sketchName;
	InternalIndex		sketchIndex;
	
	Handle aux = GS_FirstAuxObject(cbp, dwgHdr);
	
	while (aux && GS_GetObjectType(cbp, aux) != dataNode)  
		aux = GS_NextObject(cbp, aux);
		
	if (GS_GetObjectType(cbp, aux) == dataNode) {
		
		Handle dataObj = GS_FindDataObject(cbp, aux, kSketchStyleContainer);
		dataObj = GS_FirstAuxObject(cbp, dataObj);
		
		while (dataObj) {
			
			// get the values needed to do the check 
			Handle nextObj = GS_NextObject(cbp, dataObj);
			GS_GetObjectVariable(cbp, dataObj, ovSketchStyle, value);
			GS_GetObjectName(cbp, dataObj, sketchName);
			GS_NameToInternalIndexN(cbp, sketchName, sketchIndex);
			
			// checking if deletion is necessary
			if(GS_GetDocumentDefaultSketchStyle(cbp) == sketchIndex)
				; // do not delete the sketch style because it's the default setting
			else if (FoundInTable(sketchIndex, sketchStyleTable)) 
				; // do not delete the sketch style because an object is using it
			else
				GS_DeleteObject(cbp, dataObj, false); // delete object, its worthless
					
			dataObj = nextObj;
		}
	}
}

static void DoPurgeObjects(CallBackPtr cbp, PurgeOptionsType purgeOptions)
	//Purges the appropriate objects according to the value of purgeData
	//which is of course determined by the user in the dialog
{
#if GS_WIN
	static HCURSOR origCursor;
	origCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
	ShowCursor(TRUE);
#else
	CursHandle cursorH = ::MacGetCursor(107);
	if (cursorH != nil)
	{
		::MacSetCursor(*cursorH);
	}
	else
	{
		SetThemeCursor(kThemeArrowCursor);
	}
#endif

	//Delete Unused Layers
	if (purgeOptions.doLayers) {
		DMSG((kBruce, "Before ForEachLayer!!!\n")); 
		GS_ForEachLayer(cbp, DoDeleteUnusedLayers, nil);
	}

	//Delete Unused RenderWorks Background Images
	if (purgeOptions.doRWBackgrounds) {
		TLargelongArray			rwBackgroundTable;

		GS_ForEachLayer(cbp, DoCreateRWBackgroundTable, &rwBackgroundTable);
		GS_ForEachObject(cbp, allObjects+descendIntoAll, DoCreateRWBackgroundTable, &rwBackgroundTable);
		DoDeleteUnusedRWBackgrounds(cbp, &rwBackgroundTable);
	}
	

	//Delete Unused Symbols
	if (purgeOptions.doSymbols) {
		DeleteAllUnusedSymbolDefs(cbp);
	}

	//Delete Unused (Empty) Symbol Folders
	if (purgeOptions.doSymbolFolders) {
		Handle	symbolLibHdr;
		symbolLibHdr = GS_GetSymbolLibraryHeader(cbp);
		if (symbolLibHdr) {
			THandleArray	symbolTable;
			GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateSymbolTable, &symbolTable);
			DeleteUnusedSymbolFolders(cbp, symbolLibHdr, &symbolTable);
		}
	}
	
	// Delete Unused Wall Styles
	// Do these after symbol definitions, because walls in symbols may use Wall Styles, and before classes, hatches, gradients, images, and textures, because
	// Wall Styles may use them
	if (purgeOptions.doWallStyles) {
		THandleArray		wallStyleTable;
		Handle				drwgHdr;
		
		InternalIndex wallPreferencesStyle = 0;
		GS_GetWallPrefStyle(cbp, wallPreferencesStyle);
		if (wallPreferencesStyle > 0) {
			InternalName name;
			GS_InternalIndexToNameN(cbp, wallPreferencesStyle, name);
			Handle def = GS_GetNamedObject(cbp, name);
			DMSG((kBruce, "Wall Style %d not found and added to table!!!\n", wallPreferencesStyle));
			wallStyleTable.PushData(def);
		}
		GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateWallStyleTable, &wallStyleTable);
		drwgHdr = GS_GetDrawingHeader(cbp);
		if (drwgHdr)
			DeleteUnusedWallStyles(cbp, drwgHdr, &wallStyleTable);
	}
	
	//Delete Unused Classes
	// (Test for unused classes after we have purged unused symbol definitions, because an unused symbol def may use a class but you still want them both purged.)
	if (purgeOptions.doClasses) {
		TLargelongArray 		classTable;
		Handle					drwgHdr;
		
		GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateClassTable, &classTable);
		drwgHdr = GS_GetDrawingHeader(cbp);
		if (drwgHdr)
			AddWallStyleClassToClassTable(cbp, drwgHdr, &classTable);
		DoDeleteUnusedClasses(cbp, &classTable);
	}


	// Delete Unused Textures
	// Do these before record formats because this operation will sometimes "orphan"
	// record formats, meaning that they should be purged by the format purging stuff
	// which follows.  -DLD 1/10/2001
	if (purgeOptions.doTextures) {
		THandleArray		textureTable;
		Handle				drwgHdr;
		
		GS_ForEachObject(cbp, allObjects+descendIntoAll, DoCreateTextureTable, &textureTable);
		AddClassTexturesToTextureTable(cbp, &textureTable);
		drwgHdr = GS_GetDrawingHeader(cbp);
		if (drwgHdr) {
			AddWallStyleTexturesToTextureTable(cbp, drwgHdr, &textureTable);
			DeleteUnusedTextures(cbp, drwgHdr, &textureTable);
		}
	}	

	//Delete Unused Record Formats
	if (purgeOptions.doRecords) {
		THandleArray		recFormatTable;
		
		GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateRecordFormatTable, &recFormatTable);
		
		Handle drawingHeader = GS_GetDrawingHeader(cbp);
		if (drawingHeader) {

			// We don't want to delete record formats used by texture resources,
			// so we add them to the table  -DLD 1/10/2001
			//AddTextureFormatsToRecordFormatTable(cbp, drawingHeader, &recFormatTable);
			
			//	We ask VectorWorks about each record before we delete it.  We do not need this knowledge
			//	in this external.  We can then expand VectorWorks and not need to modify this code.
			//	 See
			DeleteUnusedRecordFormats(cbp, drawingHeader, &recFormatTable);
		}
	}	

	//Delete Unused Hatches, Gradients & Image Fills
	if (purgeOptions.doHatches || purgeOptions.doGradients || purgeOptions.doImageFills) {
		THandleArray		hatchGradImFillTable;
		Handle				drwgHdr;
		
		GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateHatch_Gradient_ImageFillTable, 
			&hatchGradImFillTable);
		AddToHatch_Gradient_ImageFillTable(cbp, &hatchGradImFillTable);
		drwgHdr = GS_GetDrawingHeader(cbp);
		if (drwgHdr) {
			AddWSToHatch_Gradient_ImageFillTable(cbp, drwgHdr, &hatchGradImFillTable);
			if (purgeOptions.doHatches)
				DeleteUnusedHatches(cbp, drwgHdr, &hatchGradImFillTable);
			if (purgeOptions.doGradients)
				DeleteUnusedGradients(cbp, drwgHdr, &hatchGradImFillTable);
			if (purgeOptions.doImageFills)
				DeleteUnusedImageFills(cbp, drwgHdr, &hatchGradImFillTable);
		}
	}	
	
	
	// Added by Drew Stanton 9/29/04
	// Delete Unused Sketch Styles
	if (purgeOptions.doSketchStyles) {
		TLargelongArray			sketchStyleTable;
		Handle					drwgHdr;
		Handle 					hatchNode;
		
		drwgHdr = GS_GetDrawingHeader(cbp);
		hatchNode = GS_FirstAuxObject(cbp, drwgHdr);
		
		// have to check the special instance of the hatch nodes
		while (GS_GetObjectType(cbp, hatchNode) != hatchContainerNode && hatchNode != nil)
			hatchNode = GS_NextObject(cbp, hatchNode);
			
		hatchNode = GS_FirstMemberObj(cbp, hatchNode);
		while(GS_NextObject(cbp,hatchNode) != nil) {
			DoCreateSketchStyleTable(hatchNode, cbp, &sketchStyleTable);
			hatchNode = GS_NextObject(cbp, hatchNode);
		}	
		
		// have to check both the layers and objects due to each layer being able to have default sketch style
		GS_ForEachLayer(cbp, DoCreateSketchStyleTable, &sketchStyleTable);
		GS_ForEachObject(cbp, allObjects+descendIntoAll+descendIntoViewports, DoCreateSketchStyleTable, &sketchStyleTable);
		DeleteUnusedSketchStyles(cbp, drwgHdr, &sketchStyleTable);
	}

	// Mark document dirty
	GS_MarkCurrentDocChanged(cbp);

#if GS_WIN
    ShowCursor(FALSE);
	SetCursor(origCursor);
#else
	SetThemeCursor(kThemeArrowCursor);
#endif

}

// Declare PurgeItemHandler to avoid compiler warning
extern "C" void PurgeItemHandler(long dlogID, long& inItemHit, void* inItemData, void* ioLayoutEnv);


/////////////////////////////////////////////////////////////////////////////////////////
extern "C" void PurgeItemHandler(long dlogID, long& inItemHit, void* inItemData, void* ioLayoutEnv)
//
// Description:
//   Layout Manager item handler method for the Purge dialog.
//
// Parameters:
//   inItemHit - input - Which item the user has hit.
//   inItemData - input - Value of the item hit.
//   ioLayoutEnv - input/output - Environment for the dialog.
//
// Created by Sean Flaherty on 4/21/00.
//
{
	PurgeEnvType*  purgeEnv = (PurgeEnvType*) ioLayoutEnv;

	switch (inItemHit) {
		case kSetupMessage: {
			Boolean bCheck;
			GetFromSavedSetting(bCheck, sCategory, sClasses);
			purgeEnv->dialogPurgeOptions.doClasses = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kClassesID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sGradients);
			purgeEnv->dialogPurgeOptions.doGradients = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kGradientsID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sHatches);
			purgeEnv->dialogPurgeOptions.doHatches = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kHatchesID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sImageFills);
			purgeEnv->dialogPurgeOptions.doImageFills = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kImagesID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sLayers);
			purgeEnv->dialogPurgeOptions.doLayers = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kLayersID, bCheck);

			if (purgeEnv->texturesEnabled) 
			{
				GetFromSavedSetting(bCheck, sCategory, sTextures);
				purgeEnv->dialogPurgeOptions.doTextures = bCheck;
				GS_SetBooleanItem(gCBP, dlogID, kTexturesID, bCheck);

				GetFromSavedSetting(bCheck, sCategory, sRWBackgrounds);
				purgeEnv->dialogPurgeOptions.doRWBackgrounds = bCheck;
				GS_SetBooleanItem(gCBP, dlogID, kRWBackgroundsID, bCheck);
			}

			GetFromSavedSetting(bCheck, sCategory, sRecords);
			purgeEnv->dialogPurgeOptions.doRecords = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kRecordsID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sSketchStyles);
			purgeEnv->dialogPurgeOptions.doSketchStyles = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kSketchStylesID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sSymbols);
			purgeEnv->dialogPurgeOptions.doSymbols = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kSymbolsID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sWallStyles);
			purgeEnv->dialogPurgeOptions.doWallStyles = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kWallStylesID, bCheck);

			GetFromSavedSetting(bCheck, sCategory, sSymbolFolders);
			purgeEnv->dialogPurgeOptions.doSymbolFolders = bCheck;
			GS_SetBooleanItem(gCBP, dlogID, kSymbolFoldersID, bCheck);

			break;
		}

		case kClassesID: purgeEnv->dialogPurgeOptions.doClasses = (*(long*) inItemData) != 0; break;
		case kGradientsID: purgeEnv->dialogPurgeOptions.doGradients = (*(long*) inItemData) != 0; break;
		case kHatchesID: purgeEnv->dialogPurgeOptions.doHatches = (*(long*) inItemData) != 0; break;
		case kImagesID: purgeEnv->dialogPurgeOptions.doImageFills = (*(long*) inItemData) != 0; break;
		case kLayersID: purgeEnv->dialogPurgeOptions.doLayers = (*(long*) inItemData) != 0; break;
		case kTexturesID: purgeEnv->dialogPurgeOptions.doTextures = (*(long*) inItemData) != 0; break;
		case kRecordsID: purgeEnv->dialogPurgeOptions.doRecords = (*(long*) inItemData) != 0; break;
		case kRWBackgroundsID: purgeEnv->dialogPurgeOptions.doRWBackgrounds = (*(long*) inItemData) != 0; break;
		case kSketchStylesID: purgeEnv->dialogPurgeOptions.doSketchStyles = (*(long*) inItemData) != 0; break;
		case kSymbolsID: purgeEnv->dialogPurgeOptions.doSymbols = (*(long*) inItemData) != 0; break;
		case kWallStylesID: purgeEnv->dialogPurgeOptions.doWallStyles = (*(long*) inItemData) != 0; break;
		case kSymbolFoldersID: purgeEnv->dialogPurgeOptions.doSymbolFolders = (*(long*) inItemData) != 0; break;
		
		case kAllID: {
			purgeEnv->dialogPurgeOptions.doClasses = 1;
			GS_SetBooleanItem(gCBP, dlogID, kClassesID, purgeEnv->dialogPurgeOptions.doClasses);
			purgeEnv->dialogPurgeOptions.doGradients = 1;
			GS_SetBooleanItem(gCBP, dlogID, kGradientsID, purgeEnv->dialogPurgeOptions.doGradients);
			purgeEnv->dialogPurgeOptions.doHatches = 1;
			GS_SetBooleanItem(gCBP, dlogID, kHatchesID, purgeEnv->dialogPurgeOptions.doHatches);
			purgeEnv->dialogPurgeOptions.doImageFills = 1;
			GS_SetBooleanItem(gCBP, dlogID, kImagesID, purgeEnv->dialogPurgeOptions.doImageFills);
			purgeEnv->dialogPurgeOptions.doLayers = 1;
			GS_SetBooleanItem(gCBP, dlogID, kLayersID, purgeEnv->dialogPurgeOptions.doLayers);
			purgeEnv->dialogPurgeOptions.doTextures = 1;
			GS_SetBooleanItem(gCBP, dlogID, kTexturesID, purgeEnv->dialogPurgeOptions.doTextures);
			purgeEnv->dialogPurgeOptions.doRWBackgrounds = 1;
			GS_SetBooleanItem(gCBP, dlogID, kRWBackgroundsID, purgeEnv->dialogPurgeOptions.doRWBackgrounds);
			purgeEnv->dialogPurgeOptions.doRecords = 1;
			GS_SetBooleanItem(gCBP, dlogID, kRecordsID, purgeEnv->dialogPurgeOptions.doRecords);
			purgeEnv->dialogPurgeOptions.doSketchStyles = 1;
			GS_SetBooleanItem(gCBP, dlogID, kSketchStylesID, purgeEnv->dialogPurgeOptions.doSketchStyles);
			purgeEnv->dialogPurgeOptions.doSymbols = 1;
			GS_SetBooleanItem(gCBP, dlogID, kSymbolsID, purgeEnv->dialogPurgeOptions.doSymbols);
			purgeEnv->dialogPurgeOptions.doWallStyles = 1;
			GS_SetBooleanItem(gCBP, dlogID, kWallStylesID, purgeEnv->dialogPurgeOptions.doWallStyles);
			purgeEnv->dialogPurgeOptions.doSymbolFolders = 1;
			GS_SetBooleanItem(gCBP, dlogID, kSymbolFoldersID, purgeEnv->dialogPurgeOptions.doSymbolFolders);
			break;
		}
		
		case kNoneID: {
			purgeEnv->dialogPurgeOptions.doClasses = 0;
			GS_SetBooleanItem(gCBP, dlogID, kClassesID, purgeEnv->dialogPurgeOptions.doClasses);
			purgeEnv->dialogPurgeOptions.doGradients = 0;
			GS_SetBooleanItem(gCBP, dlogID, kGradientsID, purgeEnv->dialogPurgeOptions.doGradients);
			purgeEnv->dialogPurgeOptions.doHatches = 0;
			GS_SetBooleanItem(gCBP, dlogID, kHatchesID, purgeEnv->dialogPurgeOptions.doHatches);
			purgeEnv->dialogPurgeOptions.doImageFills = 0;
			GS_SetBooleanItem(gCBP, dlogID, kImagesID, purgeEnv->dialogPurgeOptions.doImageFills);
			purgeEnv->dialogPurgeOptions.doLayers = 0;
			GS_SetBooleanItem(gCBP, dlogID, kLayersID, purgeEnv->dialogPurgeOptions.doLayers);
			purgeEnv->dialogPurgeOptions.doTextures = 0;
			GS_SetBooleanItem(gCBP, dlogID, kTexturesID, purgeEnv->dialogPurgeOptions.doTextures);
			purgeEnv->dialogPurgeOptions.doRWBackgrounds = 0;
			GS_SetBooleanItem(gCBP, dlogID, kRWBackgroundsID, purgeEnv->dialogPurgeOptions.doRWBackgrounds);
			purgeEnv->dialogPurgeOptions.doRecords = 0;
			GS_SetBooleanItem(gCBP, dlogID, kRecordsID, purgeEnv->dialogPurgeOptions.doRecords);
			purgeEnv->dialogPurgeOptions.doSketchStyles = 0;
			GS_SetBooleanItem(gCBP, dlogID, kSketchStylesID, purgeEnv->dialogPurgeOptions.doSketchStyles);
			purgeEnv->dialogPurgeOptions.doSymbols = 0;
			GS_SetBooleanItem(gCBP, dlogID, kSymbolsID, purgeEnv->dialogPurgeOptions.doSymbols);
			purgeEnv->dialogPurgeOptions.doWallStyles = 0;
			GS_SetBooleanItem(gCBP, dlogID, kWallStylesID, purgeEnv->dialogPurgeOptions.doWallStyles);
			purgeEnv->dialogPurgeOptions.doSymbolFolders = 0;
			GS_SetBooleanItem(gCBP, dlogID, kSymbolFoldersID, purgeEnv->dialogPurgeOptions.doSymbolFolders);
			break;
		}

		case kOKID: {

			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doClasses, sCategory, sClasses);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doGradients, sCategory, sGradients);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doHatches, sCategory, sHatches);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doImageFills, sCategory, sImageFills);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doLayers, sCategory, sLayers);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doTextures, sCategory, sTextures);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doRWBackgrounds, sCategory, sRWBackgrounds);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doRecords, sCategory, sRecords);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doSketchStyles, sCategory, sSketchStyles);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doSymbols, sCategory, sSymbols);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doWallStyles, sCategory, sWallStyles);
			SetFromSavedSetting(purgeEnv->dialogPurgeOptions.doSymbolFolders, sCategory, sSymbolFolders);

			if (GS_NonUndoableActionOK(gCBP)) 
			{
				GS_SetUndoMethod(gCBP, kUndoNone);

				Boolean suspend = true;
				GS_SetProgramVariable(gCBP, 9871, &suspend);
	
				DoPurgeObjects(gCBP, purgeEnv->dialogPurgeOptions);

				suspend = false;
				GS_SetProgramVariable(gCBP, 9871, &suspend);
			}

			break;
		}
		case kDialogDisplayContextualHelp: {
			if (GS_DisplayContextualHelp(gCBP, "net.nemetschek.help.2E7F336C-DA71-11DC-9BB1-001AA0D70350")) {
				inItemHit = kDialogHasContextualHelp;
			}
			break;
		}

		default:
			break;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
bool PurgeDialog(CallBackPtr cbp, PurgeOptionsType& ioPurgeOptions, bool inTexturesEnabled)
//
// Description:
//   Creates and runs the Purge dialog using the Layout Manager.
//
// Parameters:
//   cbp - input - Callback pointer.
//   ioPurgeOptions - input/output - Which options have been enabled for purging.
//   inTexturesEnabled - input - Should the textures check box be presented as an option.
//
// Returns:
//   bool - TRUE if the user selected OK.
//
// Created by Sean Flaherty on 4/21/00.
//
{
	Str255	itemStr1, itemStr2, itemStr3;	// Temporary strings to hold values from the resources

	// Create the layout
	GS_GetResourceString(cbp, kDialogItemStrsID, kDialogNameID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kOKID, itemStr2);
	GS_GetResourceString(cbp, kDialogItemStrsID, kCancelID, itemStr3);
	long dlogID = GS_CreateLayout(cbp, itemStr1, true, itemStr2, itemStr3);
	
	// Create items for the layout
	GS_GetResourceString(cbp, kDialogItemStrsID, kClassesID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kClassesID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kGradientsID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kGradientsID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kHatchesID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kHatchesID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kImagesID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kImagesID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kLayersID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kLayersID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kTexturesID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kTexturesID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kRecordsID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kRecordsID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kRWBackgroundsID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kRWBackgroundsID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kSketchStylesID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kSketchStylesID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kSymbolsID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kSymbolsID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kSymbolFoldersID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kSymbolFoldersID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kWallStylesID, itemStr1);
	GS_CreateCheckBox(cbp, dlogID, kWallStylesID, itemStr1);
	
	// Setting up the All/None buttons
	GS_GetResourceString(cbp, kDialogItemStrsID, kAllID, itemStr1);
	GS_CreatePushButton(cbp, dlogID, kAllID, itemStr1);
	GS_GetResourceString(cbp, kDialogItemStrsID, kNoneID, itemStr1);
	GS_CreatePushButton(cbp, dlogID, kNoneID, itemStr1);

	// Set help strings
	for (short i = 1; i <= kNoneID; i++) {
		GS_GetResourceString(cbp, kDialogHelpStrsID, i, itemStr1);
		GS_SetHelpText(cbp, dlogID, i, itemStr1);
	}

	// Arrange items in the layout
	GS_SetFirstLayoutItem(cbp, dlogID, kClassesID);
	GS_SetBelowItem(cbp, dlogID, kClassesID, kGradientsID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kGradientsID, kHatchesID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kHatchesID, kImagesID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kImagesID, kLayersID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kLayersID, kRecordsID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kRecordsID, kRWBackgroundsID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kRWBackgroundsID, kSketchStylesID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kSketchStylesID, kSymbolsID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kSymbolsID, kSymbolFoldersID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kSymbolFoldersID, kTexturesID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kTexturesID, kWallStylesID, 0, 0);
	GS_SetBelowItem(cbp, dlogID, kWallStylesID, kAllID, 3, 0);
	GS_SetRightItem(cbp, dlogID, kAllID, kNoneID, 0, 0);
	
	
	const TXString emptyStr = "";
	const TXString category = "PurgeUnusedObjects", item = "LegacyMenuCommand";
	Str255 message = "";
	GS_GetResourceString(cbp, kWarningStringsID, 3, message);

	GS_AlertInform(cbp, message, emptyStr, false, category, item, emptyStr);
 
	// Run the layout
	if (GS_VerifyLayout(cbp, dlogID)) {
		PurgeEnvType	dialogEnv;
		
		dialogEnv.dialogPurgeOptions = ioPurgeOptions;
		dialogEnv.texturesEnabled = inTexturesEnabled;

		long result = GS_RunLayoutDialog(cbp, dlogID, PurgeItemHandler, (void*) &dialogEnv);
		
		if (result == kOKID) {
			ioPurgeOptions = dialogEnv.dialogPurgeOptions;
			return true;
		}
	}

	return false;
}

