//	DosStructs.c

#include "ADFS_LogFile.h"
#include "IC_ImageTypes.h"
#include "IC_FileIO.h"
#include "FileSystemTypes.h"
#include "DosStructs.h"

Dos_SectorSpec		Dos_gVtocSector		= Dos_kVtocSector;
Dos_SectorSpec		Dos_gEmptySector	= Dos_kEmptySector;
Dos_SectorSpec		Dos_gInvalidSector	= Dos_kInvalidSector;

Dos_FileDescription		Dos_FileDescArray[Dos_FileDesc_NUMTYPES] = {
	"ASCII text file", 
	"Integer Basic program", 
	"AppleSoft Basic program", 
	"Binary file", 
	"ÒSÓ-Type", 
	"Relocatable Binary file", 
	"ÒaÓ-Type", 
	"ÒbÓ-Type" 
};

Dos_SectorSpec		GetFirstTSSector(Dos_DirEntry *entryP)
{
	Dos_SectorSpec		spec = entryP->firstTSSector;
	
	if (Dos_IsDeleted(entryP)) {
		spec.track = entryP->name[Dos_kNameLength - 1];
	}
	
	return spec;
}

void		Dos_BuildFileTypeMenu(MenuRef theMenu)
{
	short				fileType;
	Str255				theStr;
	
	DeleteMenuItem(theMenu, 1);
	
	for (fileType = Dos_FileDesc_TEXT; fileType < Dos_FileDesc_NUMTYPES; fileType++) {
		CopyCStringToPascal(Dos_FileDescArray[fileType], theStr);
		AppendMenu(theMenu, theStr);
	}
}


//	accessing a sector
OSErr		Dos_GetSector(
	DiskImageRec	*imageRecP, 
	Dos_SectorSpec	sectorSpec, 
	Dos_Sector		**sectorPP)
{
	OSErr		err = noErr;
	
	if (IS_ImageRec_IN_MEMORY(imageRecP)) {
		*sectorPP = (Dos_Sector *)Gen_GetSector(imageRecP, sectorSpec);
		if (*sectorPP == NULL) err = IC_Err_READ_ILLEGAL_TRACK_SECTOR;
	} else {
		ulong		image_offsetUL = 0;
		ulong		sector_offsetUL;

		if (!(
			sectorSpec.track < Dos_kTracksPerDisk400 
			&& sectorSpec.sector < Dos_kSectorsPerTrack400)
		) {
			ReportError(err = IC_Err_READ_ILLEGAL_TRACK_SECTOR);
		}
				
		switch (ImageRec_DiskType(imageRecP)) {

			case DiskType_onDisk_DiskCopy: {
				image_offsetUL += sizeof(Disk_DiskCopy_Header);
				break;
			}

			case DiskType_onDisk_2img: {
				image_offsetUL += ImageRec_VolRec(imageRecP).image.header.twoimg.img_start_offset;
				break;
			}
		}
		
		sector_offsetUL = 
			  sectorSpec.track * sizeof(Dos_Track400) 
			+ sectorSpec.sector * sizeof(Dos_Sector);
		
		if (imageRecP->deviceP->interleavePartitionsB) {
			sector_offsetUL = (sector_offsetUL << 1) + (sizeof(Dos_Sector) * imageRecP->partition.idS);
		} else {
			image_offsetUL += imageRecP->partition.offsetL;
		}
		
		if (!err) err = ReadChunk(
			imageRecP, *sectorPP, 
			image_offsetUL + sector_offsetUL, 
			sizeof(Dos_Sector));
		
		if (err) {
			*sectorPP = NULL;
		}
	}
	
	return err;
}

OSErr		Dos_SetSector(
	DiskImageRec	*imageRecP, 
	Dos_SectorSpec	sectorSpec, 
	Dos_Sector		*sectorP)
{
	OSErr		err = noErr;
	
	if (IS_ImageRec_IN_MEMORY(imageRecP)) {
		err = WriteImage(imageRecP);
	} else {
		ulong		image_offsetUL = 0;
		ulong		sector_offsetUL;

		if (!(
			sectorSpec.track < Dos_kTracksPerDisk400 
			&& sectorSpec.sector < Dos_kSectorsPerTrack400)
		) {
			ReportError(err = IC_Err_READ_ILLEGAL_TRACK_SECTOR);
		}
		
		switch (ImageRec_DiskType(imageRecP)) {

			case DiskType_onDisk_DiskCopy: {
				image_offsetUL += sizeof(Disk_DiskCopy_Header);
				break;
			}

			case DiskType_onDisk_2img: {
				image_offsetUL += ImageRec_VolRec(imageRecP).image.header.twoimg.img_start_offset;
				break;
			}
		}

		sector_offsetUL = 
			  sectorSpec.track * sizeof(Dos_Track400) 
			+ sectorSpec.sector * sizeof(Dos_Sector);
		
		if (imageRecP->deviceP->interleavePartitionsB) {
			sector_offsetUL = (sector_offsetUL << 1) + (sizeof(Dos_Sector) * imageRecP->partition.idS);
		} else {
			image_offsetUL += imageRecP->partition.offsetL;
		}

		if (!err) err = WriteChunk(
			imageRecP, sectorP, 
			image_offsetUL + sector_offsetUL, 
			sizeof(Dos_Sector));
	}
	
	return err;
}

Byte		Dos_GetVolNum(DiskImageRec *imageRec)
{
	Byte				volNum = 254;
	Dos_VtocSector		vtoc;
	Dos_VtocSector		*vtocP = &vtoc;
	OSErr				err = noErr;
	
	err = Dos_GetSector(imageRec, Dos_gVtocSector, (Dos_Sector **)&vtocP);
	if (!err) {
		volNum = vtocP->volumeNumber;
	}
	
	return volNum;
}

static	Boolean		Dos_IsDosTest(DiskImageRec *imageRec)
{
	Boolean				isDos = FALSE;
	Dos_VtocSector		vtoc;
	Dos_VtocSector		*vtocP = &vtoc;
	OSErr				err = noErr;
	
	ASSERT(sizeof(Dos_TSListSector) == sizeof(Dos_Sector));
	ASSERT(sizeof(Dos_VtocSector) == sizeof(Dos_Sector));

	err = Dos_GetSector(imageRec, Dos_gVtocSector, (Dos_Sector **)&vtocP);
	if (!err) {
		isDos = vtocP->maxSectorSpecs					== Dos_kMaxSectorSpecs
			&& (
				   vtocP->perDisk.track					== Dos_kTracksPerDisk
				|| vtocP->perDisk.track					== Dos_kTracksPerDisk400) 
			&& (
				vtocP->perDisk.sector					== Dos_kSectorsPerTrack
				|| vtocP->perDisk.sector				== Dos_kSectorsPerTrack400)
			&& GetRboShort(vtocP->bytesPerSector)		== Dos_kBytesPerSector;
		
		/*
			you have to check the sector interleaving too.  you'll always find the  vtoc even
			on the wrong interleave. so get the 2nd dir sector and verify that it points to
			the 3rd.  (cuz the 1st will also always be in the right place, even on the wrong
			interleave)
		*/
		if (isDos) {
			Dos_DirSector	*dirSectorP = (Dos_DirSector *)&vtoc;
			
			err = Dos_GetSector(imageRec, vtocP->dirSector, (Dos_Sector **)&dirSectorP);
			
			if (err) {
				isDos = FALSE;
			} else {
				err = Dos_GetSector(imageRec, dirSectorP->nextDirSector, (Dos_Sector **)&dirSectorP);
			}

			if (err) {
				isDos = FALSE;
			} else {
				isDos = dirSectorP->nextDirSector.sector == Dos_kSectorsPerTrack - 3
					|| dirSectorP->nextDirSector.sector == Dos_kSectorsPerTrack400 - 3;
			}
		}
	}
	
	if (isDos) {
		imageRec->osType = FSType_DOS;
	}
	
	return isDos;
}

static	Boolean		Dos_TestNibOrder(DiskImageRec *imageRec, FSType assumeOrder, FSType orig)
{
	Boolean		success = FALSE;
	
	AssumeConvertImageType(imageRec, assumeOrder, FSType_DOS);
	
	success = Dos_IsDosTest(imageRec);
	
	if (success) {
		ADFS_Log("It was a DOS file in ");
		ADFS_Log_FSType(assumeOrder);
		ADFS_Log(" order\n");
		
		ImageRec_OrigOrder(imageRec)	= assumeOrder;
	} else {
		UnAssumeConvertImageType(imageRec, assumeOrder, orig);
	}
	
	return success;
}


Boolean		Dos_IsDos(DiskImageRec *imageRec)
{
	Boolean		isDos		= FALSE;
	FSType		origType 	= imageRec->curOrder;

	isDos = Dos_IsDosTest(imageRec);
	
	if (
		!isDos 
		&& !IS_ImageRec_IN_MEMORY(imageRec)
	) {
		imageRec->deviceP->interleavePartitionsB = TRUE;
		isDos = Dos_IsDosTest(imageRec);
		
		if (!isDos) {
			imageRec->deviceP->interleavePartitionsB = FALSE;
		}
	}

	if (isDos) {
		ADFS_Log("It was already in DOS order\n");
		ImageRec_OrigOrder(imageRec)	= FSType_DOS;
	}

	if (IS_ImageRec_IN_MEMORY(imageRec)) {
		if (!isDos) {
			ConvertImage(imageRec, FSType_DOS);
			
			isDos = Dos_IsDosTest(imageRec);
			if (isDos) {
				ADFS_Log("It was in ");
				ADFS_Log_FSType(ImageRec_OrigOrder(imageRec));
				ADFS_Log(" order, now DOS order\n");
				
				ASSERT(ImageRec_OrigOrder(imageRec) != FSType_GEN);
				if (ImageRec_OrigOrder(imageRec) == FSType_UNK) {
					ImageRec_OrigOrder(imageRec) = FSType_DOS;
				}
			} else {
				ConvertImage(imageRec, origType);
			}
		}
/*
		if (!isDos) {
			AssumeConvertImageType(imageRec, FSType_DOS, FSType_GEN);
			isDos = Dos_IsDosTest(imageRec);
			if (isDos) {
				ADFS_Log("It was a nib disk, already in DOS order\n");
				ImageRec_OrigOrder(imageRec) = FSType_DOS;
			} else {
				UnAssumeConvertImageType(imageRec, FSType_DOS, origType);
			}
		}
*/
		if (!isDos) isDos = Dos_TestNibOrder(imageRec, FSType_C2P, origType);
		if (!isDos) isDos = Dos_TestNibOrder(imageRec, FSType_GEN, origType);
		if (!isDos) isDos = Dos_TestNibOrder(imageRec, FSType_PRO, origType);
		if (!isDos) isDos = Dos_TestNibOrder(imageRec, FSType_CPM, origType);
	}
	
	if (isDos) {
		imageRec->curOrder	= FSType_DOS;
	} else {
		ADFS_Log("It's not a DOS disk\n");
	}
	
	return isDos;
}

/*
Dos_FileDescType	Dos_DescTypeToFileType(Dos_FileType fileType)
{
}
*/

Dos_FileDescType	Dos_FileTypeToDescType(Dos_FileType fileType)
{
	Dos_FileDescType	descType;
	
	//	bit shifting shenanegans
	if (fileType == Dos_FileType_TXT) {
		descType = Dos_FileDesc_TEXT;
	} else {
		for (descType = Dos_FileDesc_INT; fileType > 0x01;) { 
			descType = (Dos_FileDescType)(descType + 1); 
			fileType = fileType >> 1;
		}
	}

	return descType;
}

