/*
 *	FileList.c - Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	11 Apr 1991  23:16:51
 *	Modified:	20 Jul 1991  12:26:18
 *
 *	Make>> make
 */

#include "Global.h"
#include "DosVar.h"
#include "ActionBack.h"
#include "FileList.h"
#include "proto/FileList.h"
#include "proto/File.h"
#include "proto/Mouse.h"
#include "proto/Draw.h"
#include "proto/Request.h"
#include "proto/ActionBack.h"

extern struct Config Config;
extern struct MinList WindowList;
extern char *ReqTitle;


void DeleteDest(char *Name)
{
	short Ok = A_RETRY;

	while (Ok == A_RETRY && !DeleteFile(Name))
		Ok = ThreeGadRequest("Retry", NULL, "Couldn't delete bad copy of \"%s\"\n%s.", Name, StrIoErr());
}


void FreeFileBuffers(struct SuperFileInfo *sfi)
{
	struct BufferList *BL, *Cur;

	if (sfi->FileInfo.fi_Type != DLX_FILE)
		return;
	BL = sfi->FileDir.File.BufferList;
	while(Cur = BL) {
		BL = Cur->Next;
		FreeMem(Cur, Cur->Size+sizeof(struct BufferList));
	}
	sfi->FileDir.File.BufferList = NULL;
}


void FreeSuperFileInfo(struct SuperFileInfo *sfi1, BPTR SrcDir, BPTR DestDir)
{
	struct SuperFileInfo *sfi2;
	struct FileInfoBlock *fib;
	char *Name;
	BPTR CD;

	switch(sfi1->FileInfo.fi_Type) {
	case DLX_FILE:
		FreeFileBuffers(sfi1);
		if (sfi1->FileDir.File.FH_S)
			Close(sfi1->FileDir.File.FH_S);
		if (sfi1->FileDir.File.FH_D) {
			Close(sfi1->FileDir.File.FH_D);
			CD = CurrentDir(DestDir);
			Name = sfi1->FileInfo.fi_Name;
			if (TwoGadRequest(ReqTitle, "File \"%s\" wasn't completly copied\nDelete bad copy ?", Name)) {
				DeleteDest(Name);
				sfi1->ActionBack |= AB_DELETE_DEST;
			}
			else if (fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)) {
				if (GetFib(Name, fib, TRUE) == A_RETRY) {
					Fib2Fi(&sfi1->FileInfo, fib);
					sfi1->ActionBack |= AB_NEW_ENTRY;
				}
				FreeMem(fib, sizeof(struct FileInfoBlock));
			}
			CurrentDir(CD);
		}
		break;
	default:	/* dirs, volumes, devices and assigns */
		while(sfi2 = (struct SuperFileInfo *)RemTail((struct List *)&sfi1->FileDir.Dir.SuperFileList))
			FreeSuperFileInfo(sfi2, sfi1->FileDir.Dir.SrcDir, sfi1->FileDir.Dir.DestDir);
		if (sfi1->FileDir.Dir.SrcDir) {
			SendUpdateDir(sfi1->FileDir.Dir.SrcDir);
			UnLock(sfi1->FileDir.Dir.SrcDir);
		}
		if (sfi1->FileDir.Dir.DestDir) {
			SendUpdateDir(sfi1->FileDir.Dir.DestDir);
			UnLock(sfi1->FileDir.Dir.DestDir);
		}
	}
	SendActionBack(sfi1, SrcDir, DestDir);
	CleanFileInfo(&sfi1->FileInfo);
	FreeMem(sfi1, sizeof(struct SuperFileInfo));
}


void FreeBrowserDir(struct BrowserDir *bd, BPTR DestDir)
{
	struct SuperFileInfo *sfi;

	while(sfi = (struct SuperFileInfo *)RemHead((struct List *)&bd->SuperFileList)) {
		/* if ActionBack has only one of SELECT or DESELECT flags,
		 * an error occured, so reselect entry */
		if (sfi->ActionBack != AB_NONE && !(sfi->ActionBack & ~(AB_SELECT|AB_DESELECT)))
			sfi->ActionBack = AB_SELECT;
		FreeSuperFileInfo(sfi, bd->DirLock, DestDir);
	}
	SendUpdateDir(bd->DirLock);
	/* Check both dir and root locks before unlock() because only one of them may be valid */
	if (bd->DirLock)
		UnLock(bd->DirLock);
	if (bd->RootLock)
		UnLock(bd->RootLock);
	FreeMem(bd, sizeof(struct BrowserDir));
}


void FreeFileList(struct HeadFileList *hfl)
{
	struct BrowserDir *bd;

	while(bd = (struct BrowserDir *)RemTail((struct List *)&hfl->DirList))
		FreeBrowserDir(bd, hfl->DestDir);
	if (hfl->DestDir) {
		SendUpdateDir(hfl->DestDir);
		UnLock(hfl->DestDir);
	}
	if (hfl->DestRoot)
		UnLock(hfl->DestRoot);
	FreeMem(hfl, sizeof(struct HeadFileList));
}


struct HeadFileList *MakeSelectedList(struct BrowserWindow *ExcludeWin, BPTR DestDir, BPTR DestRoot)
{
	struct BrowserWindow *Win;
	struct ScrollEntry *S;
	struct HeadFileList *hfl;
	struct BrowserDir *bd;
	struct SuperFileInfo *sfi;
	struct Point Position;
	short i;

	if (!(hfl = AllocMem(sizeof(struct HeadFileList), MEMF_PUBLIC|MEMF_CLEAR)))
		return NULL;
	if (Config.Select.si_Flags & SI_AFFECT_SUBDIRS)
		hfl->Select = Config.Select;	/* copy the select info for virtual select */
	hfl->CopyMode = Config.CopyMode;
	hfl->CopyFlags = Config.CopyFlags;
	hfl->DestDir = DestDir;
	hfl->DestRoot = DestRoot;
	NewMinList(&hfl->DirList);

	Win = (struct BrowserWindow *)WindowList.mlh_Head;
	while(Win->bw_Node.mln_Succ) {
		if (Win->bw_SelectNum > 0 && Win != ExcludeWin) {
			if (!(bd = AllocMem(sizeof(struct BrowserDir), MEMF_PUBLIC|MEMF_CLEAR))) {
				FreeFileList(hfl);
				return NULL;
			}
			AddTail((struct List *)&hfl->DirList, (struct Node *)bd);
			if (Win->bw_Type == BW_DIR) {
				bd->DirLock = DupLock(Win->bw_DirLock);
				bd->RootLock = DupLock(Win->bw_RootLock);
			}
			NewMinList(&bd->SuperFileList);
			for( i=0 ; i < Win->bw_ShownEntries ; i++ ) {
				S = Win->bw_EntryArray[i];
				if (S->se_State & STATE_SELECTED) {
					if (!(sfi = AllocMem(sizeof(struct SuperFileInfo), MEMF_PUBLIC|MEMF_CLEAR))) {
						FreeFileList(hfl);
						return NULL;
					}
					AddTail((struct List*)&bd->SuperFileList, (struct Node *)sfi);
					CopyFileInfo(&sfi->FileInfo, &S->se_FileInfo);
					sfi->ActionBack = (Config.Options & OPT_KEEPSELECTED) ? AB_SELECT : AB_DESELECT;
					/* Now, save file name because some actions create a new one (rename, duplicate,...)*/
					strcpy(sfi->OldName, sfi->FileInfo.fi_Name);
					hfl->NumEntries++;
					DoSelect(Win, S, OPT_TOGGLESELECT);		/* deselect entry */
					/* change state from SELECTED to GHOSTED */
					S->se_State = STATE_GHOSTED;
					switch(sfi->FileInfo.fi_Type) {
					case DLX_FILE:
						break;
					case DLX_DIR:
						NewMinList(&sfi->FileDir.Dir.SuperFileList);
						hfl->Dirs = TRUE;
						break;
					default:
						NewMinList(&sfi->FileDir.Dir.SuperFileList);
						hfl->Vols = TRUE;	/* same flag for Assigns, Volumes and devices */
					}
					if (GetSePosition(Win, S, &Position))
						Print(Win, S, Position.X, Position.Y);
				}
			}
		}
		MakeBottomInfoString(Win);
		RefreshBottomInfo(Win);
		Win = (struct BrowserWindow *) Win->bw_Node.mln_Succ;
	}
	RefreshBottomInfo((struct BrowserWindow *)WindowList.mlh_Head);
	return hfl;
}


