//	ProStructs.h

#ifndef _H_ProStructs
#define _H_ProStructs

#include "FileSystemTypes.h"
#include "ProDiskLocSpec.h"

#pragma options align = packed

/***********************************************************/
//	disk structs
#define	Pro_kBytesPerBlock		512L		//	0x0200L
#define Pro_kShortsPerBlock		(Pro_kBytesPerBlock >> 1)
#define Pro_kLongsPerBlock		(Pro_kBytesPerBlock >> 2)

//	140k disk stuff
#define	Pro_kBlocksPerDisk		280L		//	0x0118L
#define	Pro_kSectorsPerBlock	2L
#define	Pro_kBlocksPerTrack		8L

#define	Pro_kBlocksPerDisk400	800L
#define	Pro_kBlocksPerDisk800	1600L
#define	Pro_kBlocksPerDisk1440	2880L
#define	Pro_kBlocksPerDisk5M	10240L
#define	Pro_kBlocksPerDisk10M	20480L
#define	Pro_kBlocksPerDisk15M	30720L
#define	Pro_kBlocksPerDisk20M	40960L
#define	Pro_kBlocksPerDisk32M	65535L

#define Pro_kDirStartBlock		2
#define	Pro_kEntryLen			39

#define	Pro_kEntriesPerVolDir	51L

#define		Pro_kNumBootBlocks		2L
#define		Pro_kNumDirBlocks		4L

typedef unsigned short	Pro_BlockNum;
#define	Pro_kNoBlock	((Pro_BlockNum)0xFFFF)

//	disk structs
typedef struct Pro_Block {
	Byte		byte[Pro_kBytesPerBlock];
} Pro_Block;

typedef struct {
	ushort		data[Pro_kShortsPerBlock];
} Pro_ShortBlock;

typedef struct Pro_HalfBlock {
	Byte		byte[Pro_kShortsPerBlock];
} Pro_HalfBlock;

typedef struct {
	Pro_HalfBlock		low;
	Pro_HalfBlock		high;
} Pro_IndexBlock;

typedef	unsigned long Pro_BitMapBlock[Pro_kLongsPerBlock];
#define	Pro_kFreeBlock	1
#define	Pro_kUsedBlock	0

typedef struct Pro_Disk {
	Pro_Block	block[Pro_kBlocksPerDisk];
} Pro_Disk;

typedef struct Pro_Disk800 {
	Pro_Block	block[Pro_kBlocksPerDisk800];
} Pro_Disk800;

typedef struct Pro_Disk1440 {
	Pro_Block	block[Pro_kBlocksPerDisk1440];
} Pro_Disk1440;

#define		kPro_Disk140_Size	sizeof(Pro_Disk)
#define		kPro_Disk800_Size	sizeof(Pro_Disk800)
#define		kPro_Disk1440_Size	sizeof(Pro_Disk1440)

/***********************************************************/
//	date and time
typedef	union {
	
	struct {
		short	ymd;
		short	hm;
	} split;

	struct {
		unsigned short	year	: 7;
		unsigned short	month	: 4;
		unsigned short	day		: 5;
		unsigned short	unused1	: 3;
		unsigned short	hour	: 5;
		unsigned short	unused2	: 2;
		unsigned short	minute	: 6;
	} dt;

} Pro_DateTimeMem;

typedef struct {
	RboShort		ymd;
	RboShort		hm;
} Pro_DateTime;

/***********************************************************/
//	block list
typedef	struct {
	Pro_BlockSpec		previous;
	Pro_BlockSpec		next;
} Pro_BlockListNode;

/***********************************************************/
//	Storage Type, Name Length, File Name
enum {
	Pro_Storage_INACTIVE, 
	Pro_Storage_SEEDLING, 
	Pro_Storage_SAPLING, 
	Pro_Storage_TREE, 
	Pro_Storage_PASCAL, 
	Pro_Storage_FORKED,
	
	Pro_Storage_SUBDIR_FILE = 0x0D, 
	Pro_Storage_SUBDIR_HEADER, 
	Pro_Storage_VOL_HEADER
};
typedef unsigned char Pro_StorageType;

typedef struct {
	Pro_StorageType		storageType	: 4;
	unsigned char		nameLength	: 4;
} Pro_StorTypNamLen;

//	file name
			#define		Pro_kNameLength		15
typedef		char		Pro_FileName[Pro_kNameLength];
typedef		char		Pro_FileNameStr[Pro_kNameLength + 1];

typedef struct {
	Pro_StorTypNamLen	stnl;
	Pro_FileName		name;
} Pro_TypeName;

#define		Pro_kUseLocaseBits		0x8000

/***********************************************************/
//	Extended (forked) file info
enum {
	Pro_ForkFInfoEntry_NONE,
	Pro_ForkFInfoEntry_FInfo,
	Pro_ForkFInfoEntry_FXInfo
};
typedef Byte	Pro_ForkFInfoEntryType;

#define	Pro_ForkFInfoSize			16							//	must be 16 bytes long
#define	Pro_ForkFInfoEntrySize		(Pro_ForkFInfoSize + 2)		//	must be 18 bytes long

typedef struct {
	Byte						entrySize;	//	== Pro_ForkFInfoEntrySize
	Pro_ForkFInfoEntryType		entryType;
	char						fInfo[Pro_ForkFInfoSize];	//	MacOS Finder Info
} Pro_ForkFInfo;

typedef struct {
	unsigned char		reserved	: 4;
	Pro_StorageType		storageType	: 4;
} Pro_LowStorType;

typedef struct {
	Pro_LowStorType		lowStorType;
	Pro_BlockSpec		key;
	RboShort			blocksUsed;
	Rbo3Byte			eof;
	
	//	only the data fork has the following extra fields, in 
	//	the res fork, it's all zeroes
	Pro_ForkFInfo		fInfo1;
	Pro_ForkFInfo		fInfo2;
	Byte				unused[212];
} Pro_ForkEntry;

typedef struct {
	Pro_ForkEntry		data;
	Pro_ForkEntry		resource;
} Pro_ExtendedIndexBlock;

/***********************************************************/
//	access privileges

#define		Pro_kUseOldTwirlDown	TRUE

typedef unsigned char Pro_AccessPrivMem;

typedef struct {
	Pro_AccessPrivMem	destroyEnable	: 1;	//	0x80
	Pro_AccessPrivMem	renameEnable	: 1;	//	0x40
	Pro_AccessPrivMem	backup			: 1;	//	0x20
	
	#if Pro_kUseOldTwirlDown
		Pro_AccessPrivMem unused0		: 1;
	#else
		Pro_AccessPrivMem twirledDownB	: 1;
	#endif
	
	Pro_AccessPrivMem	unused1			: 2;
	Pro_AccessPrivMem	writeEnable		: 1;	//	0x02
	Pro_AccessPrivMem	readEnable		: 1;	//	0x01
} Pro_AccessPriv;

extern	Pro_AccessPriv		Pro_kAccess_FOLDER;
extern	Pro_AccessPriv		Pro_kAccess_UNLOCKED;
extern	Pro_AccessPriv		Pro_kAccess_LOCKED;
extern	Pro_FileNameStr		Pro_kUntitledFolderStr;
extern	Pro_FileNameStr		Pro_kUntitledFileStr;

/***********************************************************/
//	directory header
typedef struct {
	Pro_TypeName		typeName;
	RboShort			unknown;		//	vol = 0x00, dir = 0x75 (117d)
	Pro_DateTime		modifiedTime;
	RboShort			locaseBits;
	Pro_DateTime		createdTime;
	Byte				version;
	Byte				minVersion;
	Pro_AccessPriv		access;
	Byte				entryLen;
	Byte				entriesPerBlock;
	RboShort			fileCount;
	
	union {
		struct {
			Pro_BlockSpec		bitMap;
			RboShort			totalBlocks;
		} volume;
		
		struct {
			Pro_BlockSpec		parent;
			Byte				parentEntryNum;
			Byte				parentEntryLength;
		} directory;
	} headerType;
	
} Pro_DirHeader;

/***********************************************************/
//	Directory entry
typedef		Byte				Pro_FileType;
#define		Pro_FileType_BINA	((Pro_FileType)0x00)
#define		Pro_FileType_BAD	((Pro_FileType)0x01)	//	bad blocks
#define		Pro_FileType_PCD	((Pro_FileType)0x02)	//	Pascal code
#define		Pro_FileType_PTX	((Pro_FileType)0x03)	//	Pascal text
#define		Pro_FileType_TXT	((Pro_FileType)0x04)
#define		Pro_FileType_PDA	((Pro_FileType)0x05)	//	Pascal data
#define		Pro_FileType_BIN	((Pro_FileType)0x06)
#define		Pro_FileType_FNT	((Pro_FileType)0x07)
#define		Pro_FileType_DIR	((Pro_FileType)0x0F)
#define		Pro_FileType_AWD	((Pro_FileType)0x19)
#define		Pro_FileType_AWP	((Pro_FileType)0x1A)
#define		Pro_FileType_AWS	((Pro_FileType)0x1B)
#define		Pro_FileType_S16	((Pro_FileType)0xB3)
#define		Pro_FileType_ICN	((Pro_FileType)0xCA)
#define		Pro_FileType_INT	((Pro_FileType)0xFA)
#define		Pro_FileType_BAS	((Pro_FileType)0xFC)
#define		Pro_FileType_REL	((Pro_FileType)0xFE)
#define		Pro_FileType_SYS	((Pro_FileType)0xFF)

typedef struct {
	Pro_TypeName		typeName;
	Pro_FileType		fileType;
	Pro_BlockSpec		key;
	RboShort			blocksUsed;
	Rbo3Byte			eof;
	Pro_DateTime		createdTime;
	RboShort			locaseBits;
	Pro_AccessPriv		access;
	RboShort			auxType;
	Pro_DateTime		modifiedTime;
	Pro_BlockSpec		header;
} Pro_DirEntry;

#define	Pro_IsEmptyEntry(entryP)		\
	((entryP)->typeName.stnl.storageType == Pro_Storage_INACTIVE)

/***********************************************************/
//	Directory block
typedef	short	Pro_EntryIndex;
#define			Pro_kMaxEntriesPerBlock		13

typedef struct {
	Pro_BlockListNode		list;
	
	union {
		Pro_TypeName		typeName;
		
		struct {
			Pro_DirHeader		header;
			Pro_DirEntry		entry[Pro_kMaxEntriesPerBlock - 1];
		} key;
		
		struct {
			Pro_DirEntry		entry[Pro_kMaxEntriesPerBlock];
		} standard;
	} blockType;

	#if Pro_kUseOldTwirlDown
		Byte				twirledDownB;
	#else
		Byte				unused;
	#endif
} Pro_DirBlock;

/***********************************************************/
//	Entry location specification
typedef struct {
	Pro_BlockNum		block;
	Pro_EntryIndex		entryIndex;	//	within block (zero based)
	Pro_EntryIndex		dirIndex;	//	within directory (one based)
} Pro_EntryLocSpec;

#pragma options align = reset

Boolean		Pro_IsPro(DiskImageRec *imageRec);
OSErr		Pro_GetBlock(DiskImageRec *imageRec, Pro_BlockNum blockNum, Pro_Block **blockP);
Boolean		Pro_IsValid(
	DiskImageRec *imageRec, 
	Pro_DirEntry *entryP, 
	ulong		 blocksInVolumeL, 
	Pro_BlockNum headerBlockS);

Boolean		Pro_IsDeleted(
	DiskImageRec *imageRec, 
	Pro_DirEntry *entryP, 
	ulong		 blocksInVolumeL, 
	Pro_BlockNum headerBlockS);
	
Boolean		Pro_IsValidDirHeader(Pro_DirHeader *dirHeaderP);

#endif