#include "cpp_posix.h"
#include "cpp_errno.h"

#include <stdexcept>
#include <sys/types.h>
#include <unistd.h>

namespace coral {
	int cpp_fork() {
		int f = fork();
		if (f < 0) {
			std::string e(cpp_strerror());
			std::string s("Failed fork(): ");
			s += e;
			throw std::runtime_error(s);
		}
		return f;
	}

	std::auto_ptr<std::streambuf>
	internal_cpp_mkstemp(const std::string& filename_template,
			     std::string* output) {
		std::string s(filename_template);
		int fd = mkstemp(const_cast<char*>(s.c_str()));
		if (fd == -1) {
			std::string e(cpp_strerror());
			std::string err("Failed mkstemp() for file ");
			err += s;
			err += ": ";
			err += e;
			throw std::runtime_error(err);
		}
		std::auto_ptr<std::streambuf> buf(coral::iofdstreambuf(fd));
		if (output)
			*output = s;
		return buf;
	}

	std::auto_ptr<std::streambuf>
	cpp_mkstemp(const std::string& filename_template) {
		return internal_cpp_mkstemp(filename_template, NULL);
	}

	std::auto_ptr<std::streambuf>
	cpp_mkstemp(const std::string& filename_template,
		    std::string& output) {
		return internal_cpp_mkstemp(filename_template, &output);
	}

	std::auto_ptr<std::streambuf>
	internal_cpp_mkstemp_with_TMP(const std::string& filename_template,
				      std::string* output) {
		std::string tmptemplate;
		if (filename_template.at(0) != '/') {
			const char* tmpdir = getenv("TMP");
			if (tmpdir) {
				tmptemplate += tmpdir;
				tmptemplate += "/";
			} else {
				tmptemplate += "/tmp/";
			}
		}
		tmptemplate += filename_template;
		return internal_cpp_mkstemp(tmptemplate, output);
	}

	std::auto_ptr<std::streambuf>
	cpp_mkstemp_with_TMP(const std::string& filename_template) {
		return internal_cpp_mkstemp_with_TMP(filename_template, NULL);
	}

	std::auto_ptr<std::streambuf>
	cpp_mkstemp_with_TMP(const std::string& filename_template,
			     std::string& output) {
		return internal_cpp_mkstemp_with_TMP(filename_template,
						     &output);
	}


	void cpp_file_rename(const std::string& old_name,
			     const std::string& new_name) {
		/*
		 * Remove old file. I think this is required for Windows.
		 * Ignore return value?
		 */
		(void) remove(new_name.c_str());
		/*
		 * Rename
		 */
		int err = rename(old_name.c_str(), new_name.c_str());
		if (err) {
			std::string e(cpp_strerror());
			std::string errstr("Failed rename() of ");
			errstr += old_name;
			errstr += " to ";
			errstr += new_name;
			errstr += ": ";
			errstr += e;
			throw std::runtime_error(errstr);
		}
	}


}
