/*
	@file scolFindData.cpp
	@brief Emulate _findfirst, _findnext on non-Windows platforms
*/

#include "OS_specific/linux/scolFindData.h"

#if SCOL_PLATFORM != SCOL_PLATFORM_WINDOWS
#include "malloc.h"
#include "sys/stat.h"

struct _find_search_t
{
	char *pattern;
	char *curfn;
	char *directory;
	int dirlen;
	DIR *dirfd;
};
        
long _findfirst(const char* pattern, struct _finddata_t* data)
{
	_find_search_t *fs = new _find_search_t;
	fs->curfn = NULL;
	fs->pattern = NULL;

	// Separate the mask from directory name
	const char *mask = strrchr(pattern, '/');
	if (mask)
	{
		fs->dirlen = mask - pattern;
		mask++;
		fs->directory = (char*) malloc(fs->dirlen + 1);
		memcpy(fs->directory, pattern, fs->dirlen);
		fs->directory[fs->dirlen] = 0;
	}
	else
	{
		mask = pattern;
		fs->directory = strdup(".");
		fs->dirlen = 1;
	}

	fs->dirfd = opendir(fs->directory);
	if (!fs->dirfd)
	{
		_findclose((long)fs);
		return -1;
	}

	/* Hack for "*.*" -> "*' from DOS/Windows */
	if (strcmp(mask, "*.*") == 0)
		mask += 2;

	fs->pattern = strdup(mask);

	/* Get the first entry */
	if (_findnext((long)fs, data) < 0)
	{
		_findclose((long)fs);
		return -1;
	}

	return (long)fs;
}

int _findnext(long id, struct _finddata_t* data)
{
	_find_search_t* fs = (_find_search_t*)id;

	/* Loop until we run out of entries or find the next one */
	dirent* entry;
	for (;;)
	{
		if (!(entry = readdir(fs->dirfd)))
		    return -1;

		/* See if the filename matches our pattern */
		if (fnmatch(fs->pattern, entry->d_name, 0) == 0)
		    break;
	}

	if (fs->curfn)
		free(fs->curfn);
	
	data->name = fs->curfn = strdup(entry->d_name);
	size_t namelen = strlen(entry->d_name);
	char *xfn = new char[fs->dirlen + 1 + namelen + 1];
	sprintf(xfn, "%s/%s", fs->directory, entry->d_name);

	/* stat the file to get if it's a subdir and to find its length */
	struct stat stat_buf;
	if (stat(xfn, &stat_buf))
	{
		// Hmm strange, imitate a zero-length file then
		data->attrib = _A_NORMAL;
		data->size = 0;
	}
	else
	{
		if (S_ISDIR(stat_buf.st_mode))
		    data->attrib = _A_SUBDIR;
		else
		    /* Default type to a normal file */
		    data->attrib = _A_NORMAL;

		data->size = stat_buf.st_size;
	}

	delete [] xfn;

	/* Files starting with a dot are hidden files in Unix */
	if (data->name [0] == '.')
		data->attrib |= _A_HIDDEN;

	return 0;
}

int _findclose(long id)
{
    int ret;
    _find_search_t* fs = (_find_search_t*)id;
    
    ret = fs->dirfd ? closedir(fs->dirfd) : 0;
    free(fs->pattern);
    free(fs->directory);
    if (fs->curfn)
        free (fs->curfn);
    
	delete fs;
    return ret;
}

#endif

