/*

		File List Utility

*/

#include "screensv.h"

struct fileListItem **fileList = NULL;	// File list
int fileListLength = 0;			// Number of files in list
static int fileListMax = 0;		// Maximum files in current list

struct fileListItem **soundFileList = NULL;	// Sound file list
int soundFileListLength = 0;	// Number of files in list
static int soundFileListMax = 0;// Maximum files in current list

int fileListStatus = 0;			// Status from building file list

#define InitialList	100			// Initial list size
#define GrowList	50			// Growth increment

/*	fileListFilter  --  Filter function to determine
						whether to include a file in the
						list.  Passed the WIN32_FIND_DATA,
						it returns 0 if the file is not
						to be included, 1 if the file is an
						image file, and 2 if the file is a
						sound file.  */

static int fileListFilter(WIN32_FIND_DATA *fd)
{
	int i;
	/*	A leading "." denotes an image file, "!" a wave audio file,
		"#" is a MIDI file.  */

	char *extensions[] = {
		".jpg",
		".gif",
		".bmp",
		".png",
		".jif",
		".jpeg",
		"!wav",
		"#mid",
		"#rmi",
		NULL
	};

	//	Skip directories and zero-length files

	if ((fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
		((fd->nFileSizeHigh | fd->nFileSizeLow) == 0)) {
		return FALSE;
	}

	for (i = 0; extensions[i] != NULL; i++) {
		char extt[10];

		strcpy(extt, extensions[i]);
		extt[0] = '.';
		if (_stricmp(extt,
				fd->cFileName +
					(strlen(fd->cFileName) - strlen(extensions[i]))) == 0) {
			return (*extensions[i] == '.') ? 1 : ((*extensions[i] == '!') ? 2 : 3);
		}
	}
	return FALSE;
}

//	file ListDestroy  --  Destroy a file list, releasing all storage

void fileListDestroy(void)
{
	int i;

	if (fileList != NULL) {
		for (i = 0; i < fileListLength; i++) {
			GlobalFree(fileList[i]);
		}
		GlobalFree(fileList);	
	}
	fileList = NULL;
	fileListLength = fileListMax = 0;

	if (soundFileList != NULL) {
		for (i = 0; i < soundFileListLength; i++) {
			GlobalFree(soundFileList[i]);
		}
		GlobalFree(soundFileList);	
	}
	soundFileList = NULL;
	soundFileListLength = soundFileListMax = 0;
}

//	fileListBuild  --  Scan a directory and build a file list

int fileListBuild(char *path)
{
	HANDLE sitem;
	WIN32_FIND_DATA fd;

	fileListStatus = 0;
	fileListDestroy();
	fileList = GlobalAlloc(GMEM_FIXED, InitialList * sizeof(struct fileListItem *));
	if (fileList == NULL) {
		return 0;
	}
	fileListMax = InitialList;

	sitem = FindFirstFile(path, &fd);

	if (sitem == INVALID_HANDLE_VALUE) {
		fileListDestroy();
		fileListStatus = FL_BADDIR;				// Invalid directory
		return 0;
	}

	while (TRUE) {
		struct fileListItem *fi;
		int filetype;

		if ((filetype = fileListFilter(&fd)) != 0) {
			if (filetype == 1) {
				if (fileListLength >= fileListMax) {
					struct fileListItem **np = GlobalAlloc(GMEM_FIXED,
						(fileListMax + GrowList) * sizeof(struct fileListItem *));

					if (np == NULL) {
						fileListDestroy();
						fileListStatus = FL_NOMEM;
						return 0;
					}
					/*	Why not use GlobalReAlloc?  Because it doesn't
						fucking work--typical Microsoft crap.  In any
						case, having been written by Kode Kiddies, it
						probably always copies anyway.  */
					memcpy(np, fileList, fileListMax * sizeof(struct fileListItem *));
					GlobalFree(fileList);
					fileList = np;
					fileListMax += GrowList;

				}
				fi = GlobalAlloc(GMEM_FIXED, sizeof(struct fileListItem) + strlen(fd.cFileName) + 1);
				if (fi == NULL) {
					fileListDestroy();
					fileListStatus = FL_NOMEM;
					return 0;
				}
				fi->age = 0;
				strcpy(fi->filename, fd.cFileName);
				fileList[fileListLength++] = fi;
			} else {
				if (soundMode != SOUND_NEVER) {
					if (soundFileListLength >= soundFileListMax) {
						struct fileListItem **np = GlobalAlloc(GMEM_FIXED,
							(soundFileListMax + GrowList) * sizeof(struct fileListItem *));

						if (np == NULL) {
							fileListDestroy();
							fileListStatus = FL_NOMEM;
							return 0;
						}
						memcpy(np, soundFileList, soundFileListMax * sizeof(struct fileListItem *));
						GlobalFree(soundFileList);
						soundFileList = np;
						soundFileListMax += GrowList;

					}
					fi = GlobalAlloc(GMEM_FIXED, sizeof(struct fileListItem) +
										strlen(fd.cFileName) + 1);
					if (fi == NULL) {
						fileListDestroy();
						fileListStatus = FL_NOMEM;
						return 0;
					}
					fi->age = filetype;
					strcpy(fi->filename, fd.cFileName);
					soundFileList[soundFileListLength++] = fi;
				}
			}
		}
		if (FindNextFile(sitem, &fd) == 0) {
			FindClose(sitem);
			break;
		}
	}

	return fileListLength;
}

//	fileListDump  --  Dump file list to a file for debugging

void fileListDump(FILE *df)
{
	int i;

	fprintf(df, "--- Image files ---\n");
	for (i = 0; i < fileListLength; i++) {
		fprintf(df, "%4d: %s\n", fileList[i]->age, fileList[i]->filename);
	}
	fprintf(df, "--- Sound files ---\n");
	for (i = 0; i < soundFileListLength; i++) {
		fprintf(df, "%4d: %s\n", soundFileList[i]->age, soundFileList[i]->filename);
	}
}

//	fileNameCompare  --  Qsort comparison function for sorting file names

static int fileNameCompare(const void *arg1, const void *arg2) {
   /* Compare all of both strings: */
	return _stricmp((*(struct fileListItem **) arg1)->filename,
					(*(struct fileListItem **) arg2)->filename);
}

/*	fileListSort  --  Sort file list into alphabetical order.
					  The above comparison auxiliary is used,
					  which performs case-insensitive comparisons.  */

void fileListSort(void)
{
	if (fileList != NULL) {
		qsort((void *) fileList, (size_t) fileListLength, sizeof(char *), fileNameCompare);
	}
	if (soundFileList != NULL) {
		qsort((void *) soundFileList, (size_t) soundFileListLength, sizeof(char *), fileNameCompare);
	}
}

//	fileListShuffleImages  --  Shuffle image file list into random order

void fileListShuffleImages(void)
{
	if (fileList != NULL) {
		int i;
		for (i = 0; i < fileListLength; i++) {
			int j = random() % fileListLength;
			struct fileListItem *fi = fileList[i];
			
			fileList[i] = fileList[j];
			fileList[j] = fi;
		}
	}
}
//	fileListShuffleSounds  --  Shuffle sound file list into random order

void fileListShuffleSounds(void)
{
	if (soundFileList != NULL) {
		int i;

		for (i = 0; i < soundFileListLength; i++) {
			int j = random() % soundFileListLength;
			struct fileListItem *fi = soundFileList[i];
			
			soundFileList[i] = soundFileList[j];
			soundFileList[j] = fi;
		}
	}
}
