#include <stdio.h>
#ifndef __GNUC__
	#include "Finder.h"
#endif

#include "ADFS_LogFile.h"
#include "MemUtils.h"
#include "Pro_Utils.h"
#include "FSUtils.h"
#include "IC_FileIO.h"
#include "IC_Errors.h"
#include "CCopyFile_FsSpec.h"

/**********************************************/
OSErr			CCopyFile_FsSpec::ICopyFile_FsSpec(
	CCopyFile		*parent0, 
	Ptr				myData)
{
	OSErr		err		= noErr;
	FSSpec		*fsSpec	= (FSSpec *)TrackNewPtr("file spec", sizeof(FSSpec));
	
	if (!fsSpec) err = memFullErr;
	
	if (!err) {
		*fsSpec = *(FSSpec *)myData;
		
		err = _inherited::ICopyFile(parent0, CCT_Copy_FSSPEC, (Ptr)fsSpec);
	}
		
	return err;
}

void			CCopyFile_FsSpec::Dispose(void)
{
	ASSERT(i_myFileData == NULL);
	ASSERT(i_myData);
	
	_inherited::Dispose();
}

/**********************************************/
FSSpec			*CCopyFile_FsSpec::GetFSSpec(void)
{
	return (FSSpec *)(i_myFileData == NULL ? i_myData : i_myFileData);
}

OSErr			CCopyFile_FsSpec::GetFileInfo(CCT_MemFileRec *fileRecP)
{
	OSErr		err = noErr;

	if (!err) {
		FInfo		fInfo;
		Boolean		isLockedB;
		FSSpec		*fileSpecP = GetFSSpec();
				
		if (!err) err = FSpGetCatFInfo(fileSpecP, &fInfo);
		if (!err) err = FSpGetFileLock(fileSpecP, &isLockedB);
		if (!err) err = FSpGetFileDates(fileSpecP, &fileRecP->creDate, &fileRecP->modDate);

		if (!err) {
			CopyPascalStringToC(fileSpecP->name, fileRecP->nameAC);
			
			Mac_To_Pro_FileType(
				fInfo.fdType, &fileRecP->fileType, &fileRecP->auxType);

			fileRecP->access.destroyEnable	= !isLockedB;
			fileRecP->access.renameEnable	= (fInfo.fdFlags & kNameLocked) == 0;
			fileRecP->access.backup			= FALSE;
			fileRecP->access.writeEnable	= !isLockedB;
			fileRecP->access.readEnable		= TRUE;

			fileRecP->forkedB = IsForked();

			err = _inherited::GetFileInfo(fileRecP);
		}
	}
	
	return err;
}

OSErr			CCopyFile_FsSpec::SetFileInfo(CCT_MemFileRec *fileRecP)
{
	OSErr		err			= noErr;
	FSSpec		*fsSpecP	= GetFSSpec();
	Boolean		isFolderB;
	FInfo		fInfo;

	if (!err) err = FSpSetFileDates(
		fsSpecP, 
		&fileRecP->creDate, 
		&fileRecP->modDate);
	
	if (!err) err = FSpIsFolder(fsSpecP, &isFolderB);
	
	//	don't lock folders on MacOS
	if (!err && !isFolderB) {
		err = FSpSetFileLock(
			fsSpecP, 
			!fileRecP->access.writeEnable);
	}
		
	if (!err) err = FSpGetCatFInfo(fsSpecP, &fInfo);
	if (!err) {
		fInfo.fdFlags |= kNameLocked;
		
		if (fileRecP->access.renameEnable) {
			fInfo.fdFlags &= ~kNameLocked;
		}
		
		err = FSpSetCatFInfo(fsSpecP, &fInfo);
	}
	
	if (!err) err = _inherited::SetFileInfo(fileRecP);
	
	return err;
}

/**********************************************/
OSErr			CCopyFile_FsSpec::IsFolder(Boolean *isFolderB)
{
	OSErr		err = noErr;
	FSSpec		*fileSpecP = GetFSSpec();
	
	if (!err) err = FSpIsFolder(fileSpecP, isFolderB);
	
	return err;
}

OSErr			CCopyFile_FsSpec::CountFilesInFolder(ulong *numFilesL)
{
	OSErr		err				= noErr;
	FSSpec		*folderSpecP	= GetFSSpec();
	
	err = FSpCountFilesInFolder(folderSpecP, numFilesL);
	
	return err;
}

OSErr			CCopyFile_FsSpec::GetIndFileInFolder(ulong fileIndex, Ptr *fileDataP)
{
	OSErr		err				= noErr;
	FSSpec		*folderSpecP	= GetFSSpec();

	err = FSpGetIndFileInFolder(folderSpecP, fileIndex, &i_indFileSpec);
	
	if (!err) {
		*fileDataP = (Ptr)&i_indFileSpec;
	}
	
	return err;
}

/**********************************************/
OSErr			CCopyFile_FsSpec::CreateFile(Ptr parentFolderP, CCT_MemFileRec *fileRecP)
{
	OSErr		err = noErr;
	OSType		fileType, fileCreator;
	FSSpec		*parentFileSpecP	= (FSSpec *)parentFolderP;
	FSSpec		*returnSpecP		= (FSSpec *)TrackNewPtr("file spec", sizeof(FSSpec));
	
	if (!returnSpecP) err = memFullErr;
	
	if (!err) err = FSpGetFolderID(parentFileSpecP, &returnSpecP->parID);
	
	if (!err) {
		CopyCStringToPascal(fileRecP->nameAC, returnSpecP->name);

		if (fileRecP->fileType != Pro_FileType_DIR) {
			Pro_To_Mac_FileType(
				fileRecP->fileType, fileRecP->auxType, 
				&fileType, &fileCreator);
		}
	}
	
	if (!err) err = FSMakeFSSpec(
		parentFileSpecP->vRefNum, returnSpecP->parID, 
		returnSpecP->name, returnSpecP);
	
	if (err == fnfErr) {
		//	if the file ain't there, then we gotta make it
		
		err = FSpCreateFileOrFolder(
			returnSpecP, fileType, fileCreator, 
			fileRecP->fileType == Pro_FileType_DIR);
	} else if (fileRecP->fileType != Pro_FileType_DIR) {
		err = FSpSetFileLock(returnSpecP, FALSE);

		if (!err) err = FSpSetFileTypeAndCreator(
			returnSpecP, fileCreator, fileType);
	}
	
	if (!err) {
		i_myFileData = (Ptr)returnSpecP;
	}
	
	if (err) ReportOSErr(err);
	
	return err;
}

void			CCopyFile_FsSpec::DisposeData(void)
{
	FSSpec		*fsSpecP = GetFSSpec();
	
	if (fsSpecP) {
		TrackDisposePtr((Ptr)fsSpecP);
	}

	_inherited::DisposeData();
}
	
/**********************************************/
OSErr			CCopyFile_FsSpec::Open(ADFS_IOType ioType, Boolean resForkB)
{
	OSErr		err	= _inherited::Open(ioType, resForkB);
	
	if (!err) {
		FSSpec		*fileSpecP	= GetFSSpec();
		
		if (i_res_forkB) {
			err = FSpOpenRF(fileSpecP, ioType == ADFS_IO_WRITE ? fsRdWrPerm : fsCurPerm, &i_fileRefNum);
		} else {
			err = FSpOpenDF(fileSpecP, ioType == ADFS_IO_WRITE ? fsRdWrPerm : fsCurPerm, &i_fileRefNum);
		}
	}
	
	return err;
}

OSErr			CCopyFile_FsSpec::Close(void)
{
	OSErr		err = noErr;
	
	if (!err) err = _inherited::Close();
	if (!err) err = FSFlushFile(i_fileRefNum);
	if (!err) err = FSClose(i_fileRefNum);

	i_fileRefNum = 0;
	
	return err;
}

OSErr			CCopyFile_FsSpec::Read(ulong *bytesIO, char *bufP)
{
	OSErr		err = noErr;

	err = FSRead(i_fileRefNum, (long *)bytesIO, bufP);

	return err;
}

OSErr			CCopyFile_FsSpec::Write(ulong *bytesIO, char *bufP)
{
	OSErr		err = noErr;
	
	err = FSWrite(i_fileRefNum, (long *)bytesIO, bufP);

	return err;
}

OSErr			CCopyFile_FsSpec::VerifyFreeSpace(CCT_CopyRec *copyRecP)
{
	OSErr		err			= noErr;
	FSSpec		*fileSpecP	= GetFSSpec();
	ulong		freeSpaceL;
	
	if (!err) err = FSGetVolSize(fileSpecP->vRefNum, &freeSpaceL);
	if (!err) {
		if (copyRecP->totalSizeL > freeSpaceL) {
			ReportError(err = IC_Err_DISK_FULL);
		}
	}
	
	if (!err) err = _inherited::VerifyFreeSpace(copyRecP);
	
	return err;
}

OSErr			CCopyFile_FsSpec::VerifyFileSize(CCopyFile *sourceP, ulong fileSizeL)
{
	return _inherited::VerifyFileSize(sourceP, fileSizeL);
}

OSErr			CCopyFile_FsSpec::GetSizeSelf(CCT_CopyRec *copyRecP)
{
	OSErr		err = noErr;
	Boolean		isFolderB;
	
	err = IsFolder(&isFolderB);
	
	if (!err) {
		if (!isFolderB) {
			FSSpec		*fileSpecP	= GetFSSpec();
			long		fileSizeL;

			err = FSpGetEOF(fileSpecP, &fileSizeL);

			if (!err) {
				copyRecP->totalItemsS++;
				copyRecP->totalSizeL += fileSizeL;
				
				err = FSpGetResEOF(fileSpecP, &fileSizeL);

				if (!err) {
					copyRecP->totalSizeL += fileSizeL;
				}
			}
		}
	}

	if (!err) err = _inherited::GetSizeSelf(copyRecP);

	return err;
}

Boolean			CCopyFile_FsSpec::IsForked(void)
{
	OSErr		err			= noErr;
	Boolean		isForkedB	= FALSE;
	Boolean		isFolderB;
	
	err = IsFolder(&isFolderB);
	
	if (!err) {
		if (!isFolderB) {
			FSSpec		*fileSpecP	= GetFSSpec();
			long		fileSizeL;

			err = FSpGetResEOF(fileSpecP, &fileSizeL);
			
			if (!err) {
				isForkedB = fileSizeL > 0;
			}
		}
	}
	
	return isForkedB;
}

Boolean			CCopyFile_FsSpec::SupportsForks(void)
{
	return TRUE;
}

OSErr			CCopyFile_FsSpec::GetForkInfo(CCT_ForkInfo *forkInfoP)
{
	OSErr		err			= noErr;
	FSSpec		*mySpecP	= GetFSSpec();
	
	err = ASSERT(IsForked());

	if (!err) err = FSpGetFInfo(mySpecP, (FInfo *)&forkInfoP->fileInfo);
	if (!err) forkInfoP->hasFInfo = TRUE;

	if (!err) err = FSpGetXFInfo(mySpecP, &forkInfoP->xFileInfo);
	if (!err) forkInfoP->hasXFInfo = TRUE;
	
	return FALSE;
}

OSErr			CCopyFile_FsSpec::SetForkInfo(CCT_ForkInfo *forkInfoP)
{
	OSErr		err			= noErr;
	FSSpec		*mySpecP	= GetFSSpec();

	err = ASSERT(IsForked());
	
	if (!err && forkInfoP->hasFInfo) {
		err = FSpSetFInfo(mySpecP, &forkInfoP->fileInfo);
	}

	if (!err && forkInfoP->hasXFInfo) {
		err = FSpSetXFInfo(mySpecP, &forkInfoP->xFileInfo);
	}
	
	return FALSE;
}

OSErr			CCopyFile_FsSpec::ScanForCopySelf(Ptr testDataP, CCopyFile **fileExistsH)
{
	OSErr		err			= noErr;
	FSSpec		*mySpecP	= GetFSSpec();
	FSSpec		*testSpecP	= (FSSpec *)testDataP;

	if (
		mySpecP->name[0] == testSpecP->name[0]
		&& memcmp(&mySpecP->name[1], &testSpecP->name[1], testSpecP->name[0]) == 0
		&& mySpecP->vRefNum == testSpecP->vRefNum
		&& mySpecP->parID == testSpecP->parID
	) {
		*fileExistsH = this;
	}
	
	return err;
}

OSErr			CCopyFile_FsSpec::GetParentRef(Ptr *parentFolderH)
{
	OSErr		err			= noErr;
	FSSpec		*mySpecP	= GetFSSpec();

	err = FSpGetParentFolder(mySpecP, &i_parentFileSpec);
	if (!err) {
		*parentFolderH = (Ptr)&i_parentFileSpec;
	}

	return err;
}

OSErr			CCopyFile_FsSpec::GetVolumeRef(Ptr *volumeH)
{
	OSErr		err			= noErr;
	FSSpec		*mySpecP	= GetFSSpec();
	
	err = FSpGetParentVolume(mySpecP, &i_parentFileSpec);
	if (!err) {
		*volumeH = (Ptr)&i_parentFileSpec;
	}
	
	return err;
}

OSErr			CCopyFile_FsSpec::Delete(void)
{
	OSErr		err			= noErr;
	FSSpec		*mySpecP	= GetFSSpec();
	char		strAC[256];
	char		strAC2[256];
	
	err = FSpDelete(mySpecP);
	CopyPascalStringToC(mySpecP->name, strAC2);
	sprintf(strAC, "Can't delete file Ò%sÓ.", strAC2);
	if (err) ReportErrorStr(err, strAC);
	
	return err;
}

void			CCopyFile_FsSpec::LogCopyFileType(void)
{
	FSSpec		*mySpecP	= GetFSSpec();
	char		pathAC[kMaxFilePathLen];
	OSErr		err = FSpGetFullPath(mySpecP, kMaxFilePathLen, pathAC);

	if (!err) {
		ADFS_Log("the MacOS disk '");
		ADFS_Log(pathAC);
		ADFS_Log("'");
	} else {
		ADFS_Log("a MacOS disk");
	}
}

