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

#include <ox/std/error.hpp>
#include <ox/std/utility.hpp>

#include <ox/fs/filesystem/filesystem.hpp>

namespace ox {

Result<const char*> MemFS::directAccess(const FileAddress &addr) const noexcept {
	switch (addr.type()) {
		case FileAddressType::Inode:
			return directAccess(addr.getInode().value);
		case FileAddressType::ConstPath:
		case FileAddressType::Path:
			return directAccess(StringView(addr.getPath().value));
		default:
			return ox::Error(1);
	}
}

Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size) noexcept {
	switch (addr.type()) {
		case FileAddressType::Inode:
			return readFileInode(addr.getInode().value, buffer, size);
		case FileAddressType::ConstPath:
		case FileAddressType::Path:
			return readFilePath(StringView(addr.getPath().value), buffer, size);
		default:
			return ox::Error(1);
	}
}

Result<Buffer> FileSystem::read(FileAddress const &addr, size_t const size) noexcept {
	Result<Buffer> out;
	out.value.resize(size);
	switch (addr.type()) {
		case FileAddressType::Inode:
			OX_RETURN_ERROR(readFileInode(addr.getInode().value, out.value.data(), size));
			break;
		case FileAddressType::ConstPath:
		case FileAddressType::Path:
			OX_RETURN_ERROR(readFilePath(StringView{addr.getPath().value}, out.value.data(), size));
			break;
		default:
			return ox::Error{1};
	}
	return out;
}

Result<Buffer> FileSystem::read(StringViewCR path, size_t const size) noexcept {
	Result<Buffer> out;
	out.value.resize(size);
	OX_RETURN_ERROR(readFilePath(path, out.value.data(), size));
	return out;
}

Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
	OX_REQUIRE(s, stat(addr));
	Buffer buff(static_cast<std::size_t>(s.size));
	OX_RETURN_ERROR(read(addr, buff.data(), buff.size()));
	return buff;
}

Result<Buffer> FileSystem::read(StringViewCR path) noexcept {
	OX_REQUIRE(s, statPath(path));
	Buffer buff(static_cast<std::size_t>(s.size));
	OX_RETURN_ERROR(readFilePath(path, buff.data(), buff.size()));
	return buff;
}

Error FileSystem::read(
		FileAddress const &addr,
		std::size_t const readStart,
		std::size_t const readSize,
		void *buffer,
		std::size_t *size) noexcept {
	switch (addr.type()) {
		case FileAddressType::Inode:
			return readFileInodeRange(addr.getInode().value, readStart, readSize, buffer, size);
		case FileAddressType::ConstPath:
		case FileAddressType::Path:
			return readFilePathRange(addr.getPath().value, readStart, readSize, buffer, size);
		default:
			return ox::Error(1);
	}
}

Result<size_t> FileSystem::read(
		StringViewCR path,
		std::size_t const readStart,
		std::size_t const readSize,
		Span<char> buff) noexcept {
	size_t szOut{buff.size()};
	OX_RETURN_ERROR(readFilePathRange(path, readStart, readSize, buff.data(), &szOut));
	return szOut;
}

Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept {
	switch (addr.type()) {
		case FileAddressType::Inode:
			return writeFileInode(addr.getInode().value, buffer, size, fileType);
		case FileAddressType::ConstPath:
		case FileAddressType::Path:
			return writeFilePath(StringView(addr.getPath().value), buffer, size, fileType);
		default:
			return ox::Error(1);
	}
}

Result<FileStat> FileSystem::stat(const FileAddress &addr) const noexcept {
	switch (addr.type()) {
		case FileAddressType::Inode:
			return statInode(addr.getInode().value);
		case FileAddressType::ConstPath:
		case FileAddressType::Path:
			return statPath(StringView(addr.getPath().value));
		default:
			return ox::Error(1);
	}
}

template class FileSystemTemplate<FileStore16, Directory16>;
template class FileSystemTemplate<FileStore32, Directory32>;

}
