//	CDisk.c

#include "MemUtils.h"
#include "CDialogCopy.h"
#include "ADFS_Strings.h"
#include "IC_FileIO.h"
#include "IC_ImageTypes.h"
#include "FSUtils.h"
#include "ADFS_LogFile.h"
#include "GenStructs.h"
#include "ADFS_Prefs.h"
#include "Utils.h"
#include "Nibblizer.h"
#include "CDialogGetInfo.h"
#include "CDialogEraseDisk.h"
#include "ADFS_O_Callbacks.h"
#include "CDesktop.h"
#include "CDialogNewDisk.h"
#include "CDiskMapWindow.h"
#include "PhysicalFloppy.h"
#include "CDesktopWindow.h"

#include "CDialogInsertDisk.h"
#include "CDialogQuick3.h"

#include "CDisk.h"

static	EntryIndex	g_diskIndex = 1;

OSErr		CDisk::IDisk(
	CDesktop		*desktop, 
	DiskImageRec	*imageRec
) {
	OSErr				err			= noErr;
	FSObjectType		type		= FSObject_DISK;
	DiskLocSpecUnion	diskLoc		= { 0 };
	O_CTopic			*root;
	
	i_desktop			= desktop;
	i_imageRec			= imageRec;
	i_flushMemLevel		= 1;
	i_fileTypeMenu		= NULL;
	i_rootDir.gen		= NULL;
	i_diskMapP			= NULL;
	i_pending_flushB	= FALSE;
	i_show_deletedB		= FALSE;

	i_blocksInVolume	= Pro_kBlocksPerDisk;	//	at least

	structclr(i_mapRec);
	structclr(i_tempFileSpec);

	if (!i_imageRec) {
		ReportError(err = IC_Err_OUT_OF_MEMORY);
	}

	if (!err) err = BuildFileTypeMenu();
	if (!err) err = desktop->i_cOutline->O_GetRoot(&root);
	if (!err) err = root->O_SetRecent();
	if (!err) err = _inherited::IEntry(this, NULL, type, diskLoc, 0, g_diskIndex++);

	return err;
}

void		CDisk::Dismount(void)
{
	if (i_diskMapP) {
		i_diskMapP->Dispose();
		i_diskMapP = NULL;
	}

	if (i_imageRec) {

		if (i_imageRec->image.gen) {
			TrackDisposePtr((Ptr)i_imageRec->image.gen);
		}
		
		if (--i_imageRec->deviceP->refCountS == 0) {

			if (IS_ImageRec_PHYSICAL(i_imageRec)) {
				(void)EjectFloppy(&ImageRec_VolRec(i_imageRec).phys);
			}
			
			TrackDisposePtr((Ptr)i_imageRec->deviceP);
		}
		

		TrackDisposePtr((Ptr)i_imageRec);
		i_imageRec = NULL;
	}
}

void		CDisk::Dispose(void)
{
	if (!i_disposingB) {

		if (i_diskMapP) {
			i_diskMapP->Dispose();
			i_diskMapP = NULL;
		}

		if (i_rootDir.gen) {
			i_rootDir.gen->Dispose();
		}
	
		Dismount();
	}
	
	_inherited::Dispose();
}

void		CDisk::Map(void)
{
	Boolean		success = TRUE;
	
	if (!i_diskMapP) {
		i_diskMapP = new CDiskMapWindow;
		
		if (i_diskMapP == NULL) {
			ReportError(IC_Err_OUT_OF_MEMORY);
		} else {
			success = i_diskMapP->IDiskMapWindow(this);
		}
	}
	
	if (success) {
		i_diskMapP->Show(TRUE);
	}
}

Err			CDisk::EntryDispatchCB(
	O_CBType				cbType, 
	O_CBDataP			cbData)
{
	OSErr		err = noErr;
	
	switch (cbType) {
		
		case ADFS_O_CB_PANE_ARRAY_GET_DISKS:
		case ADFS_O_CB_PANE_ARRAY_GET_SEL_DISKS: {
			err = _inherited::EntryDispatchCB(
				ADFS_O_CB_PANE_ARRAY_GET, cbData);
			break;
		}
		
		default: {
			err = _inherited::EntryDispatchCB(cbType, cbData);
			break;
		}
	}

	return err;
}

MenuRef		CDisk::GetFileTypeMenu(void)
{
	return i_fileTypeMenu;	
}

OSErr		CDisk::BuildFileTypeMenu(void)
{
	i_fileTypeMenu = NULL;
	return noErr;
}

short		CDisk::MenuItemToFileType(short menuItem, ushort *auxType)
{
	return 0;
}

short		CDisk::FileTypeToMenuItem(Byte fileType, short auxType)
{
	return 1;
}

short		CDisk::GetSectorOrderForIcon(void)
{
	short	order = -1;
	
	switch (ImageRec_OrigOrder(i_imageRec)) {
		case FSType_C2P: order++;	//	3
		case FSType_CPM: order++;	//	2
		case FSType_DOS: order++;	//	1
		case FSType_PRO:
		case FSType_PAS: order++;	//	0
	}
	
	return order;
}

ulong		CDisk::GetLogicalSize(void)
{
	if (i_logical_sizeL == 0) {
		i_logical_sizeL = GetVolumeBytesUsed();
	}
	
	return i_logical_sizeL;
}

ulong		CDisk::GetVolumeBytesUsed(void)
{
	return 0;	//	override, calc bytes used
}

ulong		CDisk::GetVolumeBytesFree(void)
{
	ulong	freeL = GetPhysicalSize() - GetLogicalSize();
	
	return freeL;
}

OSErr		CDisk::VerifyFreeSpace(ulong sizeL)
{
	OSErr		err = noErr;
	
	if (sizeL > GetVolumeBytesFree()) {
		ReportError(err = IC_Err_DISK_FULL);
	}
	
	return err;
}

ulong		CDisk::GetPhysicalSize(void)
{
	if (i_physical_sizeL == 0) {
		i_physical_sizeL = GetVolumeSize();
	}
	
	return i_physical_sizeL;
}

ulong		CDisk::GetVolumeSize(void)
{
	return sizeof(Gen_Disk);
}

Gen_AllocNodeRec	*CDisk::GetNodeRec(
	Gen_AllocMap		*blockBitMapP, 
	Gen_AllocTypeRec	*allocTypeRecP, 
	ushort				curSectorS)
{
	Gen_AllocNodeRec		*nodeRecP = NULL;
	Pro_BlockNum			blockNum;
	Gen_SectorSpec			sectorSpec;

	switch (blockBitMapP->allocSize) {

		case Gen_AllocSize_SECTORS: {
			sectorSpec = allocTypeRecP->u.sectorsA[curSectorS];
			
			if (!Gen_ValidSector(blockBitMapP->allocSize, sectorSpec)) {
				sectorSpec = Gen_LastValidSector(blockBitMapP->allocSize);
				blockBitMapP->nonExistantS++;
			}
			
			nodeRecP	= &blockBitMapP->map.disk140A
				->track[sectorSpec.track].sector[sectorSpec.sector];
			break;
		}

		case Gen_AllocSize_SECTORS400: {
			sectorSpec = allocTypeRecP->u.sectorsA[curSectorS];

			if (!Gen_ValidSector(blockBitMapP->allocSize, sectorSpec)) {
				sectorSpec = Gen_LastValidSector(blockBitMapP->allocSize);
				blockBitMapP->nonExistantS++;
			}

			nodeRecP	= &blockBitMapP->map.disk400A
				->track[sectorSpec.track].sector[sectorSpec.sector];
			break;
		}

		case Gen_AllocSize_SHORT: {
			blockNum	= allocTypeRecP->u.short_blocksA[curSectorS];

			if (blockNum >= blockBitMapP->maxSizeS) {
				blockNum = blockBitMapP->maxSizeS - 1;
				blockBitMapP->nonExistantS++;
			}
			nodeRecP	= &blockBitMapP->map.blockA[blockNum];
			break;
		}

		case Gen_AllocSize_BYTE: {
			blockNum	= allocTypeRecP->u.byte_blocksA[curSectorS];

			if (blockNum >= blockBitMapP->maxSizeS) {
				blockNum = blockBitMapP->maxSizeS - 1;
				blockBitMapP->nonExistantS++;
			}

			nodeRecP	= &blockBitMapP->map.blockA[blockNum];
			break;
		}
	}
	
	return nodeRecP;
}

Gen_AllocType		CDisk::SpecifyAllocFileType(Gen_AllocType allocType, ADFS_FileType fileType)
{
	if (allocType == Gen_Alloc_FILE) {
	
		switch (fileType) {

			case ADFS_File_BASIC:
			case ADFS_File_INTBASIC: {
				allocType	= Gen_Alloc_FILE_BAS;
				break;
			}
			
			case ADFS_File_TEXT:
			case ADFS_File_AWP: {
				allocType	= Gen_Alloc_FILE_TXT;
				break;
			}
			
			case ADFS_File_BINARY: {
				allocType	= Gen_Alloc_FILE_BIN;
				break;
			}
		}
	}
	
	return allocType;
}


OSErr		CDisk::AddSectorsToMap(
	CEntry				*entryP, 
	Gen_EntryAlloc		*entrySectorsP, 
	Gen_AllocMap		*blockBitMapP)
{
	OSErr					err = noErr;
	Gen_AllocType			allocTypeS;
	Gen_AllocNodeRec		*nodeRecP;
	Gen_AllocTypeRec		*allocTypeRecP;
	ushort					curSectorS;

	ASSERT(entrySectorsP->allocSize == blockBitMapP->allocSize);
	
	for (
		allocTypeS = Gen_Alloc_NONE; 
		!err && allocTypeS < Gen_Alloc_NUMTYPES;
		allocTypeS = (Gen_AllocType)(allocTypeS + 1)
	) {
		allocTypeRecP = &entrySectorsP->type[allocTypeS];
		
		for (
			curSectorS = 0; 
			!err && curSectorS < allocTypeRecP->totalS; 
			curSectorS++
		) {
			nodeRecP = GetNodeRec(
				blockBitMapP, allocTypeRecP, curSectorS);
			
			if (!err) {
			
				if (nodeRecP->allocType != Gen_Alloc_NONE) {
					Gen_AllocNodeRec		**nodeRecH;
					
					if (nodeRecP->allocType != Gen_Alloc_MULTI) {
						nodeRecH			= (Gen_AllocNodeRec **)TrackNewHandleClear(
							"multi disk map node rec", 
							sizeof(Gen_AllocNodeRec));
							
						if (nodeRecH == NULL) err = IC_Err_OUT_OF_MEMORY;
						
						if (!err) {
							**nodeRecH			= *nodeRecP;
							nodeRecP->entryP	= (CEntry *)nodeRecH;
							nodeRecP->allocType	= Gen_Alloc_MULTI;
						}
					}
					
					if (!err) {
						Gen_AllocNodeRec	empytRec;
						ulong				sizeL;
						
						structclr(empytRec);
						nodeRecH = (Gen_AllocNodeRec **)nodeRecP->entryP;
						
						err = TrackPtrAndHand(
							(Ptr)&empytRec, (Handle)nodeRecH, sizeof(Gen_AllocNodeRec));
						
						sizeL		= CountNodeRecH(nodeRecH);
						nodeRecP	= &(*nodeRecH)[sizeL - 1];
					}
				}
			}
			
			if (!err) {
				nodeRecP->allocType	= SpecifyAllocFileType(allocTypeS, entryP->i_fileType);
				nodeRecP->entryP	= entryP;
			}
		}
		
		if (!err) {
			if (allocTypeRecP->totalS) {
				char	str1AC[256];
				
				sprintf(str1AC, "Adding: %5hu + %5hu = %5hu, %s", 
					allocTypeRecP->totalS, 
					blockBitMapP->curSizeS, 
					allocTypeRecP->totalS + blockBitMapP->curSizeS, 
					ADFS_Str((ADFS_StrType)(ADFS_Str_ALLOC_NONE + allocTypeS)));
				
				ADFS_Log(str1AC);
				ADFS_Log("\n");
			}
		}
		
		if (!err) {
			blockBitMapP->curSizeS += allocTypeRecP->totalS;
		}
	}
	
	return err;
}

OSErr		CDisk::RemoveSectorsFromMap(
	CEntry				*entryP, 
	Gen_EntryAlloc		*entrySectorsP, 
	Gen_AllocMap		*blockBitMapP)
{
	OSErr					err = noErr;
	Gen_AllocType			allocTypeS;
	Gen_AllocNodeRec		*nodeRecP;
	Gen_AllocTypeRec		*allocTypeRecP;
	ushort					curSectorS;
	
	ASSERT(entrySectorsP->allocSize == blockBitMapP->allocSize);
	
	for (
		allocTypeS = Gen_Alloc_NONE; 
		!err && allocTypeS < Gen_Alloc_NUMTYPES;
		allocTypeS = (Gen_AllocType)(allocTypeS + 1)
	) {
		allocTypeRecP = &entrySectorsP->type[allocTypeS];
		
		for (
			curSectorS = 0; 
			!err && curSectorS < allocTypeRecP->totalS; 
			curSectorS++
		) {
			nodeRecP = GetNodeRec(
				blockBitMapP, allocTypeRecP, curSectorS);
			
			if (entryP->i_type == FSObject_DISK) {
				ASSERT(nodeRecP->allocType == Gen_Alloc_NONE);
			} else {
				ASSERT(nodeRecP->allocType != Gen_Alloc_NONE);
			}
			
			if (nodeRecP->allocType == Gen_Alloc_MULTI) {
				Gen_AllocNodeRec	*foundNodeRecP;
				Gen_AllocNodeRec	**nodeRecH			= (Gen_AllocNodeRec **)nodeRecP->entryP;
				ulong				curRecL, maxRecL	= CountNodeRecH(nodeRecH);
				
				ASSERT(maxRecL >= 2);
				
				for (curRecL = 0; curRecL < maxRecL; curRecL++) {
					foundNodeRecP = &(*nodeRecH)[curRecL];
					
					if (memcmp(foundNodeRecP, nodeRecP, sizeof(Gen_AllocNodeRec) == 0)) {
						break;
					}
				}
				
				ASSERT(curRecL < maxRecL);
				if (curRecL < maxRecL) {

					ASSERT(foundNodeRecP->entryP	== entryP
						&& foundNodeRecP->allocType	== allocTypeS);

					if (maxRecL == 2) {
						*nodeRecP = (*nodeRecH)[1 - curRecL];
						TrackDisposeHandle((Handle)nodeRecH);
						err = MemError();
					} else {
						if (curRecL + 1 < maxRecL) {
							memmove(
								foundNodeRecP, 
								foundNodeRecP + 1, 
								sizeof(Gen_AllocNodeRec) * (maxRecL - (curRecL + 1)));
						}

						err = TrackSetHandleSize((Handle)nodeRecH, (maxRecL - 1) * sizeof(Gen_AllocNodeRec));
					}
				}
			} else {
				nodeRecP->allocType = Gen_Alloc_NONE;
				nodeRecP->entryP	= NULL;
			}
		}
		
		if (!err) {
			if (allocTypeRecP->totalS) {
				char	str1AC[256];
				
				sprintf(str1AC, "Removing: %5hu + %5hu = %5hu, %s", 
					allocTypeRecP->totalS, 
					blockBitMapP->curSizeS, 
					allocTypeRecP->totalS + blockBitMapP->curSizeS, 
					ADFS_Str((ADFS_StrType)(ADFS_Str_ALLOC_NONE + allocTypeS)));
				
				ADFS_Log(str1AC);
				ADFS_Log("\n");
			}
		}
		
		if (!err) {
			blockBitMapP->curSizeS -= allocTypeRecP->totalS;
		}
	}
	
	return err;
}

static	OSErr		CopyAllocNodeRec(
	Gen_AllocNodeRec	*dstP, 
	Gen_AllocNodeRec	*srcP)
{
	OSErr		err = noErr;
	
	if (srcP->allocType != Gen_Alloc_MULTI) {
		*dstP = *srcP;
	} else {
		Gen_AllocNodeRec	**nodeRecH = (Gen_AllocNodeRec **)TrackNewHandleClear(
			"multi disk map node rec", GetHandleSize((Handle)srcP->entryP));
			
		if (nodeRecH == NULL) err = IC_Err_OUT_OF_MEMORY;
		
		if (!err) {
			**nodeRecH = **((Gen_AllocNodeRec **)srcP->entryP);
			
			dstP->allocType	= Gen_Alloc_MULTI;
			dstP->entryP	= (CEntry *)nodeRecH;
		}
	}
	
	return err;
}

void		CDisk::DisposeBlockMap(Gen_AllocMap *blockMapP, Boolean onlyMapB)
{
	if (blockMapP) {

		if (blockMapP->map.ptr) {
			Gen_AllocNodeRec		*nodeRecP;
			Gen_SectorSpec			curSectorSpec;
			Pro_BlockNum			blockNum;
			
			switch (blockMapP->allocSize) {

				case Gen_AllocSize_SECTORS: {
					FOR_EACH_TRACK_SECTOR(curSectorSpec) {
						nodeRecP	= &blockMapP->map.disk140A
							->track[curSectorSpec.track].sector[curSectorSpec.sector];
						
						if (nodeRecP->allocType == Gen_Alloc_MULTI) {
							TrackDisposeHandle((Handle)nodeRecP->entryP);
						}
					}
					break;
				}

				case Gen_AllocSize_SECTORS400: {
					FOR_EACH_TRACK_SECTOR400(curSectorSpec) {
						nodeRecP	= &blockMapP->map.disk400A
							->track[curSectorSpec.track].sector[curSectorSpec.sector];
						
						if (nodeRecP->allocType == Gen_Alloc_MULTI) {
							TrackDisposeHandle((Handle)nodeRecP->entryP);
						}
					}
					break;
				}

				case Gen_AllocSize_SHORT:
				case Gen_AllocSize_BYTE: {
					for (blockNum = 0; blockNum < blockMapP->maxSizeS; blockNum++) {
						nodeRecP	= &blockMapP->map.blockA[blockNum];

						if (nodeRecP->allocType == Gen_Alloc_MULTI) {
							TrackDisposeHandle((Handle)nodeRecP->entryP);
						}
					}
				}
			}

			TrackDisposePtr(blockMapP->map.ptr);
			blockMapP->map.ptr = NULL;
		}
		
		if (!onlyMapB) {
			TrackDisposePtr((Ptr)blockMapP);
		}
	}
}

OSErr		CDisk::FlushMemDisk(Boolean flushB)
{
	OSErr		err = noErr;
	
	if (flushB) {
		i_flushMemLevel++;
	} else {
		i_flushMemLevel--;
	}
	
	ASSERT(i_flushMemLevel <= 1);
	
	if (i_flushMemLevel == 1 && flushB == TRUE) {
		OSErr	err2;
		
		err = WriteImage(i_imageRec);
		
		err2 = Flush();
		if (!err) err = err2;

		err2 = UnCacheDiskImage();
		if (!err) err = err2;
		
	} else if (i_flushMemLevel == 0 && flushB == FALSE) {
		err = CacheDiskImage();
	}
	
	return err;
}

OSErr		CDisk::CacheDiskImage(void)
{
	OSErr		err = noErr;
	
	if (!IS_ImageRec_PHYSICAL(i_imageRec)) {
		
		if (ImageRec_VolRec(i_imageRec).image.refCountS++ == 0) {
			ASSERT(ImageRec_VolRec(i_imageRec).image.refNum == 0);
			err = FSpOpenDF(
				&ImageRec_VolRec(i_imageRec).image.fileSpec, 
				fsCurPerm, 
				&ImageRec_VolRec(i_imageRec).image.refNum);
			
			if (err) {
				ImageRec_VolRec(i_imageRec).image.refCountS--;
				ImageRec_VolRec(i_imageRec).image.refNum = 0;
			}
		}
	}
	
	return err;
}

OSErr		CDisk::UnCacheDiskImage(void)
{
	OSErr	err = noErr;
	
	if (!IS_ImageRec_PHYSICAL(i_imageRec)) {
		if (--ImageRec_VolRec(i_imageRec).image.refCountS == 0) {
			ASSERT(ImageRec_VolRec(i_imageRec).image.refNum != 0);
			
			if (ImageRec_VolRec(i_imageRec).image.refNum) {
				OSErr		err2;
				
				err = FSFlushFile(ImageRec_VolRec(i_imageRec).image.refNum);
				err2 = FSClose(ImageRec_VolRec(i_imageRec).image.refNum);
				if (!err) err = err2;
				
				ImageRec_VolRec(i_imageRec).image.refNum = 0;
			}
		}
	}
	
	return err;
}

//	gets prodos equivalent file type
ushort			CDisk::GetFileType_ProEquiv(void)
{
	return 0x0F;	//	Pro_FileType_DIR;
}

OSErr			CDisk::DragReceiveFlavor(
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	void			*data)
{
	return i_rootDir.gen->DragReceiveFlavor(theDrag, itemRef, flavorType, data);
}

OSErr			CDisk::CanAcceptFlavor(
	DragReference	theDrag, 
	ItemReference	itemRef, 
	FlavorType		flavorType, 
	Boolean			*goodFlavorB)
{
	return i_rootDir.gen->CanAcceptFlavor(theDrag, itemRef, flavorType, goodFlavorB);
}

char		*CDisk::GetWhereString(char *buf256)
{
	GetName(buf256);
	return buf256;
}

char		*CDisk::GetStorageStr(char *buf256)
{
	buf256[0] = 0;

	if (IS_ImageRec_PHYSICAL(i_imageRec)) {
		sprintf(buf256, "Physical floppy drive %d, ", (int)ImageRec_VolRec(i_imageRec).phys.driveNumS);
	} else {
		if (IS_ImageRec_DiskCopy(i_imageRec)) {
			strcat(buf256, "Disk Copy,  ");
		} else if (IS_ImageRec_2img(i_imageRec)) {
			strcat(buf256, "2IMG,  ");
		}
		
		if (IS_ImageRec_NIB(i_imageRec)) {
			strcat(buf256, "Nibblized, ");
		}
	}
	
	strcat_FSType(ImageRec_OrigOrder(i_imageRec), buf256);
	strcat(buf256, " Sector Order");
	return buf256;
}

Boolean		CDisk::SetDiskFormat(
	ND_DiscFormatRec *formatP)
{
	OSErr				err					= noErr;
	Boolean				success				= TRUE;
	Boolean				changedB			= FALSE;
	ND_DiskFileType		oldFileType			= ND_DiskTypeToFileType(ImageRec_DiskType(i_imageRec));
	Boolean				sectorOrderChangedB	= ImageRec_OrigOrder(i_imageRec) != formatP->sectorOrder;
	
	if (IS_ImageRec_IN_MEMORY(i_imageRec)) {
		Boolean		was_nibblizedB = IS_ImageRec_NIB(i_imageRec);
		
		if (
			sectorOrderChangedB
			|| was_nibblizedB != formatP->nibblizedB
		) {
			changedB = TRUE;
			
			if (was_nibblizedB != formatP->nibblizedB) {
				if (formatP->nibblizedB) {
					if (ImageRec_DiskType(i_imageRec) == DiskType_inMemory_Raw) {
						ImageRec_DiskType(i_imageRec) = DiskType_inMemory_Nib;
					} else {
						ImageRec_VolRec(i_imageRec).image.header.twoimg.format = IMG_Format_NIB;
					}
				} else {
					if (ImageRec_DiskType(i_imageRec) == DiskType_inMemory_Nib) {
						ImageRec_DiskType(i_imageRec) = DiskType_inMemory_Raw;
					} else {
						ASSERT(ImageRec_DiskType(i_imageRec) == DiskType_inMemory_2img);
						
						switch (ImageRec_OrigOrder(i_imageRec)) {

							case FSType_DOS: {
								ImageRec_VolRec(i_imageRec).image.header.twoimg.format = IMG_Format_DOS;
								break;
							}

							case FSType_PRO:
							case FSType_PAS: {
								ImageRec_VolRec(i_imageRec).image.header.twoimg.format = IMG_Format_PRO;
								break;
							}
							
							case FSType_CPM: {
								ImageRec_VolRec(i_imageRec).image.header.twoimg.format = IMG_Format_CPM;
								break;
							}

							case FSType_C2P: {
								ImageRec_VolRec(i_imageRec).image.header.twoimg.format = IMG_Format_C2P;
								break;
							}	 

							default: {
								ASSERT(0);
								break;
							}
						}
					}
				}
			}
		}
	}

	if (success && formatP->diskFileType != oldFileType) {
		long		sofOffset = 0;

		switch (oldFileType) {
			
			default: {
				ReportErrorStr(-1, "Bizzarre file format conversion (from).");
				success = FALSE;
				break;
			}

			case ND_Format_RAW: {
				sofOffset -= 0;
				break;
			}

			case ND_Format_2IMG: {
				sofOffset -= sizeof(Disk_2IMG_Header);
				break;
			}

			case ND_Format_DISK_COPY: {
				sofOffset -= sizeof(Disk_DiskCopy_Header);
				break;
			}
		}

		switch (formatP->diskFileType) {
			
			default: {
				ReportErrorStr(-1, "Bizzarre file format conversion (to).");
				success = FALSE;
				break;
			}

			case ND_Format_RAW: {
				if (IS_ImageRec_IN_MEMORY(i_imageRec)) {
					ImageRec_DiskType(i_imageRec) = DiskType_inMemory_Raw;
				} else {
					ImageRec_DiskType(i_imageRec) = DiskType_onDisk_Raw;
				}
				sofOffset += 0;
				break;
			}

			case ND_Format_2IMG: {
				if (IS_ImageRec_IN_MEMORY(i_imageRec)) {
					ImageRec_DiskType(i_imageRec) = DiskType_inMemory_2img;
				} else {
					ImageRec_DiskType(i_imageRec) = DiskType_onDisk_2img;
				}

				sofOffset += sizeof(Disk_2IMG_Header);
				break;
			}

			case ND_Format_DISK_COPY: {
				if (IS_ImageRec_IN_MEMORY(i_imageRec)) {
					ImageRec_DiskType(i_imageRec) = DiskType_inMemory_DiskCopy;
				} else {
					ImageRec_DiskType(i_imageRec) = DiskType_onDisk_DiskCopy;
				}

				sofOffset += sizeof(Disk_DiskCopy_Header);
				break;
			}
		}
		
		if (success) {
			Str255		nameStr;
			ulong		imageSize;
			
			changedB = TRUE;
			
			//	negative: add abs(that many bytes) to start of file
			//	positive: subtract that many bytes from start of file
			err = FSpSetSOF(&ImageRec_VolRec(i_imageRec).image.fileSpec, -sofOffset);
			if (err) {
				ReportErrorStr(-1, "Error setting start of file");
				success = FALSE;
			}
			
			if (success) {
				ImageRec_OrigOrder(i_imageRec) = (FSType)formatP->sectorOrder;
		
				GetName((char *)nameStr);
				CopyCStringToPascal((char *)nameStr, nameStr);
				
				if (formatP->nibblizedB) {
					imageSize = sizeof(Nib_Disk);
				} else {
					imageSize = GetPhysicalSize();
				}
				
				FillInImageRecHeader(
					nameStr, 
					imageSize, 
					formatP->nibblizedB, 
					i_imageRec);
			}
		}
	}
	
	if (success && changedB) {
		ulong				imageSize = GetPhysicalSize();
		CDialogGetInfo		*getInfoP = GetGetInfo();
		
		ImageRec_OrigOrder(i_imageRec)		= (FSType)formatP->sectorOrder;

		err = WriteImage(i_imageRec);

		if (!err && ImageRec_DiskType(i_imageRec) == DiskType_onDisk_Raw) {
			/*
				yeah it's strange, i'm setting the EOF of the file
				from 2 different places, i've got the real one here
				in CDisk (where I think this all belongs)
				and another one in IC_FileIO, where it's called
				every time we write to a disk, seems overkill.
				only needs to happen when changing the size of the
				disk (like now) or expanding the disk (when creating
				a new large prodos volume)
				
				but everyone gets set in IC_FileIO except the 
				onDisk_Rawtype, which is set here
			*/

			
			if (ImageRec_VolRec(i_imageRec).image.refNum) {
				err = SetEOF(ImageRec_VolRec(i_imageRec).image.refNum, imageSize);
			} else {
				err = FSpSetEOF(&ImageRec_VolRec(i_imageRec).image.fileSpec, imageSize);
			}
		}
		
		UpdateFileType(i_imageRec, formatP, imageSize);
		InvalStat(ADFS_Stat_ICON);
		
		if (getInfoP && getInfoP->i_entryP == this) {
			getInfoP->InvalDialogItem(ADFS_GetInfo_VERB_STORAGE);
		}
		
		if (sectorOrderChangedB) {
			if (i_diskMapP) {
				i_diskMapP->Refresh();
			}
		}
	}

	return success;
}

void		CDisk::DoSectorOrderDlg(void)
{
	ADFS_NewDiskRec		diskRec;

	structclr(diskRec);
	
	diskRec.diskP = this;
	
	ImageRecToDiskFormatRec(i_imageRec, &diskRec.format);
	
	diskRec.osType = i_imageRec->osType;
	
	if (IS_ImageRec_IN_MEMORY(i_imageRec)) {
		diskRec.bytesOnDiskL = Gen_kBytesPerDisk;
		
		if (i_imageRec->partition.writeLengthL <= 73728) {
			diskRec.osType = FSType_HYB;
		}
	}
	
	ShowNewDisk(&diskRec);
}

OSErr		CDisk::ZeroUnused(void)
{
	return noErr;
}

ulong		CDisk::CalcBytesUsedByFile(ulong fileSize)
{
	return 0;
}

ulong		CDisk::GetVolumeMaxFileSize(ushort pro_fileTypeS)
{
	return 0xFFFFFFFF;
}

OSErr		CDisk::DuplicateToTemp(void)
{
	OSErr		err			= noErr;
	CCopyTree	*copyTreeP	= NULL;
	FSSpec		folderSpec;
	
	if (!err) err = FSpCreateTempFile(
		ImageRec_VolRec(i_imageRec).image.fileSpec.vRefNum, 
		ImageRec_VolRec(i_imageRec).image.fileSpec.name, 
		GetAppCreator(), 
		kFirstMagicBusyFiletype, 
		&i_tempFileSpec);

	if (!err) err = FSpGetParentFolder(
		&i_tempFileSpec, &folderSpec);

	if (!err) err = GetNewCopyTree(
		CCT_Copy_FSSPEC, (Ptr)&folderSpec, &copyTreeP);
	
	if (!err) {
		if (!err) err = copyTreeP->AddEntry(
			NULL, CCT_Copy_FSSPEC, 
			(Ptr)&ImageRec_VolRec(i_imageRec).image.fileSpec, NULL);
		
		if (!err) err = copyTreeP->Copy(FALSE);

		copyTreeP->Dispose();
		copyTreeP = NULL;
	}

//	if (!err) err = FSMakeFSSpec(
//		folderSpec.vRefNum, folderID, 
//		ImageRec_VolRec(i_imageRec).image.fileSpec.name, &i_tempFileSpec);

	return err;
}

OSErr		CDisk::ExchangeTemp(void)
{
	OSErr	err  = noErr;
	
	err = FSpExchangeFiles(&i_tempFileSpec, &ImageRec_VolRec(i_imageRec).image.fileSpec);
	
	if (err) ReportOSErr(err);
	
	return err;
}
		
OSErr		CDisk::DeleteTemp(void)
{
	OSErr	err  = noErr;
	
	err = FSpDelete(&i_tempFileSpec);
	structclr(i_tempFileSpec);
	return noErr;
}

OSErr		CDisk::Optimize(void)
{
//	Boolean		old_translatedB = IsCopyTranslated();
	OSErr		err				= noErr, err2;
//	Boolean		badErrB			= FALSE;
	CCopyTree	*copyDestP		= NULL;
	CCopyTree	*copyTreeP		= NULL;
	Boolean		was_show_deletedB = i_show_deletedB;
	
	if (was_show_deletedB) {
		ToggleDeletedFiles();
	}
	
	SetCopyTranslated(FALSE);

	// make a new file in the temp folder, that is a 
	// copy of this file
	if (!err) err = DuplicateToTemp();
	
	if (!err) {
		err = FlushMemDisk(FALSE);
		
		if (!err) {
			// new copy tree, dest is this CDisk (actually it's root dir)
			// sources added by meta tree
			if (!err) err = GetNewCopyTree(
				CCT_Copy_ENTRY, (Ptr)i_rootDir.gen, &copyDestP);
			
			//	new meta tree, dest is above copy tree
			//	source is this CDisk
			if (!err) err = GetNewCopyTree(
				CCT_Copy_META_TREE, (Ptr)copyDestP, &copyTreeP);
			
			if (!err) {
				long			curEntryL, numEntriesL = i_rootDir.gen->CountEntries();
				
				for (curEntryL = 0; !err && curEntryL < numEntriesL; curEntryL++) {
					err = copyTreeP->AddEntry(
						NULL, CCT_Copy_ENTRY, 
						(Ptr)i_rootDir.gen->GetIndEntry(curEntryL), NULL);
				}
				
				//	hope we don't run out of memory
				if (!err) err = copyTreeP->Copy(FALSE);

				copyTreeP->Dispose();
				copyTreeP = NULL;
			}
			
			if (!err) err = Erase(FALSE);
			if (!err) err = copyDestP->Copy(FALSE);
			
			err2 = FlushMemDisk(TRUE);
			if (!err) err = err2;

			//	if there was any problem at all, go back to orig file
			if (err) err2 = ExchangeTemp();
		}
		
		err2 = DeleteTemp();
		if (!err) err = err2;

		if (copyDestP) copyDestP->Dispose();
	}
	
	SetCopyTranslated((**gPrefsH).detokenizeB);
	
	//	USE THIZ from now on
	CDisk		*thiz		= this;

	if (err) {
		Boolean		mapB		= i_diskMapP != NULL;
		
		err = Remount(&thiz);

		if (!err && mapB) {
			thiz->Map();
		}
	}

	if (was_show_deletedB) {
		thiz->ToggleDeletedFiles();
	}

	return err;
}

OSErr		CDisk::Remount(CDisk **diskPP0)
{
	OSErr			err				= noErr;
	DiskDeviceRec	*deviceP		= i_imageRec->deviceP;
	PartitionRec	partitionRec	= i_imageRec->partition;
	CDisk			*diskP			= NULL;
	
	//	make sure device doesn't get disposed / ejected
	deviceP->refCountS++;
	
	Dispose();	//	will decrement the refcount

	//	but decrement again back to zero and start fresh
	deviceP->refCountS--;

	err = gDesktop->MountPartition(deviceP, &partitionRec, &diskP);
	
	if (err && deviceP->refCountS == 0) {
		TrackDisposePtr((Ptr)deviceP);
	} else {
		diskP->i_imageRec->partition = partitionRec;

		if (diskPP0) {
			*diskPP0 = diskP;
		}
	}
	
	return err;
}

OSErr		CDisk::Erase(Boolean confirmB)
{
	OSErr		err = noErr;
	char		bufAC[256];
	
	GetName(bufAC);

	ResetEraseDiskDialog();

	if (
		!confirmB
		|| DoEraseDiskDialog(bufAC) == kDlog_EraseDisk_ItemID_ERASE
	) {
		err = FlushMemDisk(FALSE);
		
		if (!err) {
			OSErr		err2;
			
			err = i_rootDir.gen->Delete(FALSE, NULL);
			if (!err) err = ZeroUnused();
			
			err2 = FlushMemDisk(TRUE);
			if (!err) err = err2;
		}
	}
	
	return err;
}

OSErr		CDisk::Duplicate(void)
{
//	uniqify the file on disk
//	copy the file on disk to unique name
//	mount new file
	return noErr;
}

short		CDisk::SkewSector(short sectorS, Boolean reverseB)
{
	ASSERT(!reverseB);
	
	if (reverseB) {
		IC_ConvertSector(ImageRec_OrigOrder(i_imageRec), i_imageRec->curOrder, &sectorS);
	} else {
		IC_ConvertSector(i_imageRec->curOrder, ImageRec_OrigOrder(i_imageRec), &sectorS);
	}

	return sectorS;
}

ushort					CDisk::GetSectorsPerBlock(void)
{
	ASSERT("You can't call this function!" == NULL);
	return 1;
}

ushort					CDisk::GetBlocksPerTrack(void)
{
	ASSERT("You can't call this function!" == NULL);
	return 1;
}

Gen_AllocSizeType		CDisk::GetAllocSize(void)
{
	return Gen_AllocSize_SHORT;
}

ushort		CDisk::TrackSectorToBlock(short trackS, short sectorS)
{
	return (trackS * GetBlocksPerTrack()) + (sectorS / GetSectorsPerBlock());
}

void		CDisk::BlockToTrackSectors(
	ushort	block, 
	ushort	*trackS, 
	ushort	sectorA[])
{
	ushort		blockIndexS = (block % GetBlocksPerTrack()) * GetSectorsPerBlock();
	short		sectorS;
	
	*trackS		= block / GetBlocksPerTrack();
	
	for (sectorS = 0; sectorS < GetSectorsPerBlock(); sectorS++) {
		sectorA[sectorS] = blockIndexS + sectorS;
	}
}

OSErr		CDisk::EntryBlocksToSectors(Gen_EntryAlloc	*sectorListP)
{
	OSErr			err = noErr;
	ushort			allocTypeS, curBlockS;
	ushort			trackS, *sectorA;
	Gen_Alloc		blockNum;
	Gen_SectorSpec	*sectorNumP;
	ushort			totalS;

	sectorA = (ushort *)TrackNewPtrClear(
		"bit map sectors", sizeof(ushort) * GetSectorsPerBlock());
	if (sectorA == NULL) err = IC_Err_OUT_OF_MEMORY;
	
	if (!err) {
		for (
			allocTypeS = Gen_Alloc_NONE;
			!err && allocTypeS < Gen_Alloc_NUMTYPES; 
			allocTypeS++
		) {
			totalS		= sectorListP->type[allocTypeS].totalS;
			
			if (totalS) {
				blockNum	= sectorListP->type[allocTypeS].u;

				sectorNumP = (Gen_SectorSpec *)TrackNewPtrClear(
					"bit map sectors", sizeof(Gen_SectorSpec) * totalS * GetSectorsPerBlock());
				if (sectorNumP == NULL) err = IC_Err_OUT_OF_MEMORY;
				
				if (!err) {
					sectorListP->type[allocTypeS].totalS		= totalS * GetSectorsPerBlock();
					sectorListP->type[allocTypeS].u.sectorsA	= sectorNumP;
					
					for (
						curBlockS = 0; 
						!err && curBlockS < totalS;
						curBlockS++
					) {
						ushort		curBlockIndexS = curBlockS * GetSectorsPerBlock();
						ushort		sectorS;
						ushort		blockS;
						
						switch (GetAllocSize()) {
						
							case Gen_AllocSize_SHORT: {
								blockS = blockNum.short_blocksA[curBlockS];
								break;
							}

							case Gen_AllocSize_BYTE: {
								blockS = blockNum.byte_blocksA[curBlockS];
								break;
							}

							default: {
								ASSERT("you got a problem with that?" == NULL);
								break;
							}
						}

						BlockToTrackSectors(
							blockS, &trackS, sectorA);
						
						for (sectorS = 0; sectorS < GetSectorsPerBlock(); sectorS++) {
							sectorNumP[curBlockIndexS + sectorS].track	= trackS;				
							sectorNumP[curBlockIndexS + sectorS].sector	= sectorA[sectorS];
						}
					}
				
					TrackDisposePtr(blockNum.ptr);
				}
			}
		}
		
		TrackDisposePtr((Ptr)sectorA);
	}
	
	return err;
}

OSErr		CDisk::GetBlockMap(Gen_AllocMap **blockMapH)
{
	OSErr		err = noErr;
	
	*blockMapH	= (Gen_AllocMap *)TrackNewPtrClear(
		"block map header", sizeof(Gen_AllocMap));

	if (*blockMapH == NULL) {
		err = IC_Err_OUT_OF_MEMORY;
	} else {
		(**blockMapH).allocSize		= GetAllocSize();
		(**blockMapH).maxSizeS		= i_blocksInVolume;
		(**blockMapH).curSizeS		= 0;
		(**blockMapH).map.ptr		= TrackNewPtrClear(
			"block map array", sizeof(Gen_AllocNodeRec) * (**blockMapH).maxSizeS);

		if ((**blockMapH).map.ptr == NULL) {
			DisposeBlockMap(*blockMapH);
			err = IC_Err_OUT_OF_MEMORY;
		} else {
			CEntry		*entryP;
			
			UpdateGlobals();
			
			entryP = i_rootDir.gen->GetIndEntry(0);
			
			//	do the items in the disk (if any)
			if (entryP) {
				if (!err) err = GetEntryTopic(entryP)->O_ApplyToItems(
					O_Iterate_ALL, 
					ADFS_O_CB_COLLECT_BITMAP, 
					(O_CBDataP *)*blockMapH, 
					TRUE,	//	only do self (not sisters)
					TRUE);	//	always go deep
			}
			
			//	and of course, do the disk itself (vol bitmap, TOC etc)
			if (!err) {
				i_mapRec.map = (**blockMapH).map;
				
				err = EntryDispatchCB(
					ADFS_O_CB_COLLECT_BITMAP, 
					(O_CBDataP)*blockMapH);
				
				i_mapRec.map.ptr = NULL;
			}
		}
	}
	
	return err;
}

OSErr		CDisk::GetSectorMap(Gen_AllocMap **blockMapH)
{
	OSErr		err = noErr;
	
	if (IS_ImageRec_IN_MEMORY(i_imageRec)) {
	
		if (!err) err = GetBlockMap(blockMapH);
		if (!err) {
			short				trackS, sectorS;
			Gen_AllocNodeRec	*dstP;
			ushort				blockIndexS;
			Gen_DiskBitMap		*bitMapP = (Gen_DiskBitMap *)TrackNewPtrClear(
				"sector map array", sizeof(Gen_DiskBitMap));
			
			if (!bitMapP) err = IC_Err_OUT_OF_MEMORY;
			
			if (!err) {
				for (trackS = 0; !err && trackS < Gen_kTracksPerDisk; trackS++) {
					for (sectorS = 0; !err && sectorS < Gen_kSectorsPerTrack; sectorS++) {
						dstP = &bitMapP->track[trackS].sector[sectorS];
						
						blockIndexS = TrackSectorToBlock(trackS, sectorS);
						
						if (blockIndexS >= (**blockMapH).curSizeS) {
							dstP->allocType = Gen_Alloc_MYSTERY;
							dstP->entryP	= bitMapP->track[0].sector[0].entryP;
						} else {
							err = CopyAllocNodeRec(
							 	dstP, &(**blockMapH).map.blockA[blockIndexS]);
						}
					}
				}
			}
			
			DisposeBlockMap(*blockMapH, TRUE);
			(**blockMapH).map.disk140A	= bitMapP;

			if (!err) {	
				(**blockMapH).allocSize		= Gen_AllocSize_SECTORS;
				(**blockMapH).maxSizeS		= (ulong)Gen_kTracksPerDisk * (ulong)Gen_kSectorsPerTrack;
			} else {
				DisposeBlockMap(*blockMapH);
				*blockMapH = NULL;
			}
		}
	} else {
		err = IC_Err_NOT_A_SECTOR_DEVICE;
	}
	
	if (err) ReportError(err);

	return err;
}

Boolean			CDisk::IsLocked(void)
{
	Boolean		isLockedB	= _inherited::IsLocked();

	if (!isLockedB) {
		Gen_AccessBits		bits;
		
		GetAccessBits(&bits);
		isLockedB = !bits.writeEnable;
	}
	
	return isLockedB;
}


static	Boolean		HasFloppyDrive(void)
{
	OSErr		err		= noErr;
	Boolean		gotItB	= FALSE;
	
	#ifdef __68k__
		long		result	= 1;
		
		err = Gestalt(gestaltFloppyAttr, &result);
	#endif
	
	if (!err) {
		//  gestaltFloppyAttr             = FOUR_CHAR_CODE('flpy'), /* Floppy disk drive/driver attributes */
		//  gestaltFloppyIsMFMOnly        = 0,    /* Floppy driver only supports MFM disk formats (ie: NOT 800k disks) */
		//  gestaltFloppyIsManualEject    = 1,    /* Floppy drive, driver, and file system are in manual-eject mode */
		//  gestaltFloppyUsesDiskInPlace  = 2     /* Floppy drive must have special DISK-IN-PLACE output; standard DISK-CHANGED not used */

		gotItB = TRUE;
	}
	
	return gotItB;
}

void		CDisk::UpdateMenus(void)
{
	EnableCommand(cmdGetInfo);
	EnableCommand(cmdShowDeleteFiles);
	EnableCommand(cmdEraseDisk);
	EnableCommand(cmdPutAway);
	EnableCommand(cmdZeroUnused);
	EnableCommand(cmdMapDisk);
	
	if (
		i_imageRec->osType == FSType_DOS
		&& !IS_ImageRec_IN_MEMORY(i_imageRec)
	) {
//		EnableCommand(cmdFlushDisk);
	}
	
	if (!IS_ImageRec_PHYSICAL(i_imageRec)) {
		EnableCommand(cmdSectorOrder);
		
		//	not for phisical cuz DuplicateToTemp doesn't know to
		//	make an image from the disk as a backup
		EnableCommand(cmdOptimizeDisk);
	}
	

	if (HasFloppyDrive()) {
		Gen_BlockNum	blocksS = GetTotalBlocks();
	
		if (
			!IS_ImageRec_IN_MEMORY(i_imageRec)
			&& !IS_ImageRec_PHYSICAL(i_imageRec)
			&& (
				i_imageRec->osType == FSType_PRO
				|| i_imageRec->osType == FSType_PAS
			) && (
				blocksS == (800 * 2)
				|| blocksS == (720 * 2)
				|| blocksS == (1440 * 2)
			)
		) {
			EnableCommand(cmdImageToDisk);
		}
	}
	
	if (IS_ImageRec_PHYSICAL(i_imageRec)) {
		EnableCommand(cmdDiskToImage);
	}
}

Boolean		CDisk::DoCommand(long command)
{
	Boolean		handledB = TRUE;
	
	switch (command) {
		
		case cmdGetInfo: {
			ShowGetInfo(this, FALSE);
			break;
		}

		case cmdDiskToImage: {
			DiskToImage();
			break;
		}
		
		case cmdImageToDisk: {
			ImageToDisk();
			break;
		}
		
//		case cmdFlushDisk: {
//			Flush();
//			break;
//		}
		
		case cmdMapDisk: {
			Map();
			break;
		}
		
		case cmdOptimizeDisk: {
			if (IsLocked()) {
				ReportError(IC_Err_DISK_LOCKED);
			} else {
				Optimize();
			}
			break;
		}
		
		case cmdZeroUnused: {
			if (IsLocked()) {
				ReportError(IC_Err_DISK_LOCKED);
			} else {
				Boolean		was_show_deletedB = i_show_deletedB;
				
				if (was_show_deletedB) {
					ToggleDeletedFiles();
				}

				ZeroUnused();

				if (was_show_deletedB) {
					ToggleDeletedFiles();
				}
			}
			break;
		}
		
		case cmdSectorOrder: {
			if (IsLocked()) {
				ReportError(IC_Err_DISK_LOCKED);
			} else {
				DoSectorOrderDlg();
			}
			break;
		}
		
		case cmdEraseDisk: {
			if (IsLocked()) {
				ReportError(IC_Err_DISK_LOCKED);
			} else {
				Erase(TRUE);
			}
			break;
		}
		
		case cmdShowDeleteFiles: {
			(void)ToggleDeletedFiles();
			break;
		}
		
		case cmdPutAway: {
			Dispose();
			break;
		}

		default: {
			handledB = FALSE;
			break;
		}
	}

	return handledB;
}

Boolean		CDisk::SupportsForks(void)
{
	return FALSE;
}


ulong		CDisk::GetTotalBlocks(void)
{
	return i_blocksInVolume;
}

OSErr			CDisk::SetGenericBlock(ushort blockNumS, Gen_Block *blockP)
{
	return ASSERT(0);
}

OSErr			CDisk::GetGenericBlock(ushort blockNumS, Gen_Block **blockP)
{
	return ASSERT(0);
}

CDisk	*g_srcDiskP;
static	Boolean	DiskToImageCB(ADFS_NewDiskRec *newDiskRecP)
{
	Boolean		successB = NewDisk_CB(newDiskRecP);
	
	if (successB) {
		if (
			g_srcDiskP->i_imageRec->osType == FSType_PRO
			|| g_srcDiskP->i_imageRec->osType == FSType_PAS
		) {
			OSErr			err = noErr;
			char			srcNameAC[256], dstNameAC[256];
			Gen_Block		*blockA;
			Gen_BlockNum	curBlockS, maxBlockS, trackBlockS;
			CDisk			*srcDiskP = g_srcDiskP, 
							*dstDiskP = newDiskRecP->diskP;					
			CDialogCopy		*copyDialogP = ShowCopyDialog();

			blockA = (Gen_Block *)TrackNewPtrClear(
				"disk image track buffer", 
				sizeof(Gen_Block) * kFloppy_BlocksPerTrack);
			if (blockA == NULL) {
				err = 1;
				ReportErrorStr(err, "Out of memory allocating disk image track buffer");
			} else {
				maxBlockS = srcDiskP->GetTotalBlocks();
				ASSERT(maxBlockS == dstDiskP->GetTotalBlocks());
				
				copyDialogP->SetItemRemain(1);
				copyDialogP->SetMaxProgress(maxBlockS * Gen_kBytesPerBlock);

				CopyPascalStringToC(ImageRec_VolRec(dstDiskP->i_imageRec).image.fileSpec.name, dstNameAC);
				copyDialogP->SetProgStrings(
					"Disk to Image", 
					srcDiskP->GetName(srcNameAC), 
					dstNameAC);

				for (curBlockS = 0; !err && curBlockS < maxBlockS; curBlockS += kFloppy_BlocksPerTrack) {
					if (!err) err = GetPhysicalTrack(&ImageRec_VolRec(srcDiskP->i_imageRec).phys, curBlockS, blockA);

					if (!err) {
						for (trackBlockS = 0; !err && trackBlockS < kFloppy_BlocksPerTrack; trackBlockS++) {
							if (!err) err = dstDiskP->SetGenericBlock(curBlockS + trackBlockS, &blockA[trackBlockS]);
						}

						if (!err) err = copyDialogP->SetProgress((curBlockS + kFloppy_BlocksPerTrack) * Gen_kBytesPerBlock);
					}
				}
			}
			
			copyDialogP->HideCopyDialog();

			//	deal with partitions here

			if (err) {
				ReportError(err);
				dstDiskP->Dispose();
			} else {
				dstDiskP->Remount();
			}
		}
	}
	
	return successB;
}

void		CDisk::DiskToImage(void)
{
	ADFS_NewDiskRec		diskRec;

	structclr(diskRec);
	diskRec = (**gPrefsH).newDiskRec;

	diskRec.diskP			= this;

	diskRec.bytesOnDiskL	= GetPhysicalSize();
	diskRec.disk2imgB		= TRUE;
	diskRec.bootableB		= FALSE;
	diskRec.customSizeB		= FALSE;
	diskRec.osType			= i_imageRec->osType;

	diskRec.NewDiskDoneCB	= DiskToImageCB;
	g_srcDiskP				= this;
	
	ShowNewDisk(&diskRec);
}

OSErr		CDisk::EntryPane_CB_EntryArray(
	TA_IterateType taType, TA_IterateData *cbData)
{
	OSErr		err = noErr;
	
	switch (taType) {
		
		case TA_Iterate_SET_SHOW_DELETED: {
			i_prev_show_deletedB = i_show_deletedB;
			
			if (!i_show_deletedB) {
				i_show_deletedB = TRUE;
				err = i_rootDir.gen->ToggleDeletedFiles();
			}
			break;
		}
		
		case TA_Iterate_RESTORE_SHOW_DELETED: {
			if (i_show_deletedB != i_prev_show_deletedB) {
				i_show_deletedB = i_prev_show_deletedB;
				err = i_rootDir.gen->ToggleDeletedFiles();
			}
			break;
		}
		
		case TA_Iterate_TOGGLE_SHOW_DELETED: {
			ToggleDeletedFiles();
			break;
		}

		case TA_Iterate_DO_COMMAND: {
			if (IsSelected()) {
				DoCommand(cbData->commandL);
			}
			break;
		}

		case TA_Iterate_UNMOUNT_DRIVE: {
			short	*driveNumSP = (short *)cbData;
			
			if (
				IS_ImageRec_PHYSICAL(i_imageRec)
				&& ImageRec_VolRec(i_imageRec).phys.driveNumS == *driveNumSP
			) {
				Dispose();
				err = 1;
			}
			break;
		}

		default: {
			err = _inherited::EntryPane_CB_EntryArray(taType, cbData);
			break;
		}
	}
	
	return err;
}

#define		kFloppyDriveStaticNum		1

void		CDisk::ImageToDisk(void)
{
	short		driveNumS;
	
	gDesktop->i_desktopWindow->UnMountDrive(kFloppyDriveStaticNum);
	
	ResetInsertDiskDialog(kDlog_InsertDisk_ItemID_NONE);
	driveNumS = DoInsertDiskDialog(kFloppyDriveStaticNum);
	
	if (driveNumS == kFloppyDriveStaticNum) {
		PhysVolumeRec		volRec;
		OSErr				err = noErr;

		err = GetVolRec(driveNumS, &volRec);
		//	also sets lock bit
		if (!err) err = GetVolBlocks(&volRec);
		
		if (!err) {
			char				verbAC[256];
			Dlog_ItemIDType		dlogAnswerS;
			Gen_BlockNum		maxBlockS;
			
			maxBlockS = GetTotalBlocks();
			
			if (maxBlockS != volRec.blocksS) {
				char	verbAC[256];
				
				sprintf(
					verbAC, 
					"The image you selected has %d blocks, while the " \
						"floppy disk you inserted has %d blocks.", 
					(int)maxBlockS, 
					(int)volRec.blocksS);
				
				ReportErrorStr(-1, verbAC);

				EjectFloppy(&volRec);
			} else {
				sprintf(verbAC, 
					"Are you sure you want to completely over-write the " \
						"contents of the floppy disk in drive %d?", 
					driveNumS);

				dlogAnswerS = Quick3Button(
					"Image Disk", 
					verbAC, 
					"Write",	Dlog_Action_NONE, 
					NULL,		Dlog_Action_NONE, 
					"Cancel",	Dlog_Action_DEFAULT); 
				
				if (dlogAnswerS == kDlog_3Button_ItemID_BUTTON_1) {
					OSErr			err = noErr;
					char			srcNameAC[256], dstNameAC[256];
					CDialogCopy		*copyDialogP = ShowCopyDialog();
					Gen_BlockNum	curBlockS, trackBlockS;
					Gen_Block		*blockP;
					Gen_Block		*blockA;
					
					blockA = (Gen_Block *)TrackNewPtrClear(
						"disk image track buffer", 
						sizeof(Gen_Block) * kFloppy_BlocksPerTrack);
					if (blockA == NULL) {
						err = 1;
						ReportErrorStr(err, "Out of memory allocating disk image track buffer");
					} else {
						copyDialogP->SetItemRemain(0);
						copyDialogP->SetMaxProgress(maxBlockS * Gen_kBytesPerBlock);

						sprintf(dstNameAC, "Floppy Drive %d", (int)driveNumS);
						
						copyDialogP->SetProgStrings(
							"Image to Disk", 
							GetName(srcNameAC), 
							dstNameAC);

						for (curBlockS = 0; !err && curBlockS < maxBlockS; curBlockS += kFloppy_BlocksPerTrack) {
						
							for (trackBlockS = 0; !err && trackBlockS < kFloppy_BlocksPerTrack; trackBlockS++) {
								if (!err) err = GetGenericBlock(curBlockS + trackBlockS, &blockP);
								if (!err) blockA[trackBlockS] = *blockP;
							}
							
							if (!err) {
								if (!err) err = SetPhysicalTrack(&volRec, curBlockS, blockA);
								if (!err) err = copyDialogP->SetProgress(curBlockS * Gen_kBytesPerBlock);
							}
						}
					}
					
					copyDialogP->HideCopyDialog();

					if (err) {
						ReportError(err);
					} else {
						DiskDeviceRec	*deviceP;
						
						err = NewDeviceRec(
							DiskType_onDisk_Physical, &volRec, &deviceP);
						
						if (!err) {
							err = gDesktop->MountDisk(deviceP);
							
							if (err && deviceP->refCountS == 0) {
								TrackDisposePtr((Ptr)deviceP);
							}
						}
					}

					if (err) {
						(void)EjectFloppy(&volRec);
					}
				}
			}
		}
	}
}

void		CDisk::UnCacheFolderSizes(void)
{
	i_physical_sizeL	= 0;
	i_logical_sizeL		= 0;

	if (i_topicRef.cTopic) {
		InvalStat(ADFS_Stat_SIZE);
		InvalStat(ADFS_Stat_USED);
	}
}


OSErr		CDisk::NewDisk_Completion(ADFS_NewDiskCompletionRec *recP)
{
	SetName(recP->diskNameZ);
	
	return noErr;
}

OSErr		CDisk::Flush(void)
{
	return noErr;
}

OSErr		CDisk::Purge(Boolean criticalB)
{
	return noErr;
}

OSErr		CDisk::ToggleDeletedFiles(void)
{
	OSErr		err = noErr;
	
	i_show_deletedB = !i_show_deletedB;
	err = i_rootDir.gen->ToggleDeletedFiles();

	if (i_diskMapP) {
		i_diskMapP->Refresh();
	}
	
	return err;
}

OSErr		CDisk::UpdateSort(Boolean recursiveB)
{
	return i_rootDir.gen->UpdateSort(recursiveB);
}