/*
 * Copyright 2015 - 2022 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 http://mozilla.org/MPL/2.0/.
 */

#include <ox/model/modelops.hpp>

#include "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(const ox::String &path) noexcept {
	auto pathSize = path.bytes();
	m_data.path = new char[pathSize];
	memcpy(m_data.path, path.c_str(), pathSize);
	m_type = FileAddressType::Path;
}

FileAddress::FileAddress(char *path) noexcept {
	auto pathSize = ox_strlen(path) + 1;
	m_data.path = new char[pathSize];
	memcpy(m_data.path, path, pathSize);
	m_type = FileAddressType::Path;
}

FileAddress::FileAddress(const char *path) noexcept {
	m_data.constPath = path;
	m_type = FileAddressType::ConstPath;
}

FileAddress::~FileAddress() noexcept {
	cleanup();
}

FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
	if (this == &other) {
		return *this;
	}
	cleanup();
	m_type = other.m_type;
	switch (m_type) {
		case FileAddressType::Path:
		{
			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);
			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==(const ox::String &path) const noexcept {
	auto [p, err] = getPath();
	if (err) {
		return false;
	}
	return path == p;
}

void FileAddress::cleanup() noexcept {
	if (m_type == FileAddressType::Path) {
		safeDeleteArray(m_data.path);
		clear();
	}
}

void FileAddress::clear() noexcept {
	m_data.path = nullptr;
	m_type = FileAddressType::None;
}

}
