/**
 * @file Path.h
 * @author apio (cloudapio.eu)
 * @brief Dirfd-friendly Path class.
 *
 * @copyright Copyright (c) 2023, the Luna authors.
 *
 */

#pragma once
#include <fcntl.h>
#include <luna/StringView.h>

namespace os
{
    /**
     * @brief A dirfd-friendly Path class.
     */
    class Path
    {
      public:
        /**
         * @brief Construct a new Path object using a C-string file path.
         *
         * @param path The file path to use.
         */
        Path(const char* path);

        /**
         * @brief Construct a new Path object using a StringView file path.
         *
         * @param path The file path to use.
         */
        Path(StringView path);

        /**
         * @brief Construct a new Path object using a file descriptor.
         *
         * @param fd The file descriptor to use.
         */
        Path(int fd);

        /**
         * @brief Construct a new Path object using a parent file descriptor and a file path.
         *
         * @param dirfd The parent file descriptor to use.
         * @param name The file path to use.
         */
        Path(int dirfd, StringView name);

        /**
         * @brief Return the file descriptor associated with this Path.
         *
         * @return int The file descriptor, or AT_FDCWD if this Path does not have one.
         */
        int dirfd() const
        {
            return m_dirfd.value_or(AT_FDCWD);
        }

        /**
         * @brief Return the file path associated with this Path.
         *
         * @return StringView The path, or an empty StringView if this Path does not have one.
         */
        StringView name() const
        {
            return m_name.value_or(""_sv);
        }

        /**
         * @brief Determine whether this Path consists only of a file descriptor.
         *
         * @return int The fstatat()-compatible flag value to use in case this Path consists only of a file descriptor.
         */
        int is_empty_path() const
        {
            if (m_dirfd.has_value() && !m_name.has_value()) return AT_EMPTY_PATH;

            return 0;
        }

      private:
        Option<int> m_dirfd;
        Option<StringView> m_name;
    };
}