/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */


#ifdef OX_USE_STDLIB
#include <istream>

#include <ox/std/array.hpp>
#include <ox/std/reader.hpp>
#include <ox/std/istreamreader.hpp>

namespace ox {

[[nodiscard]]
constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
	switch (in) {
		case ox::ios_base::beg:
			return std::ios_base::beg;
		case ox::ios_base::end:
			return std::ios_base::end;
		case ox::ios_base::cur:
			return std::ios_base::cur;
	}
	return std::ios_base::beg;
}

Result<char> StreamReader::peek() const noexcept {
	try {
		if (m_strm.eof()) {
			return Error{1, "EOF"};
		}
		char c{};
		m_strm.get(c);
		if (m_strm.unget()) [[unlikely]] {
			return ox::Error{1, "Unable to unget character"};
		}
		return static_cast<char>(c);
	} catch (std::exception const&) {
		return ox::Error(1, "peek failed");
	}
}

Result<size_t> StreamReader::read(char *v, size_t cnt) noexcept {
	return static_cast<size_t>(m_strm.read(v, static_cast<std::streamsize>(cnt)).gcount());
}

Error StreamReader::seekg(size_t p) noexcept {
	try {
		m_strm.seekg(static_cast<long long int>(p), std::ios_base::cur);
	} catch (std::exception const&) {
		return ox::Error(1, "seekg failed");
	}
	return {};
}

Error StreamReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
	try {
		m_strm.seekg(p, sdMap(sd));
	} catch (std::exception const&) {
		return ox::Error(1, "seekg failed");
	}
	return {};
}

Result<size_t> StreamReader::tellg() noexcept {
	const auto sz = m_strm.tellg();
	return {static_cast<size_t>(sz), ox::Error(sz == -1)};
}

}

#endif
