#include "file_helpers.h"

#ifdef GLLIB_OS_WINDOWS
//for workaround for Windows' non portable garbage
std::wstring s2ws(const std::string& s) {
	int len;
	int slength = (int)s.length() + 1;
	len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
	wchar_t* buf = new wchar_t[len];
	MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
	std::wstring r(buf);
	delete[] buf;
	return r;
}
CHAR wide_to_narrow(WCHAR w) {
	// simple typecast
	// works because UNICODE incorporates ASCII into itself
	return CHAR(w);
}
wstring c_to_w(string source) {
	int i = 0;

	wstring result;
	const char* s = source.c_str();
	while (s[i]!='\0') {
		result += (WCHAR)s[i];
		++i;
	}
	return result;
}
#endif

void make_directory(string name) {
	#ifdef GLLIB_OS_WINDOWS
	CreateDirectoryW(s2ws(name).c_str(),NULL);
	#elif defined GLLIB_OS_UNIX
	mkdir(name.c_str(),S_IRWXU|S_IRWXG|S_IRWXO);
	#else
	#error Making a directory not defined!
	#endif
}

bool remove_directory_files(string directory);
bool remove_directory(string directory) {
	if (!remove_directory_files(directory)) {
		printf("Could not remove files in directory \"%s\"!\n",directory.c_str());
		return false;
	}
	#ifdef GLLIB_OS_WINDOWS
	if (!RemoveDirectory(s2ws(directory).c_str())) {
	#elif defined GLLIB_OS_UNIX
	if ( rmdir(directory.c_str()) != 0) {
	#else
	#error Making a directory not defined!
	{
	#endif
		printf("Could not remove directory \"%s\"!\n",directory.c_str());
	}
	return true;
}
bool remove_directory_files(string directory) {
	#ifdef GLLIB_OS_WINDOWS
	wchar_t* DirSpec;

	const char* dir_name = directory.c_str();

	// Check that the input is not larger than allowed.
	size_t length_of_arg = strlen(dir_name);
	if (length_of_arg>(MAX_PATH-2)) return false;

	// Prepare string for use with FindFile functions.  First,
	// copy the string to a buffer, then append '\*' to the
	// directory name.
	wstring temp = wstring(c_to_w(directory))+L"\\*";
	DirSpec = (wchar_t*)(temp.c_str());

	// Find the first file in the directory.
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind = FindFirstFile(DirSpec, &FindFileData);

	if (hFind == INVALID_HANDLE_VALUE) return false;
	else {
		char filename[MAX_PATH];
		do {
			transform(FindFileData.cFileName,FindFileData.cFileName+MAX_PATH,filename,wide_to_narrow);
			remove_file(directory+"/"+filename);
		} while (FindNextFile(hFind, &FindFileData)!=0);

		DWORD dwError = GetLastError();
		FindClose(hFind);
		if (dwError!=ERROR_NO_MORE_FILES) return false;
	}
	#elif defined GLLIB_OS_UNIX
	DIR* mydir = opendir(directory.c_str());
	struct dirent* entry = NULL;
	while ((entry=readdir(mydir))) {
		if (entry->d_name==string(".")) continue;
		if (entry->d_name==string("..")) continue;
		string name = directory + "/" + entry->d_name;
		const char* name_str = name.c_str();
		if (!remove_file(name)) {
			printf("Could not remove file \"%s\"!\n",name_str);
			return false;
		}
		//else printf("Removed file \"%s\"!\n",name_str);
	}
	closedir(mydir);
	#else
	#error "Removing a directory's files not defined!"
	#endif
	return true;
}
bool remove_file(string name) {
	return (remove(name.c_str())==0);
}

bool is_directory(string path) {
	struct stat status;
	if (stat(path.c_str(),&status)==-1) return false;
	if (status.st_mode&S_IFDIR) return true;
	return false;
}
bool is_file(string path) {
	struct stat status;
	if (stat(path.c_str(),&status)==-1) return false;
	if (status.st_mode&S_IFREG) return true;
	return false;
}
bool exists_file(string path) {
	FILE* f = fopen(path.c_str(),"r");
	if (f==NULL) return false;
	fclose(f);
	return true;
}