//	CFolderPas.c

#include "IC_Errors.h"
#include "CDesktop.h"
#include "CFilePas.h"
#include "CDiskPas.h"
#include "CFolderPas.h"

OSErr		CFolderPas::IFolderPas(
	CDiskPas		*cDiskPas, 
	Pas_BlockNum	block
) {
	OSErr				err = noErr;
	Pas_EntryIndex		entryIndex		= 0;		//	relative to cur dir sector
	Pas_EntryIndex		dirIndex		= 0;		//	relative to entire directory
	DiskLocSpecUnion	locSpec;
	
	locSpec.pro = SetRboShort(block);
	
	err = _inherited::IFolder(
		cDiskPas, NULL, locSpec, 
		entryIndex, dirIndex);

	if (!err) err = Pas_ForEachEntry(Pas_MakeNewEntryCB, &dirIndex);
	
	return err;
}

void			CFolderPas::Dispose(void)
{
	_inherited::Dispose();
}

OSErr			CFolderPas::Pas_ForEachEntry(
	Pas_ForEachEntryCB	Pas_ForEachUserCB, 
	void				*data)
{
	OSErr				err = noErr;
	Pas_DirEntry		*dirEntryP;
	Pas_EntryIndex		entryIndex	= 0;	//	relative to cur dir sector
//	Pas_EntryIndex		dirIndex	= 0;	//	relative to entire directory
	Boolean				doneB = FALSE;
	
	for (
		entryIndex = 0; 
		!doneB && !err 
			&& entryIndex <= i_cDisk.pas->i_directory.index[0].entryType.volume.numFiles;
		entryIndex++
	) {
		dirEntryP	= &i_cDisk.pas->i_directory.index[entryIndex];

		err = (*Pas_ForEachUserCB)(
			this, dirEntryP, Pas_kDirStartBlock, 
			entryIndex, &doneB, data);
	}

	return err;
}

//	static
OSErr	CFolderPas::Pas_MakeNewEntryCB(
	CFolderPas			*thiz, 
	Pas_DirEntry		*entry, 
	Pas_BlockNum		blockNum, 
	Pas_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data)
{
	OSErr				err			= noErr;
	Pas_EntryIndex		*dirIndex	= (Pas_EntryIndex *)data;
	
	//	the zeroeth one is the volume index, so skip that
	//	the rest are kept contiguous, so there are no "empty" entries
	
	if (entryIndex > 0) {
		(*dirIndex)++;	
		err	= thiz->Pas_MakeNewEntry(entry, blockNum, entryIndex, *dirIndex, NULL);
	}
	
	return err;
}

OSErr			CFolderPas::Pas_MakeNewEntry(
	Pas_DirEntry		*entry, 
	Pas_BlockNum		blockNum, 
	Pas_EntryIndex		entryIndex, 	//	within cur sector
	Pas_EntryIndex		directoryIndex, //	within entire catalog
	CEntry				**newEntry0)
{
	OSErr		err = noErr;
	CFilePas	*cFile;
	
	if (NewObject(cFile, CFilePas, err)) {
	
		err = cFile->IFilePas(
			i_cDisk.pas, this, blockNum, entryIndex, directoryIndex);

		if (err) {
			cFile->Dispose();
		} else {
			if (newEntry0) {
				*newEntry0 = cFile;
			}
		}
	}
	
	return err;
}

static	OSErr	Pas_GetUniqueNameCB(
	CFolderPas			*thiz, 
	Pas_DirEntry		*entryP, 
	Pas_BlockNum		blockNum, 
	Pas_EntryIndex		entryIndex, 
	Boolean				*done, 
	void				*data
) {
	if (entryIndex > 0) {
		Gen_GetUniqueNameRec	*nameRec = (Gen_GetUniqueNameRec *)data;
		Pas_TitleIDStr			entryName;
		
		Pas_GetName(entryP, entryName);
		
		if (strcmp(entryName, nameRec->name) == 0) {
			nameRec->unique	= FALSE;
			*done			= TRUE;
		}
	}

	return noErr;
}

Boolean			CFolderPas::GetUniqueName(char *fileName)
{
	OSErr					err		= noErr;
	Boolean					done	= FALSE;
	Gen_GetUniqueNameRec	nameRec;
	
	Pas_SanitizeName(fileName, Pas_kTitleIDLength);

	nameRec.name	= fileName;
	nameRec.unique	= TRUE;
	err	= Pas_ForEachEntry(Pas_GetUniqueNameCB, &nameRec);
	
	if (err) {
		nameRec.unique	= FALSE;
	} else if (!nameRec.unique) {
		Pas_TitleIDStr			finalNameAC;
		short					loop;
		
		nameRec.name	= finalNameAC;
		fileName[Pas_kTitleIDLength - 3] = 0;
		
		for (loop = 1; !done && loop <= 99; loop++) {
			nameRec.unique	= TRUE;
			sprintf(finalNameAC, "%s_%.2d", fileName, loop);
			err	= Pas_ForEachEntry(Pas_GetUniqueNameCB, &nameRec);

			if (err) {
				done			= TRUE;
				nameRec.unique	= FALSE;
			} else if (nameRec.unique) {
				done = TRUE;
				strcpy(fileName, finalNameAC);
			}
		}
	}
	
	return nameRec.unique;
}

static	Pas_DateRec	Pas_GetCurDate(void)
{
	DateTimeRec		dt;
	Pas_DateRec		dateTime;
	
	GetTime(&dt);
	Pas_MacToPasDate(&dt, &dateTime);
	return dateTime;
}

OSErr	CFolderPas::NewFile(Boolean isFolderB, CEntry **entryH)
{
	OSErr					err = noErr;
	O_CTopic				*topic		= NULL;
	CEntry					*newEntry	= NULL;
	Pas_EntryIndex			entryIndex	= 0;	
	Pas_EntryIndex			numFiles	= -1;	
	Pas_DirEntry			*dirEntryP = GetMyEntry();
	Pas_DirEntry			*entryP;
	Pas_TitleIDStr			fileNameAC;
	
	*entryH = NULL;
	
	if (isFolderB) {
		err = IC_Err_NOT_REALLY_A_FOLDER;
		goto new_file_done;
	}

	strcpy(fileNameAC, "NEWFILE");
	if (!GetUniqueName(fileNameAC)) {
		ReportError(err = IC_Err_FILE_ALREADY_EXISTS);
		goto new_file_done;
	}

	if (dirEntryP->entryType.volume.numFiles == Pas_kMaxDirEntries) {
		ReportError(err = IC_Err_NO_DIR_ENTRY);
		goto new_file_done;
	} else {
		numFiles	= dirEntryP->entryType.volume.numFiles;	
		entryIndex	= ++dirEntryP->entryType.volume.numFiles;
		dirEntryP->entryType.volume.lastBoot = Pas_GetCurDate();
	}
	
	entryP = GetEntry(Pas_kDirStartBlock, entryIndex);

	if (entryP == NULL) {
		ReportError(err = IC_Err_NO_DIR_ENTRY);
		goto new_file_done;
	}
	
	entryP->firstBlock				= SetRboShort(0);
	entryP->lastBlockPlusOne		= SetRboShort(0);
	entryP->fileKind				= SetRboShort(Pas_FileKind_DATA);
	CopyCStringToPascal(fileNameAC, entryP->entryType.file.titleID);
	entryP->entryType.file.lastByte	= SetRboShort(0);
	entryP->entryType.file.access	= Pas_GetCurDate();
	
	err = i_cDisk.pas->Pas_FlushDirectory();
	if (err) goto new_file_error;
	
	if (GetParentFolder()) {
		topic = i_topicRef.cTopic;
	} else {
		topic = i_cDisk.pas->i_topicRef.cTopic;
	}
	
	err = topic->O_SetRecent();
	if (err) goto new_file_error;
	
	newEntry = GetTopicEntry(topic);
	if (!newEntry) goto new_file_error;
	
	newEntry->i_addTopicIndex = entryIndex - 1;
	newEntry = NULL;

	err = Pas_MakeNewEntry(
		entryP, Pas_kDirStartBlock, 
		entryIndex, entryIndex, &newEntry);

	if (err) goto new_file_error;
	goto new_file_done;

	//	if error, try to back out, ignore any other errors
	new_file_error:
	if (newEntry) {
		newEntry->Dispose();
		newEntry = NULL;
	}
	
	if (numFiles != (Pas_EntryIndex)-1) {
		dirEntryP->entryType.volume.numFiles = numFiles;
		(void)i_cDisk.pas->Pas_FlushDirectory();
	}

	new_file_done:
	*entryH = newEntry;

	return err;
}

Pas_DirEntry	*CFolderPas::GetEntry(Pas_BlockNum block, Pas_EntryIndex entryIndex)
{
	return &i_cDisk.pas->i_directory.index[entryIndex];
}

Pas_DirEntry	*CFolderPas::GetMyEntry(void)
{
	return GetEntry(Pas_kDirStartBlock, 0);
}

OSErr			CFolderPas::Pas_DeleteEntry(Pas_EntryIndex entryIndex)
{
	OSErr				err = noErr;

	err = i_cDisk.pas->FlushMemDisk(FALSE);
	
	if (!err) {
		OSErr				err2;
//		Boolean				doneB = FALSE;
		Pas_DirEntry		*entryP;

		entryP = GetMyEntry();
		if (entryP == NULL) err = IC_Err_ENTRY_NOT_FOUND;
		
		/*
			things that are ONE based for dir entries have zero as the dir itself
			things that are ZERO based have no entry for the dir itself
			
			entryIndex							= ONE based
			entryP->entryType.volume.numFiles	= ZERO based  ie: N == (0..N-1)
			i_cDisk.pas->i_directory.index[]	= ONE based
			GetIndEntry()						= ZERO based
			
			so be careful with arithmatic!!
		*/
		
		if (entryP->entryType.volume.numFiles >= entryIndex) {
		
			//	set the time here?
			//	entryP->entryType.volume.loadTime = SetRboShort(?);
			entryP->entryType.volume.lastBoot = Pas_GetCurDate();
			entryP->entryType.volume.numFiles--;
			
			if (entryP->entryType.volume.numFiles >= entryIndex) {
				memmove(
					&i_cDisk.pas->i_directory.index[entryIndex], 
					&i_cDisk.pas->i_directory.index[entryIndex + 1], 
					sizeof(Pas_DirEntry) * (entryP->entryType.volume.numFiles - entryIndex + 1));

				err = OffsetEachFile(
					(CFilePas *)GetIndEntry(entryIndex - 1),
					(CFilePas *)GetIndEntry(entryP->entryType.volume.numFiles - 1), 
					-1);
			}

			if (!err) err = i_cDisk.pas->Pas_FlushDirectory();
			if (!err) err = i_cDisk.pas->Optimize();
		}
		
		err2 = i_cDisk.pas->FlushMemDisk(TRUE);
		if (!err) err = err2;
	}
	
	UnCacheFolderSizes();

	return err;
}

OSErr			CFolderPas::Delete(Boolean warnB, CDialogCopy *copyP0)
{
	return DeleteFolderContents(warnB, copyP0);
}

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

