//	CFilePas

#include "CDiskMapWindow.h"
#include "ProStructs.h"
#include "CFolderPas.h"
#include "CDiskPas.h"
#include "CFilePas.h"

OSErr		CFilePas::IFilePas(
	CDiskPas			*cDisk, 
	CFolderPas			*cParentFolderPas, 
	Pas_BlockNum		block, 
	Pas_EntryIndex		entryIndex,	//	relative to cur dir sector
	Pas_EntryIndex		directoryIndex			//	relative to entire directory
) {
	OSErr				err = noErr;
	DiskLocSpecUnion	locSpec;
	
	locSpec.pas = SetRboShort(block);
	
	err = _inherited::IFile(
		cDisk, 
		cParentFolderPas, 
		locSpec, 
		entryIndex, 
		directoryIndex);

	return err;
}

ushort			CFilePas::GetFileType_ProEquiv(void)
{
	ushort				proType;
	Pas_FileKindType	fileType = GetPasFileType();
	
	switch (fileType) {

		case Pas_FileKind_TEXT: {
			proType = Pro_FileType_TXT;
			break;
		}
		
		case Pas_FileKind_VOL_DIR:
		case Pas_FileKind_SECURE_DIR: {
			proType = Pro_FileType_DIR;
			break;
		}

		case Pas_FileKind_BAD_BLOCKS: {
			proType = Pro_FileType_BAD;
			break;
		}

		case Pas_FileKind_CODE: {
			proType = Pro_FileType_PCD;
			break;
		}
			
		case Pas_FileKind_DATA: {
/*
			.pic
			.img
			.few
			.many
			.desk
			.words
			.apple
			.txt
			.font
			.partial
*/
			proType = Pro_FileType_PDA;
			break;
		}
		
		case Pas_FileKind_INFO: {
//			if .script TXT
			proType = Pro_FileType_BINA;
			break;
		}

		default:
		case Pas_FileKind_GRAF:
		case Pas_FileKind_FOTO: {
			proType = Pro_FileType_BIN;
			break;
		}
	}
	
	return proType;
}

Pas_DirEntry	*CFilePas::GetMyEntry(void)
{
	return ((CFolderPas *)GetParentFolder())->GetEntry(
		GetRboShort(i_diskLoc.pas), 
		i_diskLocDirEntryIndex
	);
}

char		*Pas_GetName(Pas_DirEntry *entryP, char *buf)
{
	buf[0] = 0;
	
	if (entryP) {
		CopyPascalStringToC(entryP->entryType.file.titleID, buf);
	}
	
	return buf;
}

char		*CFilePas::GetName(char *buf)
{
	_inherited::GetName(buf);
	
	if (buf[0] == 0) {
		Pas_GetName(GetMyEntry(), buf);
	}
	
	return buf;
}

void		CFilePas::SetName(char *buf)
{
	Pas_DirEntry		*dirEntry = GetMyEntry();
	
	if (dirEntry) {
		Pas_SanitizeName(buf, Pas_kTitleIDLength);

		CopyCStringToPascal(buf, dirEntry->entryType.file.titleID);
		
		_inherited::SetName(buf);
		(void)i_cDisk.pas->Pas_FlushDirectory();
	}
}


ushort		CFilePas::GetLoadAddress(void)
{
	return 0;
}

void		CFilePas::SetLoadAddress(ushort address)
{
}

OSErr 		CFilePas::ReadFile(Byte *buffer, long length)
{
	OSErr	err = noErr;
	
	return err;
}

OSErr 		CFilePas::WriteFile(Byte *buffer, long length)
{
	OSErr	err = noErr;
	
	return err;
}

//	gets native file type as short
ushort			CFilePas::GetFileType(void)
{
	return (ushort)GetPasFileType();
}

//	gets native file type as short
Pas_FileKindType		CFilePas::GetPasFileType(void)
{
	Pas_FileKindType	fileKind = Pas_FileKind_BAD_BLOCKS;
	Pas_DirEntry		*dirEntry = GetMyEntry();
	
	if (dirEntry) {
		fileKind =  (Pas_FileKindType)GetRboShort(dirEntry->fileKind);
	}
	
	return fileKind;
}

char		*CFilePas::GetDescription(char *buf)
{
	strcpy(buf, Pas_GetFileType(GetPasFileType()));
	return buf;
}

ulong		CFilePas::GetPhysicalSize(void)
{
	if (i_physical_sizeL == 0) {
		Pas_DirEntry	*entryP		= GetMyEntry();
		
		if (entryP) {
			ulong	lastBlock	= GetRboShort(entryP->lastBlockPlusOne), 
					firstBlock	= GetRboShort(entryP->firstBlock);
							 
			i_physical_sizeL	= ((lastBlock - firstBlock) * Pas_kBytesPerBlock);
		}
	}
	
	return i_physical_sizeL;
}

ulong		CFilePas::GetLogicalSize(void)
{
	if (i_logical_sizeL == 0) {
		Pas_DirEntry	*entryP		= GetMyEntry();
		
		if (entryP) {
			ulong		lastByte = GetRboShort(GetMyEntry()->entryType.file.lastByte);
			
			i_logical_sizeL = GetPhysicalSize() - (Pas_kBytesPerBlock) + lastByte;
		}
	}
		
	return i_logical_sizeL;
}

Pas_DateRec		Pas_MacToPasDate(DateTimeRec *macP, Pas_DateRec *pasP)
{
	pasP->date.year		= macP->year - 1900;
	pasP->date.month	= macP->month - 1;
	pasP->date.day		= macP->day;
	
	pasP->rboShort = SetRboShort(pasP->value);
	
	return *pasP;
}

DateTimeRec		*Pas_PasToMacDate(Pas_DateRec *pasP, DateTimeRec *macP)
{
	Pas_DateRec		myRec;
	
	myRec.value = GetRboShort(pasP->rboShort);

	macP->year			= 1900 + myRec.date.year;
	macP->month			= myRec.date.month + 1;
	macP->day			= myRec.date.day;
	macP->hour			= 0;
	macP->minute		= 0;
	macP->second		= 0;
	macP->dayOfWeek		= 0;
	
	return macP;
}

DateTimeRec	*CFilePas::GetModifiedTime(DateTimeRec *dt)
{
	Pas_DirEntry	*entry		= GetMyEntry();
	
	if (entry) {
		Pas_PasToMacDate(&entry->entryType.file.access, dt);
	} else {
		_inherited::GetCreatedTime(dt);
	}
	
	return dt;
}

void	CFilePas::SetModifiedTime(DateTimeRec *dt)
{
	Pas_DirEntry	*entry		= GetMyEntry();
	
	if (entry) {
		Pas_MacToPasDate(dt, &entry->entryType.file.access);
		i_cDisk.pas->Pas_FlushDirectory();
	} else {
		_inherited::GetCreatedTime(dt);
	}
}

ADFS_IconType		CFilePas::GetIconType(void)
{
	return _inherited::GetIconType();
}

#define		kPas_TextBufSize	(ushort)(sizeof(Pas_Block) * 2)

ulong			CFilePas::ADFS_GetBufSize(void)
{
	ulong	size = sizeof(Pas_Block);

	if (!IsCopyTranslated() || i_fileType == ADFS_File_TEXT) {
		size = kPas_TextBufSize;
	}
	
	return size;
}

OSErr		CFilePas::Pas_GetIndBlockNum(
	Pas_BlockNum blockIndex, 
	Pas_BlockNum *blockNum)
{
	OSErr			err = noErr;
	Pas_DirEntry	*entry = GetMyEntry();
	
	if (!entry) {
		err = IC_Err_ENTRY_NOT_FOUND;
	} else {
		Pas_BlockNum		lastBlock	= GetRboShort(entry->lastBlockPlusOne) - 1, 
							firstBlock	= GetRboShort(entry->firstBlock);

		if (blockIndex > lastBlock - firstBlock) {
			err = IC_Err_READ_ILLEGAL_FILE_BLOCK;
			ReportError(err);
		} else {
			*blockNum = firstBlock + blockIndex;
		}
	}
	
	return err;
}

#define	Pas_TextDLE		16

OSErr		CFilePas::ADFS_Open(
	ADFS_IOType	ioType, 
	Boolean		resForkB, 
	char		**bufferP, 
	ulong		*bufSize)
{
	i_dle_straddleB = FALSE;
	return _inherited::ADFS_Open(ioType, resForkB, bufferP, bufSize);
}

OSErr			CFilePas::ADFS_Read(ushort *bytesRead)
{
	OSErr			err = noErr;
	Pas_BlockNum	curBlockIndex	= (Pas_BlockNum)(i_filePos >> 9);		//	fp  is base 0, div by 512
	Pas_BlockNum	lastBlockIndex	= curBlockIndex;
	
	*bytesRead = 0;

	//	error if we're not reading block boundaries
	if (i_filePos != (ulong)curBlockIndex * (ulong)Pas_kBytesPerBlock) {
		err = IC_Err_BLOCK_BOUNDARIES;
		ReportError(err);
	}
	
	if (!err && i_eof > 0) {
		Pas_BlockNum	blockNum;
		Pas_Block		*blockP;

		lastBlockIndex	= (Pas_BlockNum)((i_eof - 1) >> 9);		//	eof is base 1, div by 512

		if (!err && curBlockIndex <= lastBlockIndex) {
			ushort		real_filePos = i_filePos;
			
			if (!err) err = Pas_GetIndBlockNum(curBlockIndex, &blockNum);
			if (!err) err = i_cDisk.pas->GetBlock(blockNum, &blockP);
			
			if (!err) {
				//	if this is the last block read, then we read <= 512 bytes!
				if (curBlockIndex == lastBlockIndex) {
					*bytesRead = ((i_eof - 1) & 0x000001FF) + 1;
				} else {
					*bytesRead = Pas_kBytesPerBlock;
				}

				real_filePos	+= *bytesRead;

				if (!IsCopyTranslated() || i_fileType != ADFS_File_TEXT) {
					*((Pas_Block *)i_fileBufP) = *blockP;
				} else {
					//	this is TEXT
					//	skip the 1k header at start of text files
					if (curBlockIndex <= 1) {
						*bytesRead = 0;
					} else {
						ushort			loop, fileBufLoop = 0;
						Boolean			doneB = FALSE;
//						ushort			realBytesRead = 0;
						
						for (loop = 0; !doneB && loop < *bytesRead; loop++) {
							if (i_dle_straddleB || blockP->byte[loop] == Pas_TextDLE) {
								ushort		num_spacesS;

								if (!i_dle_straddleB) {
									++loop;
									if (loop == sizeof(Pas_Block)) {
										i_dle_straddleB = TRUE;
									}
								} else {
									i_dle_straddleB = FALSE;
									ASSERT(loop == 0);
								}
								
								if (!i_dle_straddleB) {
									num_spacesS = blockP->byte[loop] - 32;
									
									while (num_spacesS--) {
										i_fileBufP[fileBufLoop++] = ' ';
										ASSERT(fileBufLoop < kPas_TextBufSize);
									}
								}
 							} else if (blockP->byte[loop] == 0) {
								doneB = TRUE;
							} else {
								i_fileBufP[fileBufLoop++] = blockP->byte[loop];
								ASSERT(fileBufLoop < kPas_TextBufSize);
							}
						}
						
						*bytesRead = fileBufLoop;
					}
				}
			}

			if (!err) err = _inherited::ADFS_Read(bytesRead);
			if (!err) i_filePos	= real_filePos;
		}
	}
		
	if (!err) {
		if (curBlockIndex >= lastBlockIndex) {
			err = eofErr;
		}
	}
	
	return err;
}

OSErr		CFilePas::EntryPane_CB_EntryArray(
	TA_IterateType taType, TA_IterateData *cbData)
{
	OSErr		err = noErr;
	
	switch (taType) {

		case ADFS_TA_Iterate_MOVE_FILE_DOWN: {
			err = MoveFileDown((Pas_BlockNum *)cbData);
			break;
		}
		
		default: {
			err = _inherited::EntryPane_CB_EntryArray(taType, cbData);
			break;
		}
	}
	
	return err;
}

OSErr		CFilePas::MoveFileDown(Pas_BlockNum	*firstFreeBlock)
{
	OSErr				err		= noErr;
	Pas_DirEntry		*entryP = GetMyEntry();
	
	if (!entryP) {
		ReportError(err = IC_Err_ENTRY_NOT_FOUND);
	} else {
		if (*firstFreeBlock < GetRboShort(entryP->firstBlock)) {
			Pas_BlockNum	numBlocks	= GetRboShort(entryP->lastBlockPlusOne) - GetRboShort(entryP->firstBlock);
			Pas_BlockNum	curBlock;
			Pas_Block		*blockP;
							
			for (
				curBlock = 0;
				!err && curBlock <= numBlocks;
				curBlock++
			) {
				err = i_cDisk.pas->GetBlock(GetRboShort(entryP->firstBlock) + curBlock, &blockP);
				
				if (!err) {
					
					if (IS_ImageRec_IN_MEMORY(i_cDisk.pas->i_imageRec)) {
						Pas_Block		*destBlockP;
						
						err = i_cDisk.pas->GetBlock(*firstFreeBlock + curBlock, &destBlockP);
						
						if (!err) {
							*destBlockP = *blockP;
						}
					} else {
						i_cDisk.pas->i_recentBlockNum = *firstFreeBlock + curBlock;
					}

					if (!err) err = i_cDisk.pas->SetBlock();
				}
			}
			
			if (!err) {
				entryP->firstBlock			= SetRboShort(*firstFreeBlock);
				entryP->lastBlockPlusOne	= SetRboShort(*firstFreeBlock + numBlocks);
				
				err = i_cDisk.pas->Pas_FlushDirectory();
			}
			
			if (!err) err = i_cDisk.pas->GetFreeBlock(firstFreeBlock);

			if (i_cDisk.gen->i_diskMapP) {
				i_cDisk.gen->i_diskMapP->Refresh(this, TRUE, TRUE);
			}
		} else {
			ASSERT(*firstFreeBlock >= GetRboShort(entryP->lastBlockPlusOne));
		}
	}
	
	return err;
}

OSErr		CFilePas::Delete(Boolean warnB, CDialogCopy *copyP0)
{
	OSErr				err			= noErr;
	Pas_EntryIndex		entryIndex	= i_diskLocDirEntryIndex;
	CFolderPas			*folderP	= (CFolderPas *)GetParentFolder();
	CDiskMapWindow		*diskMapP	= i_cDisk.gen->i_diskMapP;		
	
	if (!err) err = _inherited::Delete(warnB, copyP0);

	if (!err && diskMapP) {
		diskMapP->Refresh();
	}

	if (!err) err = folderP->Pas_DeleteEntry(entryIndex);
	
	return err;
}

OSErr	CFilePas::Pas_WriteBlock(
	ushort			numBytesS, 
	Pas_Block		*blockBufP)
{
	OSErr				err		= noErr;
	Pas_DirEntry 		*entryP = GetMyEntry();
	Pas_Block			*blockP;
	Pas_BlockNum		blockNum;
	
	if (!entryP) {
		ReportError(err = IC_Err_CANT_READ_PASCAL_BLOCK);
	}
	
	if (!err) {
		if (numBytesS > sizeof(Pas_Block)) {
			ReportError(err = IC_Err_CANT_WRITE_MORE_THAN_1);
		}
	}
	
	if (!err) {
		if (!err) err = i_cDisk.pas->GetFreeBlock(&blockNum);
		
		if (GetRboShort(entryP->firstBlock) == 0) {
			//	brand new file, write first block
			entryP->firstBlock = SetRboShort(blockNum);
		} else {
			ASSERT(blockNum == GetRboShort(entryP->lastBlockPlusOne));
		}

		entryP->lastBlockPlusOne = SetRboShort(blockNum + 1);
		if (!err) err = i_cDisk.pas->GetBlock(blockNum, &blockP);

		if (!err) {
			*blockP = *blockBufP;

			entryP->entryType.file.lastByte = SetRboShort(numBytesS);

			if (numBytesS < sizeof(Pas_Block)) {
				memset(&blockP->byte[numBytesS], 0, sizeof(Pas_Block) - numBytesS);
			}
		}
	}
	
	return err;
}

OSErr			CFilePas::ADFS_Write(ushort *bytesWritten)
{
	OSErr			err = noErr;
	Pas_BlockNum	curBlockIndex	= (Pas_BlockNum)(i_filePos >> 9);		//	div by 512
	
	//	error if we're not reading block boundaries
	if (i_filePos != ((ulong)curBlockIndex * (ulong)Pas_kBytesPerBlock)) {
		err = IC_Err_BLOCK_BOUNDARIES;
		ReportError(err);
	}
	
	if (!err) err = _inherited::ADFS_Write(bytesWritten);
	
	if (*bytesWritten > sizeof(Pas_Block)) {
		err = ASSERT(*bytesWritten <= sizeof(Pas_Block) * 2);

		if (!err) err = Pas_WriteBlock(sizeof(Pas_Block), (Pas_Block *)i_fileBufP);
		if (!err) err = Pas_WriteBlock(
			*bytesWritten - sizeof(Pas_Block), 
			(Pas_Block *)&i_fileBufP[sizeof(Pas_Block)]);
	} else {
		if (!err) err = Pas_WriteBlock(*bytesWritten, (Pas_Block *)i_fileBufP);
	}
	
	i_eof = i_filePos;

	return noErr;
}

OSErr		CFilePas::ADFS_Close(void)
{
	OSErr		err = noErr;
	OSErr		err2;
	
	if (i_ioType == ADFS_IO_WRITE) {
		err = i_cDisk.pas->Pas_FlushDirectory();
	}
	
	err2 = _inherited::ADFS_Close();
	if (!err) err = err2;

	return err;
}

/***********************************************************/
OSErr		CFilePas::GetFileBlocks(
	Pas_BlockNum	*fileBlockA0, 
	Pas_BlockNum	*numFileBlocksSP)
{
	OSErr	err	= noErr;
	
	(*numFileBlocksSP) = ((i_eof - 1) >> 9) + 1;	//	eof is base 1, div by 512;

	if (fileBlockA0) {
		Pas_BlockNum	curIndex;
		
		for (curIndex = 0; !err && curIndex < *numFileBlocksSP; curIndex++) {
			err = Pas_GetIndBlockNum(curIndex, &fileBlockA0[curIndex]);
		}
	}
	
	return err;
}

OSErr		CFilePas::GetEntryAlloc(
	Boolean			getAsBlocksB, 
	Gen_EntryAlloc	**sectorListH)
{
	OSErr		err = noErr;
	
	*sectorListH	= (Gen_EntryAlloc *)TrackNewPtrClear(
		"entry sectors, for file", sizeof(Gen_EntryAlloc));
	
	if (*sectorListH == NULL) err = memFullErr;
	
	if (!err) {
		Pas_DirEntry	*entryP	= GetMyEntry();
		Pas_BlockNum	numFileBlocksS;
		Pas_BlockNum	*blockNumP = NULL;
				
		(**sectorListH).allocSize = getAsBlocksB ? Gen_AllocSize_SHORT : Gen_AllocSize_SECTORS;
		
		if (!entryP) {
			err = IC_Err_ENTRY_NOT_FOUND;
		} else {
			numFileBlocksS		= 0;
		}

		if (!err) err = GetFileBlocks(NULL, &numFileBlocksS);
		
		if (!err && numFileBlocksS) {
			blockNumP = (Pas_BlockNum *)TrackNewPtrClear(
				"entry sectors, file blocks", 
				sizeof(Pro_BlockNum) * numFileBlocksS);
			
			if (blockNumP == NULL) err = memFullErr;
			
			if (!err) {
				(**sectorListH).type[Gen_Alloc_FILE].totalS				= numFileBlocksS;
				(**sectorListH).type[Gen_Alloc_FILE].u.short_blocksA	= blockNumP;
				blockNumP = NULL;
			}
		}

		if (!err) {
			numFileBlocksS		= 0;

			err = GetFileBlocks(
				(**sectorListH).type[Gen_Alloc_FILE].u.short_blocksA,	&numFileBlocksS);
		}
	}
	
	if (!err && !getAsBlocksB) {
		err = i_cDisk.pas->EntryBlocksToSectors(*sectorListH);
	}
	
	if (err) {
		DisposeEntryAlloc(*sectorListH);
		*sectorListH = NULL;
	}
	
	return err;
}

OSErr			CFilePas::UnDelete(Boolean recursiveB, CDialogCopy *copyP0)
{
//	OSErr	err = noErr;
	
	return noErr;
}
