//	PasStructs.c

#include "Utils.h"
#include "ctype.h"
#include "stdio.h"
#include "IC_ImageTypes.h"
#include "IC_FileIO.h"
#include "ADFS_LogFile.h"
#include "PasStructs.h"

OSErr	Pas_GetBlock(DiskImageRec *imageRec, Pas_BlockNum blockNum, Pas_Block **blockP)
{
	OSErr		err = noErr;
	Pas_Block	*theBlock;

	if (IS_ImageRec_IN_MEMORY(imageRec)) {
		if (blockNum > Pas_kBlocksPerDisk) {
			err = IC_Err_READ_ILLEGAL_DISK_BLOCK;
		} else {
			theBlock = &(imageRec->image.pas->block[blockNum]);
		}
	} else {
		ulong		image_offsetUL = 0;
		
		switch (ImageRec_DiskType(imageRec)) {

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

			case DiskType_onDisk_2img: {
				image_offsetUL = ImageRec_VolRec(imageRec).image.header.twoimg.img_start_offset;
				break;
			}
		}
		
		theBlock = (Pas_Block *)imageRec->image.proBlock;
				
		err = ReadChunk(
			imageRec, theBlock, 
			image_offsetUL + (blockNum * sizeof(Pas_Block)), 
			sizeof(Pas_Block));
		
		if (err) err = IC_Err_CANT_READ_PASCAL_BLOCK;
	}
	
	if (!err) {
		*blockP = theBlock;
	}

	return err;
}

static	Boolean		Pas_IsPasTest(DiskImageRec *imageRec)
{
	OSErr			err = noErr;
	Boolean			isPas = FALSE;
	Pas_DirEntry	*dirEntry;

	err = Pas_GetBlock(imageRec, Pas_kDirStartBlock, (Pas_Block **)&dirEntry);
	
	if (!err) {
		ushort			vol_size = GetRboShort(
				dirEntry->entryType.volume.endOfVolume);

		isPas = ( 
			vol_size									> 0
			&& GetRboShort(dirEntry->firstBlock)			== 0
			&& GetRboShort(dirEntry->lastBlockPlusOne)	== Pas_kDirEndBlockPlusOne
			&& GetRboShort(dirEntry->fileKind)			== Pas_FileKind_VOL_DIR
//			&& (vol_size == Pas_kBlocksPerDisk || vol_size == Pas_kBlocksPerDisk800)
		);
	}
	
	if (isPas) {
		imageRec->osType = FSType_PAS;
	}
	
	return isPas;
}

static	Boolean		Pas_TestNibOrder(DiskImageRec *imageRec, FSType assumeOrder, FSType orig)
{
	Boolean		success = FALSE;
	
	AssumeConvertImageType(imageRec, assumeOrder, FSType_PAS);
	
	success = Pas_IsPasTest(imageRec);
	
	if (success) {
		ADFS_Log("It was a Pascal file in ");
		ADFS_Log_FSType(assumeOrder);
		ADFS_Log(" sector order\n");

		ImageRec_OrigOrder(imageRec)	= assumeOrder;
	} else {
		UnAssumeConvertImageType(imageRec, assumeOrder, orig);
	}
	
	return success;
}


Boolean		Pas_IsPas(DiskImageRec *imageRec)
{
	Boolean			isPas = FALSE;
	
	isPas = Pas_IsPasTest(imageRec);
	if (isPas) {
		ADFS_Log("It was already in Pascal(ProDOS) order\n");
		ImageRec_OrigOrder(imageRec)	= FSType_PRO;
	} else {
		if (IS_ImageRec_IN_MEMORY(imageRec)) {
			FSType		origType = imageRec->curOrder;

			ConvertImage(imageRec, FSType_PRO);
			isPas = Pas_IsPasTest(imageRec);

			if (isPas) {
				ADFS_Log("It was in ");
				ADFS_Log_FSType(ImageRec_OrigOrder(imageRec));
				ADFS_Log(" order, now Pascal (ProDOS) order\n");
				
				ASSERT(ImageRec_OrigOrder(imageRec) != FSType_GEN);
				if (ImageRec_OrigOrder(imageRec) == FSType_UNK) {
					ImageRec_OrigOrder(imageRec) = FSType_PRO;
				}
			} else {
				ConvertImage(imageRec, ImageRec_OrigOrder(imageRec));
			}

			if (!isPas) isPas = Pas_TestNibOrder(imageRec, FSType_C2P, origType);
			if (!isPas) isPas = Pas_TestNibOrder(imageRec, FSType_GEN, origType);
			if (!isPas) isPas = Pas_TestNibOrder(imageRec, FSType_DOS, origType);
			if (!isPas) isPas = Pas_TestNibOrder(imageRec, FSType_CPM, origType);
		}
	}
	
	if (!isPas) {
		ADFS_Log("It was not a Pascal Disk\n");
	}
	
	return isPas;														
}


typedef char	Pas_FileTypeStr[32];
Pas_FileTypeStr	gPas_FileTypeTable[Pas_FileKind_NUMTYPES] = {
	"Directory", 
	"Pascal Disk Information", 
	"Pascal Code file", 
	"Pascal Text file", 
	"Pascal Debugger Information", 
	"User Data", 
	"Graphics", 
	"Photograph", 
	"Secure Directory"
};

char	*Pas_GetFileType(Pas_FileKindType fileKind)
{
	return gPas_FileTypeTable[fileKind];
}

static	char	*Pas_GetFileSize(Pas_DirEntry *entry, char *fileSizeBuf)
{
	long	lastBlock		= GetRboShort(entry->lastBlockPlusOne) - 1, 
			firstBlock		= GetRboShort(entry->firstBlock), 
			remainBytes		= GetRboShort(entry->entryType.file.lastByte), 
			totalBytes		= ((lastBlock - firstBlock) * Pas_kBytesPerBlock) + remainBytes;

	return FormatSize(totalBytes, fileSizeBuf);
}

typedef char			Pas_MonthName[4];
/*
static	Pas_MonthName	gPas_Calandar[12] = {
	"JAN", "FEB", "MAR", "APR", "MAY", "JUN", 
	"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
};
*/
static	char	*Pas_GetDate(Pas_DateRec date, char *fileDateBuf)
{
/*	sprintf(
		fileDateBuf, 
		"%2d-%s-%02d", 
		(short)date.day, 
		gPas_Calandar[date.month + 1], 
		(short)date.year
	);
*/	
	return fileDateBuf;
}

static	void	Pas_GetDiskSizes(DiskImageRec *imageRec, long *bytesUsed, long *bytesFree)
{
	*bytesUsed = 0;
	*bytesFree = 0;
}

/*
void		Pas_Catalog(DiskImageRec *imageRec)
{
	Pas_DirEntry	*directory, *entry;
	long			entryIndex, bytesUsed, bytesFree;
	char			fileSizeBuf[10], fileDateBuf[12], sizeBuf1[10], sizeBuf2[10];
	
	directory = (Pas_DirEntry *)Pas_GetBlock(imageRec, Pas_kDirStartBlock);
	
	printf(
		"\nPascal Volume: /%#s\n\n"
		"Name              Type   Size  Modified\n\n", 
		directory->entryType.volume.volumeID
	);
	
	for (
		entryIndex = 1;
		entryIndex < directory->entryType.volume.numFiles;
		entryIndex++
	) {
		entry = (Pas_DirEntry *)&(directory[entryIndex]);
		
		printf(
			"%#-17s %s %6s  %s\n", 
			entry->entryType.file.titleID, 
			Pas_GetFileType((Pas_FileKindType)GetRboShort(entry->fileKind)), 
			Pas_GetFileSize(entry, fileSizeBuf), 
			Pas_GetDate(entry->entryType.file.access, fileDateBuf)
		);
	}
	
	Pas_GetDiskSizes(imageRec, &bytesUsed, &bytesFree);
	
	printf(
		"\nFree: %s  Used: %s\n", 
		FormatSize(bytesFree, sizeBuf1), 
		FormatSize(bytesUsed, sizeBuf2)
	);
}
*/

void		Pas_SanitizeName(char *pasNameZ, short maxLenS)
{	
	if (pasNameZ[0] == 0) {
		pasNameZ[0] = 'A';
		pasNameZ[1] = 0;
	} else {
		short			lenS = strlen(pasNameZ);
		short			indexS;
		char			*charP;
		
		if (lenS > maxLenS) {
			lenS = maxLenS;
			pasNameZ[lenS] = 0;
		}
		
		charP = &pasNameZ[0];
		*charP = toupper(*charP);

		if (*charP < 'A' && *charP > 'Z') {
			*charP = 'A';	//	first char must be letter
		}

		for (
			indexS = 1;
			indexS < lenS;
			indexS++
		) {
			charP = &pasNameZ[indexS];
			*charP = toupper(*charP);
			
			//	illegal becomes a dot
			if (!(
				(*charP >= 'A' && *charP <= 'Z')
				|| (*charP >= '0' && *charP <= '9')
				|| (*charP == '.'))
			) {
				*charP = '.';
			}
		}
	}
}
