//	IC_ImageTypes.c

#include "MemUtils.h"
#include "string.h"
#include "IC_Errors.h"
#include "IC_ImageTypes.h"
#include "GenStructs.h"

typedef		Byte				IC_SectorOrderMap[Gen_kSectorsPerTrack];
typedef		IC_SectorOrderMap	IC_SectorOrderTable[FSType_NUMTYPES];

IC_SectorOrderTable		gOrderTable = {
	{		//	unknown
		0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 	
		0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
	}, {	//	Generic
		0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 	
		0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
	}, {	//	DOS order		skewed 9 descending
		0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 	
		0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
	}, {	//	ProDOS order	skewed 2 ascending
		0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 	
		0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF
	}, {	//	Pascal order	skewed 2 ascending
		0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 	
		0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF
	}, {	//	CP/M order		skewed 4 descending?
		0x0, 0xC, 0x9, 0x6, 0x3, 0xF, 0x8, 0x5, 
		0x2, 0xE, 0xB, 0x4, 0x1, 0xD, 0xA, 0x7
	}, {	//	Copy ][+ order (ProDOS 2x)
		0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 	
		0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF
	}
};

/*
(sk 3 a)		(ProDOS)
CP/M Logical    CP/M Physical    DOS 3.3       Apple Physical
Sectors         Sectors          Sectors       Sectors

00,01 0              0               0               0
02,03 1              9               6               3
04,05 2              3               C               6
06,07 3              C               3               9
08,09 4              6               9               C
0A,0B 5              F               F               F
0C,0D 6              1               E               2
0E,0F 7              A               5               5
10,11 8              4               B               8
12,13 9              D               2               B
14,15 A              7               8               E
16,17 B              8               7               1
18,19 C              2               D               4
1A,1B D              B               4               7
1C,1D E              5               A               A
1E,1F F              E               1               D

true CPM sector order	
0x0, 0xC, 0x9, 0x6, 0x3, 0xF, 0x8, 0x5, 
0x2, 0xE, 0xB, 0x4, 0x1, 0xD, 0xA, 0x7, 

	phys->logical cpm
		0x0, 0xB, 0x6, 0x1, 0xC, 0x7, 0x2, 0xD, 	
		0x8, 0x3, 0xE, 0x9, 0x4, 0xF, 0xA, 0x5

	logical cpm->phys apple
		0x0, 0x3, 0x6, 0x9, 0xC, 0xF, 0x2, 0x5, 	
		0x8, 0xB, 0xE, 0x1, 0x4, 0x7, 0xA, 0xD

	logical cpm->dos 3.3
		0x0, 0x6, 0xC, 0x3, 0x9, 0xF, 0xE, 0x5, 	
		0xB, 0x2, 0x8, 0x7, 0xD, 0x4, 0xA, 0x1

	logical cpm->phys cpm (prodos)
		0x0, 0x9, 0x3, 0xC, 0x6, 0xF, 0x1, 0xA,	
		0x4, 0xD, 0x7, 0x8, 0x2, 0xB, 0x5, 0xE


*/

void			IC_ConvertSector(FSType oldType, FSType newType, short *sectorS)
{
	if (oldType != newType) {
		short		gen_sectorS;
		Byte		*convertFrom	= NULL,
					*convertTo		= NULL;

		ASSERT(oldType != FSType_UNK);
		ASSERT(newType != FSType_UNK);

		convertFrom	= gOrderTable[oldType];
		convertTo	= gOrderTable[newType];
		
		for (gen_sectorS = 0; gen_sectorS < Gen_kSectorsPerTrack; gen_sectorS++) {
			if (convertFrom[gen_sectorS] == *sectorS) {
				break;
			}
		}
		
		*sectorS = convertTo[gen_sectorS];
	}
}

static	void	ConvertMemImage2(Gen_Disk *diskP, FSType oldType, FSType newType)
{
	if (oldType != newType) {
		Gen_Track	*curTrack, tempTrack;
		Byte		track, sector, 
					*convertFrom	= NULL,
					*convertTo		= NULL;

		ASSERT(oldType != FSType_UNK);
		ASSERT(newType != FSType_UNK);

		convertFrom	= gOrderTable[oldType];
		convertTo	= gOrderTable[newType];
			
		for (track = 0; track < Gen_kTracksPerDisk; track++) {
			curTrack	= &(diskP->track[track]);
			tempTrack	= *curTrack;
			
			for (sector = 0; sector < Gen_kSectorsPerTrack; sector++) {
				curTrack->sector[convertFrom[sector]] 
					= tempTrack.sector[convertTo[sector]];
			} 
		}
	}
}

void	ConvertMemImage(Gen_Disk *diskP, FSType oldType, FSType newType)
{
	if (oldType != newType) {
		ConvertMemImage2(diskP, oldType, FSType_GEN);
		ConvertMemImage2(diskP, FSType_GEN, newType);
	}
}

/*
		if (oldType == FSType_CPM || newType == FSType_CPM) {
			if (oldType == FSType_GEN || newType == FSType_GEN) {
				ConvertMemImage2(diskP, oldType, newType);
			} else {
				ConvertMemImage2(diskP, oldType, FSType_GEN);
				ConvertMemImage2(diskP, FSType_GEN, newType);
			}
		} else {
			ConvertMemImage2(diskP, oldType, newType);
		}
	}
}
*/

/*
void	ConvertMemImage(Gen_Disk *diskP, FSType oldType, FSType newType)
{
	Gen_Track	*curTrack, tempTrack;
	Byte		track, sector, 
				*convertFrom	= NULL,
				*convertTo		= NULL;

	ASSERT(oldType != FSType_UNK);
	ASSERT(newType != FSType_UNK);

	convertFrom	= gOrderTable[oldType];
	convertTo	= gOrderTable[newType];
		
	for (track = 0; track < Gen_kTracksPerDisk; track++) {
		curTrack	= &(diskP->track[track]);
		
//		if (convertFrom) {
			tempTrack = *curTrack;
			
			for (sector = 0; sector < Gen_kSectorsPerTrack; sector++) {
				curTrack->sector[convertTo[sector]] 
					= tempTrack.sector[convertFrom[sector]];
				//tempTrack.sector[sector];
			} 
//		}
/*		
		if (convertTo) {
			tempTrack = *curTrack;

			for (sector = 0; sector < Gen_kSectorsPerTrack; sector++) {
				curTrack->sector[sector] = tempTrack.sector[convertTo[sector]];
			} 
		}
/
	}
}

*/

typedef	struct {
	IC_SectorOrderMap	sector;
	FSType				origOrder;
	FSType				curOrder;
} IC_SimpleConvertRec;

static	void	SimpleConvertTest2(
	IC_SectorOrderMap *curSector, FSType oldType, FSType newType)
{
	Byte					sector, fromByte, toByte;
	IC_SectorOrderMap		tempSector, 
							*convertFrom	= NULL,
							*convertTo		= NULL;

	ASSERT(oldType != FSType_UNK);
	ASSERT(newType != FSType_UNK);
		
	convertFrom	= &gOrderTable[oldType];
	convertTo	= &gOrderTable[newType];
	
	memcpy(&tempSector, curSector, sizeof(IC_SectorOrderMap));
	
	for (sector = 0; sector < Gen_kSectorsPerTrack; sector++) {
		fromByte	= (*convertFrom)[sector];
		toByte		= (*convertTo)[sector];
		
		(*curSector)[fromByte] = tempSector[toByte];
	} 
}

static	void	SimpleConvertTest(
	IC_SimpleConvertRec *convRec, FSType newType)
{
	if (convRec->curOrder != newType) {
		if (convRec->curOrder == FSType_CPM || newType == FSType_CPM) {
			if (convRec->curOrder == FSType_GEN || newType == FSType_GEN) {
				SimpleConvertTest2(&convRec->sector, convRec->curOrder, newType);
			} else {
				SimpleConvertTest2(&convRec->sector, convRec->curOrder, FSType_GEN);
				SimpleConvertTest2(&convRec->sector, FSType_GEN, newType);
			}
		} else {
			SimpleConvertTest2(&convRec->sector, convRec->curOrder, newType);
		}
		
		convRec->curOrder = newType;
	}
}

static	void	SimpleAssumeConvertImageType(
	IC_SimpleConvertRec *imageRec, 
	FSType				oldType, 
	FSType				newType)
{
	imageRec->curOrder = oldType;
	SimpleConvertTest(imageRec, newType);
}

static	void	SimpleUnAssumeConvertImageType(
	IC_SimpleConvertRec		*imageRec, 
	FSType					newType, 
	FSType					assumeType)
{
	SimpleConvertTest(imageRec, newType);
	imageRec->curOrder = assumeType;
}

/**************************************************/
void	ConvertImage(DiskImageRec *imageRec, FSType newType)
{
	if (
		IS_ImageRec_IN_MEMORY(imageRec)
		&& imageRec->image.gen 
		&& imageRec->curOrder != newType
	) {
		ConvertMemImage(imageRec->image.gen, imageRec->curOrder, newType);
		imageRec->curOrder = newType;
	}
}
/**************************************************/
void	AssumeConvertImageType(DiskImageRec *imageRec, FSType oldType, FSType newType)
{
	if (
		IS_ImageRec_IN_MEMORY(imageRec)
		&& imageRec->image.gen
	) {
		imageRec->curOrder = oldType;
		ConvertImage(imageRec, newType);
	}
}

void	UnAssumeConvertImageType(DiskImageRec *imageRec, FSType newType, FSType assumeType)
{
	if (
		IS_ImageRec_IN_MEMORY(imageRec)
		&& imageRec->image.gen 
	) {
		ConvertImage(imageRec, newType);
		imageRec->curOrder = assumeType;
	}
}


void	IC_ConvertTest(void)
{
	IC_SimpleConvertRec		curRec, testRec;
	int						result;
	short					sector;
	
	curRec.origOrder	= FSType_GEN;
	curRec.curOrder		= FSType_GEN;
	
	for (sector = 0; sector < Gen_kSectorsPerTrack; sector++) {
		curRec.sector[sector] = sector;
	}

	testRec = curRec;
	
	//	Pro 2x = C2P order!!
	SimpleConvertTest(&curRec, FSType_PRO);
	SimpleAssumeConvertImageType(&curRec, FSType_GEN, FSType_PRO);
	SimpleUnAssumeConvertImageType(&curRec, FSType_GEN, FSType_PRO);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);
	
	//	Dos 2x = C2P order!!
	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleAssumeConvertImageType(&curRec, FSType_GEN, FSType_DOS);
	SimpleUnAssumeConvertImageType(&curRec, FSType_GEN, FSType_DOS);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);
	
	//	Pro->Dos = reverse C2P order!!
	SimpleConvertTest(&curRec, FSType_PRO);
	SimpleAssumeConvertImageType(&curRec, FSType_GEN, FSType_PRO);
	SimpleUnAssumeConvertImageType(&curRec, FSType_GEN, FSType_PRO);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);
	
	//	Dos->CPM
	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleAssumeConvertImageType(&curRec, FSType_C2P, FSType_CPM);
	SimpleUnAssumeConvertImageType(&curRec, FSType_C2P, FSType_DOS);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);
	
	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleConvertTest(&curRec, FSType_PRO);
	SimpleConvertTest(&curRec, FSType_C2P);
	SimpleConvertTest(&curRec, FSType_CPM);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleConvertTest(&curRec, FSType_PRO);
	SimpleConvertTest(&curRec, FSType_C2P);
	SimpleConvertTest(&curRec, FSType_CPM);
	SimpleConvertTest(&curRec, FSType_GEN);
	SimpleConvertTest(&curRec, FSType_PRO);
	SimpleConvertTest(&curRec, FSType_GEN);
	SimpleConvertTest(&curRec, FSType_CPM);
	SimpleConvertTest(&curRec, FSType_C2P);
	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleConvertTest(&curRec, FSType_PRO);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleConvertTest(&curRec, FSType_CPM);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleConvertTest(&curRec, FSType_CPM);
	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleConvertTest(&curRec, FSType_DOS);
	SimpleConvertTest(&curRec, FSType_CPM);
	SimpleConvertTest(&curRec, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleAssumeConvertImageType(&curRec, FSType_DOS, FSType_PRO);
	SimpleUnAssumeConvertImageType(&curRec, FSType_DOS, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleAssumeConvertImageType(&curRec, FSType_DOS, FSType_GEN);
	SimpleUnAssumeConvertImageType(&curRec, FSType_DOS, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);

	SimpleAssumeConvertImageType(&curRec, FSType_GEN, FSType_DOS);
	SimpleUnAssumeConvertImageType(&curRec, FSType_GEN, curRec.origOrder);
	result = memcmp(&curRec, &testRec, sizeof(IC_SimpleConvertRec));
	ASSERT(result == 0);
}

/*
void	IC_ConvertTest(void)
{
	DiskImageRec		imageRec;
	Gen_Disk			*testDiskP;
	
	imageRec.image.gen	= (Gen_Disk *)TrackNewPtr(sizeof(Gen_Disk));
	testDiskP			= (Gen_Disk *)TrackNewPtr(sizeof(Gen_Disk));
	
	if (imageRec.image.gen && testDiskP) {
		int			result;
		short		track, sector, curByte;
		
		for (track = 0; track < Gen_kTracksPerDisk; track++) {
			for (sector = 0; sector < Gen_kSectorsPerTrack; sector++) {
				for (curByte = 0; curByte < Gen_kBytesPerSector; curByte++) {
					imageRec.image.gen->track[track].sector[sector].byte[curByte] = sector;
				}
			}
		}

		*testDiskP = *imageRec.image.gen;
	
		ImageRec_OrigOrder(imageRec)	= FSType_GEN;
		imageRec.curOrder	= FSType_GEN;
		
		ConvertImage(&imageRec, FSType_DOS);
		ConvertImage(&imageRec, ImageRec_OrigOrder(imageRec));
		
		result = memcmp(imageRec.image.gen, testDiskP, sizeof(Gen_Disk));
		ASSERT(result == 0);
		
		ConvertImage(&imageRec, FSType_DOS);
		ConvertImage(&imageRec, FSType_PRO);
		ConvertImage(&imageRec, FSType_CPM);
		ConvertImage(&imageRec, FSType_C2P);
		ConvertImage(&imageRec, ImageRec_OrigOrder(imageRec));
		
		result = memcmp(imageRec.image.gen, testDiskP, sizeof(Gen_Disk));
		ASSERT(result == 0);

		AssumeConvertImageType(&imageRec, FSType_DOS, FSType_PRO);
		UnAssumeConvertImageType(&imageRec, FSType_DOS, ImageRec_OrigOrder(imageRec));

		result = memcmp(imageRec.image.gen, testDiskP, sizeof(Gen_Disk));
		ASSERT(result == 0);

		AssumeConvertImageType(&imageRec, FSType_DOS, FSType_GEN);
		UnAssumeConvertImageType(&imageRec, FSType_DOS, ImageRec_OrigOrder(imageRec));

		result = memcmp(imageRec.image.gen, testDiskP, sizeof(Gen_Disk));
		ASSERT(result == 0);

		AssumeConvertImageType(&imageRec, FSType_GEN, FSType_DOS);
		UnAssumeConvertImageType(&imageRec, FSType_GEN, ImageRec_OrigOrder(imageRec));

		result = memcmp(imageRec.image.gen, testDiskP, sizeof(Gen_Disk));
		ASSERT(result == 0);
	}

	if (imageRec.image.gen) {
		TrackDisposePtr((Ptr)imageRec.image.gen);
	}

	if (testDiskP) {
		TrackDisposePtr((Ptr)testDiskP);
	}
}
*/