#include <psemek/io/file_stream.hpp>

namespace psemek::io
{

	std::size_t istream::read_all(char * p, std::size_t size)
	{
		auto left = size;
		while (left > 0)
		{
			auto s = read(p, left);
			if (s == 0)
				throw istream_end{};
			p += s;
			left -= s;
		}
		return size;
	}

	std::size_t ostream::write_all(char const * p, std::size_t size)
	{
		auto left = size;
		while (left > 0)
		{
			auto s = write(p, left);
			if (s == 0)
				throw ostream_end{};
			p += s;
			left -= s;
		}
		return size;
	}

	std::unique_ptr<istream> std_in()
	{
		return std::make_unique<file_istream>(stdin);
	}

	std::unique_ptr<ostream> std_out()
	{
		return std::make_unique<file_ostream>(stdout);
	}

	std::unique_ptr<ostream> std_err()
	{
		return std::make_unique<file_ostream>(stderr);
	}

	util::blob read_full(istream && stream)
	{
		std::size_t allocated = 0;
		std::size_t size = 0;
		std::unique_ptr<char[]> data;
		while (true)
		{
			if (!data)
			{
				allocated = 16;
				data.reset(new char[allocated]);
			}
			else if (size == allocated)
			{
				allocated *= 2;
				std::unique_ptr<char[]> new_data(new char[allocated]);
				std::copy(data.get(), data.get() + size, new_data.get());
				data = std::move(new_data);
			}

			std::size_t count = stream.read(data.get() + size, allocated - size);
			if (count == 0)
				break;
			size += count;
		}
		return util::blob(size, std::move(data));
	}

}
