
#include "ml_io.h"

#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>


std::string read_file_contents(const std::string &filename) {
	std::ifstream f;
	f.open(filename.c_str());
	if (!f)
		throw std::runtime_error("could not open file (" + filename + ")");

	f.seekg(0, std::ios::end);
	std::string contents;
	contents.reserve(f.tellg());
	f.seekg(0, std::ios::beg);
	contents.assign(std::istreambuf_iterator<char>(f),
			std::istreambuf_iterator<char>());
	f.close();

	return contents;
}

int write_file_contents(const std::string &filename, const std::string &content) {
	std::ofstream f;
	f.open(filename.c_str());
	int result = (f << content) ? 1 : 0;
	f.close();
	return result;
}

MlValue list_dir(const std::string &path) {
	std::vector<MlValue> entries;

	DIR *dirp = opendir(path.c_str());
	if (dirp == NULL) {
		throw std::runtime_error("could not open dir (" + path + ")");
	}
	struct dirent *dp;
	while ((dp = readdir(dirp)) != NULL) {
		entries.push_back(MlValue::string(dp->d_name));
	}
	closedir(dirp);

	return MlValue(entries);
}

bool is_path_file(const std::string &path) {
	std::ifstream ifile(path.c_str());
	return (bool) ifile;
}

bool is_path_dir(const std::string &path) {
	struct stat buf;
	stat(path.c_str(), &buf);
	return (bool) S_ISDIR(buf.st_mode);
}

int mk_path_dir(const std::string &path) {
	int r = ::mkdir(path.c_str(), 0755);
	return r;
}

int rm_path_dir(const std::string &path) {
	int r = ::rmdir(path.c_str());
	return r;
}

MlValue exec_system_cmd(const std::string &cmd) {
	// TODO handle reading of stderr
	// https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po
	// https://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/

	std::string cmd_output;
	int stat;
	char buffer[128];
	FILE *pipe = popen(cmd.c_str(), "r");
	if (!pipe)
		throw std::runtime_error("popen() failed!");
	try {
		while (!feof(pipe)) {
			if (fgets(buffer, 128, pipe) != nullptr)
				cmd_output += buffer;
		}
	} catch (...) {
		stat = pclose(pipe);
		throw;
	}
	stat = pclose(pipe);
	int cmd_retval = WEXITSTATUS(stat);

	return std::vector<MlValue> { MlValue((long)cmd_retval), MlValue::string(cmd_output) };
}
