#include "ADFS_Icons.h"
#include "FSUtils.h"
#include "Utils.h"
#include "IC_Errors.h"

#define		kSys7AppIcon			kGenericApplicationIconResource
#define		kSys7DocumentIcon		kGenericDocumentIconResource
#define		kSys7FolderIcon			kGenericFolderIconResource
#define		kSys7SystemIcon			-16494
#define		kSys7MountIcon			kMountedFolderIconResource
#define		kSys7ShareIcon			kSharedFolderIconResource

#define		kSys7FinderIcon			3
#define		kSys7TrashIcon			kTrashIconResource
#define		kSys7TrashFullIcon		kFullTrashIconResource

#ifdef OLD68K
	typedef	void	*IconRef;
 	#define	gestaltIconUtilitiesHasIconServices		4
#endif

IconRef	gApplicationIconSuite		= NULL;
IconRef	gDocumentIconSuite			= NULL;
IconRef	gFolderIconSuite			= NULL;
IconRef	gSuitcaseIconSuite			= NULL;
IconRef	gMountIconSuite				= NULL;
IconRef	gShareIconSuite				= NULL;

static	OSErr	ADFS_IconTypeToRef(ADFS_IconType iconType, IconRef **iconRefPP)
{
	OSErr				err = noErr;
	
	switch (iconType) {
		
		case ADFS_Icon_APPLICATION: {
			*iconRefPP = &gApplicationIconSuite;
			break;
		}

		case ADFS_Icon_DOCUMENT: {
			*iconRefPP = &gDocumentIconSuite;
			break;
		}

		case ADFS_Icon_FOLDER: {
			*iconRefPP = &gFolderIconSuite;
			break;
		}

		case ADFS_Icon_SYSTEM: {
			*iconRefPP = &gSuitcaseIconSuite;
			break;
		}

		case ADFS_Icon_MOUNT_FOLDER: {
			*iconRefPP = &gMountIconSuite;
			break;
		}

		case ADFS_Icon_SHARE_FOLDER: {
			*iconRefPP = &gShareIconSuite;
			break;
		}
	}

	if (**iconRefPP == NULL) {
		#ifdef OLD68K
			ASSERT("iconRef on 68k?" == NULL);
		#else
			err = GetIconRef(
				kOnSystemDisk, kSystemIconsCreator, 
				iconType, *iconRefPP);
		#endif
	}
	
	return err;
}

extern	RgnHandle		gRgn1;
extern	RgnHandle		gRgn2;

static	Boolean		ic_inittedB = FALSE;
static	Boolean		ic_hasB = FALSE;
static	Boolean		HasIconServices(void)
{
	if (!ic_inittedB) {
		long	result;
		
		if (Gestalt(gestaltIconUtilitiesAttr, &result) == noErr) {
			ic_hasB = (result & (1 << gestaltIconUtilitiesHasIconServices)) != 0;
		}
		
		ic_inittedB = TRUE;
	}
	
	return ic_hasB;
}

Handle			g_iconSuiteH = NULL;

/*

#define require(x,y) do { if (!(x)) goto y; } while (0)

AEDesc pFinderTarget;

//----------------------------------------------------------------------------
// FinderIsRunning
//
// Walk the Process Mgr list to check if the Finder is running
//----------------------------------------------------------------------------

static Boolean FinderIsRunning (void)
{
 OSErr   err;
 ProcessInfoRec pInfo;
 ProcessSerialNumber psn;
 Boolean   foundIt;

 foundIt = false;
 psn.highLongOfPSN = 0; psn.lowLongOfPSN = kNoProcess;

 while ((foundIt == false) && (GetNextProcess(&psn) == noErr)) {
  pInfo.processName   = NULL;
  pInfo.processAppSpec  = NULL;
  pInfo.processInfoLength = sizeof(ProcessInfoRec);
 
  err = GetProcessInformation(&psn, &pInfo);
 
  if ((err == noErr) 
   && (pInfo.processSignature == 'MACS') 
   && (pInfo.processType == 'FNDR'))
   
   foundIt = true;
 }
 
 return foundIt;
}

//----------------------------------------------------------------------------
// HaveScriptableFinder
//
// We have it if the Gestalt bit is set and the Finder is running
//----------------------------------------------------------------------------

static Boolean HaveScriptableFinder(void)
{
 long   response;
 Boolean  haveScriptableFinder;
 OSErr  err;

 haveScriptableFinder = false;
 
 err = Gestalt(gestaltFinderAttr, &response);
 require(err == noErr, Gestalt);

 if ((response & (1 << gestaltOSLCompliantFinder)) && (FinderIsRunning()))
  haveScriptableFinder = true;

Gestalt:
 return haveScriptableFinder;
}

//----------------------------------------------------------------------------
// SendAppleEvent
//----------------------------------------------------------------------------

static OSErr SendAppleEvent(AppleEvent *ae, AppleEvent *reply, AESendMode sendMode)
{
 AppleEvent throwAwayReply;
 OSErr  err;

 if (reply == NULL) {
  err = AESend(ae, &throwAwayReply, sendMode, 
     kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
  if (err == noErr)
   AEDisposeDesc(&throwAwayReply);
 }
 else
  err = AESend(ae, reply, sendMode, 
     kAENormalPriority, kAEDefaultTimeout, NULL, NULL);

 return err;
}


//----------------------------------------------------------------------------
// MakeAppleEvent
//----------------------------------------------------------------------------

static pascal OSErr MakeAppleEvent
 (AEEventClass aeClass, AEEventID aeID, AEDesc *target, AppleEvent *ae)
{
 OSErr err = noErr;

 if (target->dataHandle == nil)
 {
  DescType finderSig = 'MACS';

  err = AECreateDesc(typeApplSignature, (Ptr) &finderSig,
   sizeof(DescType), target);
 }

 if (!err)
  err = AECreateAppleEvent(aeClass, aeID, target, 
   kAutoGenerateReturnID, kAnyTransactionID, ae);
 
 return err;
}

//----------------------------------------------------------------------------
// MakeSpecifierForSelection
//----------------------------------------------------------------------------

static OSErr MakeSpecifierForSelection(AEDesc *selectionSpecifier)
{
 OSErr   err;
 DescType  descData;
 AEDesc  keyData, nullDescriptor;
 
 nullDescriptor.descriptorType = typeNull;
 nullDescriptor.dataHandle = NULL;

 //
 // Make a descriptor whose type is 'typeType' and whose
 // contents are 'pSelection' (defined in FinderRegistry.h).
 // This descriptor specifies the property of the null container
 // that we are interested in--in this case, the selection.
 //
 descData = pSelection;
 err = AECreateDesc(typeType, (Ptr) &descData, sizeof(DescType), &keyData);
 require(err == noErr, AECreateDesc);
 
 err = CreateObjSpecifier(cProperty, &nullDescriptor, formPropertyID,
         &keyData, true, selectionSpecifier);

AECreateDesc:
 return err;
}

//----------------------------------------------------------------------------
// MakeSpecifierForFile
//----------------------------------------------------------------------------
static pascal OSErr MakeSpecifierForFile(FSSpecPtr hfsObj, AEDesc *fileSpecifier)
{
 OSErr  err;
 AEDesc  nullDesc, hfsData;
 AliasHandle fileAlias;

 //
 // Create the file descriptor with the FSSpec passed in.
 //
 err = NewAlias(NULL, hfsObj, &fileAlias);
 require(err == noErr, NewAlias);

 HLock((Handle) fileAlias);
 err = AECreateDesc(typeAlias, (Ptr) *fileAlias, 
    GetHandleSize((Handle) fileAlias), &hfsData);
 HUnlock((Handle) fileAlias);
 DisposeHandle((Handle) fileAlias);
 require(err == noErr, AECreateDesc);

 //
 // Make the object specifier with a null container
 // (i.e., "file of <null>", or just "file")
 //
 nullDesc.descriptorType = typeNull;
 nullDesc.dataHandle = NULL; 
 err = CreateObjSpecifier(typeWildCard, &nullDesc, 
    formAlias, &hfsData, false, fileSpecifier);

AECreateDesc:
NewAlias:
 return err;
}

//----------------------------------------------------------------------------
// MakePropertySpecifierForSpecifier
//----------------------------------------------------------------------------

static pascal OSErr MakePropertySpecifierForSpecifier
 (DescType property, AEDesc *ofSpecifier, AEDesc *propertySpecifier)
{
 OSErr  err;
 AEDesc  keyData;
 
 //
 // Create a 'type' AEDesc with the desired property
 //
 err = AECreateDesc(typeType, (Ptr) &property, sizeof(DescType), &keyData);
 require(err == noErr, AECreateDesc);

 //
 // With it create a property specifier for the object specifier
 // passed to us.
 //
 err = CreateObjSpecifier(cProperty, ofSpecifier, 
    formPropertyID, &keyData, false, propertySpecifier);

 (void) AEDisposeDesc(&keyData); 
AECreateDesc:
 return err;
}

//----------------------------------------------------------------------------
// GetSizeFromIconType
//----------------------------------------------------------------------------

static pascal Size GetSizeFromIconType (DescType iconType)
{
 Size size = -1;

 switch (iconType) {
  case large8BitData:
   size = kLarge8BitIconSize;
   break;
  case large4BitData:
   size = kLarge4BitIconSize;  
   break;
  case large1BitMask:
   size = kLargeIconSize;
   break;
  case small8BitData:
   size = kSmall8BitIconSize;
   break;
  case small4BitData:
   size = kSmall4BitIconSize;
   break;
  case small1BitMask:
   size = kSmallIconSize;
   break;
 }
 return size;
}


//----------------------------------------------------------------------------
// BuildIconSuiteFromAEDesc
//
// OK, this uses the Apple Event Manager to pick the icon data out of the
// 'ifam' AEDesc.
//----------------------------------------------------------------------------

static pascal OSErr BuildIconSuiteFromAEDesc
 (Boolean largeIcons, Handle *iconSuite, AEDesc *iconFam)
{
 OSErr  err;
 Handle   suite, icon;
 AERecord rec;
 Ptr   buffer;
 DescType large[3] = {large8BitData, large4BitData, large1BitMask};
 DescType small[3] = {small8BitData, small4BitData, small1BitMask};
 DescType *type, iconType, typeCode;
 long  count;
 Size  maxSize, size, iconSize;
 Boolean  maskAdded;
 DescType maskType;

 maskAdded = false;
 suite = NULL;
 maxSize = kLarge8BitIconSize;

 if (largeIcons == true) {
  type = large;
  maskType = large1BitMask;
 }
 else {
  type = small;
  maskType = small1BitMask;
 }

 buffer = NewPtr(maxSize);
 require(buffer != NULL, NewPtr);
 
 err = NewIconSuite(&suite);
 require(err == noErr, NewIconSuite);
 
 err = AECoerceDesc(iconFam, typeAERecord, (AEDesc *) &rec);
 require(err == noErr, AECoerceDesc);
 
 for (count = 0; count < 3; count ++) {
  //
  // loop through the icons and grab the data from the AERecord for
  // each type of icon we're interested in.
  //
  iconType = type[count];
  size = GetSizeFromIconType(iconType);
  err = AEGetKeyPtr(&rec, iconType, iconType, &typeCode, 
      buffer, maxSize, &iconSize);
 
  if (err == noErr) {
   //
   // We don't set the error code for this unless the NewHandle
   // call fails, because it's possible that the 'ifam' doesn't
   // have an icon for one that we're interested in.
   //
   icon = NewHandle(size);
 
   if (icon != NULL) {
    //
    // OK, the memory alloc succeeded and we have data. Copy
    // it into the allocated icon and add it to the suite. 
    // Set atLeastOne to true, to indicate later that we did
    // in fact add at least one icon to this suite.
    //
    BlockMoveData(buffer, *icon, size);
    err = AddIconToSuite(icon, suite, iconType);
    if ((err == noErr) && (iconType == maskType))
     maskAdded = true;
   }
   else
    err = memFullErr;
  }
 }

 (void) AEDisposeDesc(&rec);

AECoerceDesc:
 if ((err != noErr) || (maskAdded == false)) {
  //
  // There was either an error in a memory allocation,  or something
  // else went wrong (like no mask was added to the suite).  Get
  // rid of the partially created suite.
  //
  DisposeIconSuite(suite, true);
  suite = NULL;
 }

NewIconSuite:
 DisposePtr(buffer);

NewPtr:
 *iconSuite = suite;
 return err;
}

//----------------------------------------------------------------------------
// GetIconSuiteFromFinder
//
// Send a GetData AE for the 'ifam'
//----------------------------------------------------------------------------
OSErr GetIconSuiteFromFinder (FSSpecPtr hfsObj, Handle *iconSuite)
{
 OSErr  err;
 AppleEvent finderEvent, replyEvent;
 AEDesc  fileSpecifier, iconPropertySpecifier;
 DescType returnType;
 Size  returnSize;
 long  returnLong;
 AEDesc  iconFamily;

 //
 // Set up our locals for easy cleanup
 //
 *iconSuite = NULL;

 //
 // Make sure the Finder is scriptable and is running.
 //
 err = paramErr;
 require(HaveScriptableFinder() == true, HaveScriptableFinder);

 //
 // Make a GetData Apple event to send to the Finder
 //
 err = MakeAppleEvent(kAECoreSuite, kAEGetData, &pFinderTarget, 
    &finderEvent);
 require(err == noErr, MakeAppleEvent);
 
 //
 // Make an object specifier for the interesting file
 //
 err = MakeSpecifierForFile(hfsObj, &fileSpecifier);
 require(err == noErr, MakeSpecifierForFile);
 
 //
 // Make an icon family property specifier for the file
 //
 err = MakePropertySpecifierForSpecifier(pIconBitmap, &fileSpecifier, 
    &iconPropertySpecifier);
 require(err == noErr, MakePropertySpecifierForSpecifier);
 
 //
 // Stuff it in the Apple event and send it
 //
 err = AEPutParamDesc(&finderEvent, keyDirectObject, &iconPropertySpecifier);
 require(err == noErr, AEPutParamDesc);

 err = SendAppleEvent(&finderEvent, &replyEvent,
    kAEWaitReply + kAECanInteract + kAECanSwitchLayer);
 require(err == noErr, SendAppleEvent);
 
 //
 // Now the Finder may have sent us an error number
 //
 err = AEGetParamPtr(&replyEvent, keyErrorNumber, typeLongInteger, 
      &returnType, &returnLong, sizeof(long), &returnSize);

 if (err == noErr)
  err = (OSErr) returnLong;
 else if (err == errAEDescNotFound)
  err = noErr;

 //
 // If not, get the icon family and build an icon suite
 //

 if (!err)
 {  
  err = AEGetParamDesc(&replyEvent, keyDirectObject, typeWildCard, &iconFamily); 
  require(err == noErr, AEGetParamDesc);
  err = BuildIconSuiteFromAEDesc(true, iconSuite, &iconFamily);
 }

 //
 // Clean up and exit
 //

 (void) AEDisposeDesc(&iconFamily);

AEGetParamDesc:
 (void) AEDisposeDesc(&replyEvent);

SendAppleEvent:
AEPutParamDesc:
 (void) AEDisposeDesc(&iconPropertySpecifier);

MakePropertySpecifierForSpecifier:
 (void) AEDisposeDesc(&fileSpecifier);

MakeSpecifierForFile:
 (void) AEDisposeDesc(&finderEvent);

MakeAppleEvent:
HaveScriptableFinder:
 return err;
} 
*/

Handle			FSpGetIconSuite(FSSpec *specP)
{
	Handle	suiteH	= NULL;
	OSErr	err		= noErr;
	OSErr	err2	= noErr;
	
	if (HasIconServices()) {
		#ifndef OLD68K
			IconRef				iconRef		= NULL;
			IconFamilyHandle	iconFamH	= NULL;
			IconSuiteRef		iconSuiteH	= NULL;
			short				label;
			
			err = GetIconRefFromFile(specP, &iconRef, &label);
			
			if (!err) {
				err = IconRefToIconFamily(iconRef, kSelectorAllAvailableData, &iconFamH);
				
				if (!err) {
					err = IconFamilyToIconSuite(iconFamH, kSelectorAllAvailableData, &iconSuiteH);
					
					if (!err) {
						suiteH = iconSuiteH;
					}
					
					DisposeHandle((Handle)iconFamH);
				}
				
				ERR2(ReleaseIconRef(iconRef));
			}
		#endif
	} else {
		Boolean		folderB;
		OSType		osType;
		
		//	suck it out of the DesktopDB
		
		//	for now just use generic icons
		err = FSpIsFolder(specP, &folderB);
		
		if (!err) {
			
			if (folderB) {
				osType = kSys7FolderIcon;
			} else {
				FInfo		fInfo;
				
				err	= FSpGetFInfo(specP, &fInfo);
				
				if (!err) {
					if (fInfo.fdType == 'APPL') {
						osType = kSys7AppIcon;
					} else {
						osType = kSys7DocumentIcon;
					}
				}
			}
			
			if (!err) {
				err = GetIconSuite(&suiteH, osType, kSelectorAllAvailableData);
			}
		}
	}
	
	return suiteH;
}

void			ADFS_DrawIcon(ADFS_IconType iconType, Rect *theRect, IconTransformType transform)
{
	OSErr			err;
	Boolean			useSuiteB = TRUE;
	Boolean			deletedB	= (transform & kTransformDeleted) != 0;
	Boolean			lockedB		= (transform & kTransformLocked) != 0;
	Handle			iconSuite	= NULL;
	
	transform &= ~(kTransformDeleted | kTransformLocked);
	
	err = noErr;

	if (iconType == ADFS_Icon_CUSTOM) {
		ASSERT(g_iconSuiteH != NULL);
		iconSuite = g_iconSuiteH;
		iconType = kSys7SystemIcon;
	} else if (iconType > ADFS_Icon_CPM_SCTP) {
	
		if (HasIconServices()) {
			#ifndef OLD68K
				IconRef		iconRef		= NULL;
				IconRef		*iconRefP	= &iconRef;
				
				useSuiteB = FALSE;

				err = ADFS_IconTypeToRef(iconType, &iconRefP);

				if (!err) err = PlotIconRef (
				    theRect, 
				    kAlignNone, 
				    transform, 
				    kIconServicesNormalUsageFlag, 
				    *iconRefP
				);

				if (!err) err = IconRefToRgn(
					gRgn1,
					theRect,
					kAlignNone,
					kIconServicesNormalUsageFlag,
				 	*iconRefP);
				#endif
		} else {
			switch (iconType) {

				case ADFS_Icon_APPLICATION: {
					iconType = kSys7AppIcon;
					break;
				}

				case ADFS_Icon_DOCUMENT: {
					iconType = kSys7DocumentIcon;
					break;
				}

				case ADFS_Icon_FOLDER: {
					iconType = kSys7FolderIcon;
					break;
				}

				case ADFS_Icon_SYSTEM: {
					iconType = kSys7SystemIcon;
					break;
				}

				case ADFS_Icon_MOUNT_FOLDER: {
					iconType = kSys7MountIcon;
					break;
				}

				case ADFS_Icon_SHARE_FOLDER: {
					iconType = kSys7ShareIcon;
					break;
				}
			}
		}
	}
	
	if (useSuiteB) {
		if (iconSuite == NULL) {
			err = GetIconSuite(&iconSuite, iconType, kSelectorAllAvailableData);
		}

		PlotIconSuite(theRect, kAlignNone, transform, iconSuite);
		IconSuiteToRgn(gRgn1, theRect, kAlignNone, iconSuite);
	}

	if (iconType == ADFS_Icon_CUSTOM) {
		g_iconSuiteH = NULL;
	}
	
	if (!err) {
		RectRgn(gRgn2, theRect);
		DiffRgn(gRgn2, gRgn1, gRgn1);
		EraseRgn(gRgn1);

	
		if (deletedB) {
			err = GetIconSuite(&iconSuite, ADFS_Icon_TRASH_BADGE, kSelectorAllAvailableData);
			PlotIconSuite(theRect, kAlignNone, transform, iconSuite);
		}

		if (!err && lockedB) {
			err = GetIconSuite(&iconSuite, ADFS_Icon_LOCK_BADGE, kSelectorAllAvailableData);
			PlotIconSuite(theRect, kAlignNone, transform, iconSuite);
		}
	}

	if (err) {
		ReportErrorStr(err, "Failed to get Icon Suite");
		ExitToShell();
	}
}

