/*
 * 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/model/modelops.hpp>

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

namespace ox {

FileAddress::FileAddress(const FileAddress &other) noexcept {
	operator=(other);
}

FileAddress::FileAddress(FileAddress &&other) noexcept {
	operator=(std::move(other));
}

FileAddress::FileAddress(std::nullptr_t) noexcept {
}

FileAddress::FileAddress(uint64_t inode) noexcept {
	m_data.inode = inode;
	m_type = FileAddressType::Inode;
}

FileAddress::FileAddress(ox::StringViewCR path) noexcept {
	auto pathSize = path.bytes();
	m_data.path = new char[pathSize + 1];
	OX_ALLOW_UNSAFE_BUFFERS_BEGIN
	memcpy(m_data.path, path.data(), pathSize);
	m_data.path[pathSize] = 0;
	OX_ALLOW_UNSAFE_BUFFERS_END
	m_type = FileAddressType::Path;
}

FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
	if (this == &other) {
		return *this;
	}
	cleanup();
	m_type = other.m_type;
	switch (m_type) {
		case FileAddressType::Path:
		{
			if (other.m_data.path) {
				OX_ALLOW_UNSAFE_BUFFERS_BEGIN
				auto strSize = ox::strlen(other.m_data.path) + 1;
				m_data.path = new char[strSize];
				ox::memcpy(m_data.path, other.m_data.path, strSize);
				OX_ALLOW_UNSAFE_BUFFERS_END
			} else {
				m_data.constPath = "";
				m_type = FileAddressType::ConstPath;
			}
			break;
		}
		case FileAddressType::ConstPath:
		case FileAddressType::Inode:
			m_data = other.m_data;
			break;
		case FileAddressType::None:
			break;
	}
	return *this;
}

FileAddress &FileAddress::operator=(FileAddress &&other) noexcept {
	if (this == &other) {
		return *this;
	}
	cleanup();
	m_type = other.m_type;
	switch (m_type) {
		case FileAddressType::Path:
		{
			m_data.path = other.m_data.path;
			break;
		}
		case FileAddressType::ConstPath:
		case FileAddressType::Inode:
			m_data = other.m_data;
			break;
		case FileAddressType::None:
			break;
	}
	other.clear();
	return *this;
}

bool FileAddress::operator==(FileAddress const&other) const noexcept {
	if (m_type != other.m_type) {
		auto const aIsPath =
				m_type == FileAddressType::Path || m_type == FileAddressType::ConstPath;
		auto const bIsPath =
				other.m_type == FileAddressType::Path || other.m_type == FileAddressType::ConstPath;
		if (!(aIsPath && bIsPath)) {
			return false;
		}
	}
	switch (m_type) {
		case FileAddressType::ConstPath:
		case FileAddressType::Path: {
			auto const a = getPath();
			auto const b = other.getPath();
			return (other.m_type == FileAddressType::ConstPath || other.m_type == FileAddressType::Path)
			    && (a.value == b.value);
		}
		case FileAddressType::Inode:
			return m_data.inode == other.m_data.inode;
		case FileAddressType::None:
			return true;
	}
	return true;
}

bool FileAddress::operator==(StringViewCR path) const noexcept {
	auto [p, err] = getPath();
	if (err) {
		return false;
	}
	return path == p;
}

}
