/*
 * 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/.
 */

#pragma once

#ifdef OX_USE_STDLIB
#include <string_view>
#endif

#include "basestringview.hpp"
#include "cstrops.hpp"
#include "maybeview.hpp"
#include "writer.hpp"

OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)

namespace ox {

template<std::size_t buffLen>
class IString;

template<std::size_t buffLen>
class BasicString;

class StringView: public detail::BaseStringView {
	public:
		constexpr StringView() noexcept = default;

		constexpr StringView(const StringView &sv) noexcept = default;

#ifdef OX_USE_STDLIB
		constexpr StringView(const std::string_view &sv) noexcept: BaseStringView(sv.data(), sv.size()) {}
#endif

		constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}

		template<std::size_t SmallStrSz>
		constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}

		template<std::size_t SmallStrSz>
		constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}

		constexpr StringView(std::nullptr_t) noexcept {}

		constexpr StringView(const char *str) noexcept: BaseStringView(str) {}

		constexpr StringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}

		constexpr auto &operator=(StringView const&other) noexcept {
			if (&other != this) {
				set(other.data(), other.size());
			}
			return *this;
		}

};

using StringViewCR = StringView const&;

constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept {
	if (s2.size() != s1.size()) {
		return false;
	}
	return ox::strncmp(s1.data(), s2.data(), s1.size()) == 0;
}

constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
	const auto maxLen = ox::min(s1.size(), s2.size());
	const auto a = &s1.front();
	const auto b = &s2.front();
	for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
		if (a[i] < b[i]) {
			return -1;
		} else if (a[i] > b[i]) {
			return 1;
		}
	}
	if (s1.size() > s2.size()) {
		return 1;
	} else if (s1.size() < s2.size()) {
		return -1;
	} else {
		return 0;
	}
}

constexpr auto write(Writer_c auto &writer, StringViewCR sv) noexcept {
	return writer.write(sv.data(), sv.bytes());
}

#ifdef OX_USE_STDLIB
constexpr auto toStdStringView(StringViewCR sv) noexcept {
	return std::string_view(sv.data(), sv.bytes());
}
#endif


constexpr ox::Result<int> strToInt(StringViewCR str) noexcept {
	OX_ALLOW_UNSAFE_BUFFERS_BEGIN
	int total = 0;
	int multiplier = 1;
	if (str.size() == 0) [[unlikely]] {
		return Error{1, "Empty string passed to strToInt"};
	}
	for (auto i = static_cast<int64_t>(str.size()) - 1; i != -1; --i) {
		auto s = static_cast<std::size_t>(i);
		if (str[s] >= '0' && str[s] <= '9') {
			total += (str[s] - '0') * multiplier;
			multiplier *= 10;
		} else {
			return ox::Error{1};
		}
	}
	return total;
	OX_ALLOW_UNSAFE_BUFFERS_END
}


}

OX_CLANG_NOWARN_END
