#include "Dir.h"

#include "Log.h"
#include "Errno.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fnmatch.h>

Dir::Dir ( ) {
	m_dirname = NULL;
	m_dir     = NULL;
	memset(m_dentryBuffer, 0, sizeof(m_dentryBuffer));
}


Dir::~Dir ( ) {
	reset();
}

void Dir::reset ( ) {
	close();
	free(m_dirname);
	m_dirname = NULL;
}

bool Dir::set ( const char *d1, const char *d2 ) {
	reset ();
	char tmp[1024];
	if ( strlen(d1) + strlen(d2) + 1 > 1024 ) {
		log(LOG_WARN, "disk: Could not set directory, directory name \"%s/%s\" "
		    "is too big.",d1,d2);
		return false;
	}
	sprintf ( tmp , "%s/%s", d1 , d2 );
	return set ( tmp );
}

bool Dir::set ( const char *dirname ) {
	reset ();
	m_dirname = strdup ( dirname );
	if ( m_dirname ) return true;
	log(LOG_WARN, "disk: Could not set directory, directory name to \"%s\": %s.",
	    dirname,mstrerror(g_errno));
	return false;
}

void Dir::close() {
	if ( m_dir )
		closedir ( m_dir );
	m_dir = NULL;
}

bool Dir::open ( ) {
	close ( );
	if ( ! m_dirname ) return false;
	do {
		m_dir = opendir ( m_dirname );
		// interrupted system call
	} while( ! m_dir && errno == EINTR );

	if ( ! m_dir ) {
		g_errno = errno;
		log( LOG_WARN, "disk: opendir(%s) : %s", m_dirname,strerror( g_errno ) );
		return false;
	}

	return true;
}

const char *Dir::getNextFilename(const char *pattern) {
	if (!m_dir) {
		log("dir: m_dir is NULL so can't find pattern %s", pattern);
		return NULL;
	}

	//Note: m_dentryBuffer has a fixed sized. The reccommended way is to
	//use a dynamic size and use sysconf() to determine how large it should
	//be. I just take a wild guess that no paths are longer than 1024
	//characters.
	struct dirent *ent;
	while (readdir_r(m_dir, (dirent *)m_dentryBuffer, &ent) == 0 && ent) {
		const char *filename = ent->d_name;

		if (!pattern || (fnmatch(pattern, filename, FNM_PATHNAME) == 0)) {
			return filename;
		}
	}

	return NULL;
}