/*
 * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
 */

module;

#include <ox/std/string.hpp>

export module hull;

namespace hull {

export
template<typename Str = ox::String, size_t SmallVecSz = 0>
constexpr ox::Result<ox::Vector<Str, SmallVecSz>> parseCmd(ox::StringViewCR cmd) noexcept
	requires(ox::is_same_v<Str, ox::String> || ox::is_same_v<Str, ox::StringView>) {
	auto const tokens = split(cmd, ' ');
	ox::Vector<Str, SmallVecSz> args;
	char waitingFor{};
	auto const handleString = [&waitingFor, &args](
		ox::StringViewCR token,
		char const delimiter) {
		if (endsWith(token, delimiter)) {
			args.emplace_back(substr(token, 1, token.size() - 1));
		} else {
			waitingFor = delimiter;
			args.emplace_back(substr(token, 1));
		}
	};
	for (auto const &token : tokens) {
		if (waitingFor) {
			if (endsWith(token, waitingFor)) {
				waitingFor = 0;
			}
			auto &tgt = *args.back().value;
			if constexpr (ox::is_same_v<Str, ox::String>) {
				tgt += substr(token, 0, token.size() - 1);
			} else {
				tgt = {tgt.data(), tgt.size() + token.size() - 1};
			}
		} else if (beginsWith(token, '"')) {
			handleString(token, '"');
		} else if (beginsWith(token, '\'')) {
			handleString(token, '\'');
		} else {
			args.emplace_back(token);
		}
	}
	if (waitingFor) {
		return ox::Error{1, "unterminated string"};
	}
	return args;
}

template<typename Str = ox::String>
[[nodiscard]]
static constexpr bool testParse(ox::StringViewCR cmd, std::initializer_list<ox::StringView> const &expected) noexcept {
	auto const [args, err] = parseCmd<Str>(cmd);
	static constexpr auto equals = [](auto const &a, auto const &b) {
		if (a.size() != b.size()) {
			return false;
		}
		for (auto i = 0u; i < a.size(); ++i) {
			if (a[i] != b[i]) {
				return false;
			}
		}
		return true;
	};
	return !err && equals(args, ox::Vector(expected));
}

static_assert(testParse("echo asdf", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo asdf", {"echo", "asdf"}));

static_assert(testParse("echo \"asdf\"", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo \"asdf\"", {"echo", "asdf"}));

static_assert(testParse("echo 'asdf'", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo 'asdf'", {"echo", "asdf"}));

static_assert(testParse("echo 'asdf' aoue", {"echo", "asdf", "aoue"}));
static_assert(testParse<ox::String>("echo 'asdf' aoue", {"echo", "asdf", "aoue"}));

export class Prompt {

	private:
		ox::String m_cmd;
		ox::String m_workingDir{"/"};
		ox::Vector<ox::String> m_prevCmds;

	public:

	private:

};

}
