//	ProStructs.c

#include "stdio.h"
#include "stddef.h"

#include "ProStructs.h"
#include "IC_ImageTypes.h"
#include "IC_Errors.h"
#include "ADFS_LogFile.h"
#include "IC_FileIO.h"

Pro_AccessPriv		Pro_kAccess_FOLDER		= { 1, 1, 1, 0, 0, 1 };
Pro_AccessPriv		Pro_kAccess_UNLOCKED	= { 1, 1, 0, 0, 1, 1 };
Pro_AccessPriv		Pro_kAccess_LOCKED		= { 0, 0, 0, 0, 0, 0 };
Pro_FileNameStr		Pro_kUntitledFolderStr	= "New Folder";
Pro_FileNameStr		Pro_kUntitledFileStr	= "New File";

Boolean		Pro_IsValidDirHeader(Pro_DirHeader *dirHeaderP)
{
	return 
		(
			dirHeaderP->typeName.stnl.storageType == Pro_Storage_VOL_HEADER
			|| dirHeaderP->typeName.stnl.storageType == Pro_Storage_SUBDIR_HEADER
		)
		&& dirHeaderP->typeName.stnl.nameLength <= Pro_kNameLength
		&& dirHeaderP->entryLen					== Pro_kEntryLen
		&& dirHeaderP->entriesPerBlock			== Pro_kMaxEntriesPerBlock;
}

Boolean		Pro_IsValid(
	DiskImageRec *imageRec, 
	Pro_DirEntry *entryP, 
	ulong		 blocksInVolumeL, 
	Pro_BlockNum headerBlockS)
{
	Pro_BlockNum	keyBlockS	= GetRboShort(entryP->key);
	Pro_BlockNum	blocksUsedS	= GetRboShort(entryP->blocksUsed);
	Pro_BlockNum	headerS		= GetRboShort(entryP->header);
	ulong			eofL		= GetRbo3Bytes(entryP->eof);
	Boolean			is_validB =
		headerS == headerBlockS
		&& (
			entryP->typeName.stnl.storageType == Pro_Storage_SUBDIR_FILE
			|| entryP->typeName.stnl.storageType <= Pro_Storage_FORKED
		)
		&& entryP->typeName.stnl.nameLength <= Pro_kNameLength
		&& keyBlockS > 0 && keyBlockS < blocksInVolumeL
		&& blocksUsedS > 0 && blocksUsedS < blocksInVolumeL
		&& eofL > 0 && eofL < (blocksInVolumeL * sizeof(Pro_Block))
		&& blocksUsedS >= eofL >> 9;
	
	if (is_validB && entryP->typeName.stnl.storageType == Pro_Storage_SUBDIR_FILE) {
		OSErr			err		= noErr;
		Pro_DirBlock	*dirBlockP;

		err = Pro_GetBlock(imageRec, keyBlockS, &(Pro_Block *)dirBlockP);

		if (!err) {
			is_validB = Pro_IsValidDirHeader(&dirBlockP->blockType.key.header);
		} else {
			is_validB = FALSE;
		}
	}
	
	return is_validB;
}

//	implies it's a valid file
Boolean		Pro_IsDeleted(
	DiskImageRec *imageRec, 
	Pro_DirEntry *entryP, 
	ulong		 blocksInVolumeL, 
	Pro_BlockNum headerBlockS)
{
	return Pro_IsEmptyEntry(entryP) && Pro_IsValid(imageRec, entryP, blocksInVolumeL, headerBlockS);
}


/****************************************************
	Is this a ProDOS disk?
*/
/*
#define		PRINT(_QFOO, _FOO)	\
	printf("offset of "_QFOO":\t\t0x%.2lx   %lu\n", offsetof(Pro_DirEntry, _FOO), offsetof(Pro_DirEntry, _FOO))

	printf("---------------------------------\n");

	printf("sizeof Pro_DirHeader:		%lu\n", sizeof(Pro_DirHeader));
	printf("\n");

	printf("sizeof Pro_DirBlock:		%lu\n", sizeof(Pro_DirBlock));
	printf("\n");
	
	printf("----------------\n");
	printf("sizeof Pro_DirEntry:		%lu\n", sizeof(Pro_DirEntry));
	printf("\n");

	PRINT("typeName",		typeName);
	PRINT("fileType",		fileType);
	PRINT("key",			key);
	PRINT("blocksUsed",		blocksUsed);
	PRINT("eof",			eof);
	PRINT("createdTime",	createdTime);
	PRINT("locaseBits",		locaseBits);
	PRINT("access",			access);
	PRINT("auxType",		auxType);
	PRINT("modifiedTime",	modifiedTime);
	PRINT("header",			header);
*/	

static	Boolean		Pro_IsProTest(DiskImageRec *imageRec)
{
	Pro_DirBlock	*dirBlock;
	Boolean			isPro = FALSE;
	OSErr			err;
	
	ASSERT(sizeof(Pro_DirBlock) == sizeof(Pro_Block));
	ASSERT(sizeof(Pro_DirHeader) == sizeof(Pro_DirEntry));
	
	err = Pro_GetBlock(imageRec, Pro_kDirStartBlock, &(Pro_Block *)dirBlock);
	
	if (!err) {
		isPro = ( 
			GetRboShort(dirBlock->list.previous)				== 0
			&& dirBlock->blockType.key.header.entryLen			== Pro_kEntryLen
			&& dirBlock->blockType.key.header.entriesPerBlock	== Pro_kMaxEntriesPerBlock
			&& dirBlock->blockType.typeName.stnl.storageType	== Pro_Storage_VOL_HEADER
		);
		
		if (isPro) {
			imageRec->osType = FSType_PRO;
		}
	}
	
	return isPro;														
}

static	Boolean		Pro_TestNibOrder(DiskImageRec *imageRec, FSType assumeOrder, FSType orig)
{
	Boolean		success = FALSE;
	
	AssumeConvertImageType(imageRec, assumeOrder, FSType_PRO);
	
	success = Pro_IsProTest(imageRec);
	
	if (success) {
		ADFS_Log("It was a ProDOS file in ");
		ADFS_Log_FSType(assumeOrder);
		ADFS_Log(" sector order\n");

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

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

			if (!isPro) {
				ConvertImage(imageRec, FSType_PRO);

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

			if (!isPro) isPro = Pro_TestNibOrder(imageRec, FSType_C2P, origType);
			if (!isPro) isPro = Pro_TestNibOrder(imageRec, FSType_GEN, origType);
			if (!isPro) isPro = Pro_TestNibOrder(imageRec, FSType_DOS, origType);
			if (!isPro) isPro = Pro_TestNibOrder(imageRec, FSType_CPM, origType);
		}
	}
		
	if (!isPro) {
		ADFS_Log("It was not a ProDOS disk\n");
	} else {
		imageRec->curOrder = FSType_PRO;
	}
	
	return isPro;
}
