/*
 *	Scan.c - Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	17 Feb 1991  10:40:09
 *	Modified:	21 Jul 1991  16:16:24
 *
 *	Make>> make
 */

#include "Global.h"
#include "proto/Scan.h"
#include "proto/File.h"
#include "proto/String.h"
#include "proto/Windows.h"
#include "proto/Mouse.h"
#include "proto/Draw.h"
#include "proto/Sort.h"


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


BOOL ScanDevs(void)
{
	struct BrowserWindow *Win;
	struct DirectoryEntry *DList = NULL, *d;
	struct ScrollEntry *S, *Tab;
	char *sptr;
	char format[10];
	short i,n,len = 0;
	BOOL Ok = FALSE;	/* assume the worst */

	Win = (struct BrowserWindow *)WindowList.mlh_Head;
	ResetWindow(Win);
	n = AddDADevs(&DList, Config.Display);
	if ((Win->bw_EntryArray = AllocMem(n<<2, MEMF_PUBLIC|MEMF_CLEAR))
		&& (Tab = AllocMem(n*sizeof(struct ScrollEntry), MEMF_PUBLIC|MEMF_CLEAR)) ) {
		d = DList;
		for( i=0 ; i<n ; i++ ) {
			S = &Tab[i];
			Win->bw_EntryArray[i] = S;
			strcpy(S->se_FileInfo.fi_Name, d->de_Name);
			len = MAX(len, strlen(d->de_Name));
			switch(S->se_FileInfo.fi_Type = d->de_Type) {
			case DLX_ASSIGN:
				S->se_Pen = 1;
				break;
			case DLX_DEVICE:
				S->se_Pen = 2;
				break;
			case DLX_UNMOUNTED:
			case DLX_VOLUME:
				S->se_Pen = 3;
			}
			d = d->de_Next;
		}
		FreeDAList(DList);
		SPrintf(format, "%%-%ds", len);
		if (sptr = AllocMem(n*(len+1), MEMF_PUBLIC)) {
			for( i=0 ; i<n ; i++ ) {
				S = Win->bw_EntryArray[i];
				S->se_Print = sptr;
				SPrintf(sptr, format, S->se_FileInfo.fi_Name);
				sptr += len+1;
			}
			Win->bw_ShownEntries = Win->bw_NumEntries = n;
			Win->bw_PrintStringLen = len;
			RefreshWindow(Win);
			MakeMainBottomInfoString();
			Ok = TRUE;
		}
	}
	return Ok;
}


BOOL UpdateEntryList(struct BrowserWindow *Win, BOOL BuildStrings)
{
	struct ScrollEntry *S, *Next;

	if (Win->bw_NumEntries > 0) {
		FreeMem(Win->bw_EntryArray, Win->bw_NumEntries<<2);
		Win->bw_EntryArray = NULL;
	}
	/* remove deleted entries */
	S = (struct ScrollEntry *)Win->bw_EntryList.mlh_Head;
	while(Next = (struct ScrollEntry *)S->se_Node.mln_Succ) {
		if (S->se_State & STATE_DELETED) {
			Win->bw_NumBytes -= S->se_FileInfo.fi_Size;
			Win->bw_NumBlocks -= S->se_FileInfo.fi_NumBlocks;
			if (S->se_FileInfo.fi_Type == DLX_FILE)
				Win->bw_NumFiles--;
			else
				Win->bw_NumDirs--;
			Remove((struct Node *)S);
			CleanFileInfo(&S->se_FileInfo);
			if (S->se_Print)
				FreeMem(S->se_Print, Win->bw_PrintStringLen+1);
			FreeMem(S, sizeof(struct ScrollEntry));
		}
		S = Next;
	}
	Win->bw_NumEntries -= Win->bw_NumDeleted;
	Win->bw_NumDeleted = 0;
	/* add new entries to current list */
	while(S = (struct ScrollEntry *)RemHead((struct List *)&Win->bw_NewEntryList)) {
		AddTail((struct List *)&Win->bw_EntryList, (struct Node *)S);
		Win->bw_NumBlocks += S->se_FileInfo.fi_NumBlocks;
		Win->bw_NumBytes += S->se_FileInfo.fi_Size;
		if (S->se_FileInfo.fi_Type == DLX_FILE)
			Win->bw_NumFiles++;
		else
			Win->bw_NumDirs++;
		if (BuildStrings) {
			if (MatchFilters(&S->se_FileInfo, &Win->bw_FiltersInfo)) {
				if (!(S->se_Print = AllocMem(Win->bw_PrintStringLen+1, MEMF_PUBLIC)))
					return FALSE;
				BuildPrintString(Win, S);
			}
		}
	}
	Win->bw_NumEntries += Win->bw_NumNewEntries;
	Win->bw_NumNewEntries = 0;
	if (Win->bw_NumEntries > 0 && !(Win->bw_EntryArray = AllocMem(Win->bw_NumEntries<<2, MEMF_PUBLIC)))
		return FALSE;
	return TRUE;
}


BOOL List2Array(struct BrowserWindow *Win)
{
	struct ScrollEntry *S, *Next;
	short i=0;
	BOOL Ok;

	FreePrintStrings(Win);
	if (Win->bw_Flags & (BWF_REBUILD_ARRAY|BWF_REBUILD_STRINGS) && !UpdateEntryList(Win, FALSE))
		return FALSE;
	Win->bw_MaxFilenameLen = Win->bw_NewMaxFilenameLen = 0;
	Win->bw_ShownFiles = Win->bw_ShownDirs = 0;
	Win->bw_ShownBytes = Win->bw_ShownBlocks = 0;
	S = (struct ScrollEntry *)Win->bw_EntryList.mlh_Head;
	while(Next = (struct ScrollEntry *)S->se_Node.mln_Succ) {
		if (MatchFilters(&S->se_FileInfo, &Win->bw_FiltersInfo)) {
			Win->bw_MaxFilenameLen = MAX(Win->bw_MaxFilenameLen, strlen(S->se_FileInfo.fi_Name));
			Win->bw_EntryArray[i++] = S;
			if (S->se_FileInfo.fi_Type == DLX_FILE)
				Win->bw_ShownFiles++;
			else
				Win->bw_ShownDirs++;
			Win->bw_ShownBytes += S->se_FileInfo.fi_Size;
			Win->bw_ShownBlocks += S->se_FileInfo.fi_NumBlocks;
		}
		else if (S->se_State & STATE_SELECTED)
			DoSelect(Win, S, OPT_TOGGLESELECT);
		S = Next;
	}
	Win->bw_ShownEntries = i;
	if (Ok = BuildPrintStrings(Win))
		Sort(Win);
	return Ok;
}


static BOOL RecordFile(struct BrowserWindow *Win, struct FileInfoBlock *fib)
{
	struct ScrollEntry *S;

	if (!(S = AllocMem(sizeof(struct ScrollEntry), MEMF_PUBLIC|MEMF_CLEAR)))
		return FALSE;
	Fib2Fi(&S->se_FileInfo, fib);
	switch(S->se_FileInfo.fi_Type) {
	case DLX_FILE:
		S->se_Pen = 1;
		Win->bw_NumFiles++;
		break;
	case DLX_DIR:
		S->se_Pen = 3;
		Win->bw_NumDirs++;
		break;
	}
	Win->bw_NumEntries++;
	Win->bw_NumBlocks += fib->fib_NumBlocks;
	Win->bw_NumBytes += fib->fib_Size;
	AddTail((struct List *)&Win->bw_EntryList, (struct Node *)S);
	SPrintf(Win->bw_BottomText, " %03d %s", Win->bw_NumEntries, S->se_FileInfo.fi_Name);
	RefreshBottomInfo(Win);
	return TRUE;
}


BOOL ScanDir(struct BrowserWindow *Win)
{
	struct FileInfoBlock *fib;
	BOOL Ok = TRUE;

	if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
		return FALSE;
	SetWaitPointer(TRUE);
	ResetWindow(Win);
	if (Examine(Win->bw_DirLock, fib) && fib->fib_DirEntryType>0) {
		while (ExNext(Win->bw_DirLock, fib) && RecordFile(Win, fib));
		if (IoErr() != ERROR_NO_MORE_ENTRIES)
			SimpleRequest(ReqTitle, "Error reading directory\n%s.", StrIoErr());
	}
	FreeMem(fib, sizeof(struct FileInfoBlock));
	if (Win->bw_NumEntries > 0) {
		if (Win->bw_EntryArray = AllocMem(Win->bw_NumEntries<<2, MEMF_PUBLIC))
			Ok = List2Array(Win);
		else
			Ok = FALSE;
	}
	MakeBottomInfoString(Win);
	RefreshWindow(Win);
	SetWaitPointer(FALSE);
	return Ok;
}


