/*
 * 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/.
 *
 * Copyright 2017-2018 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

#include "../view.hpp"

#include <filesystem>

#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>

#if !defined(O_BINARY)
#define O_BINARY 0
#endif


namespace cruft::posix {
    ///------------------------------------------------------------------------
    /// A simple RAII wrapper for file descriptors
    class fd {
    public:
        ///////////////////////////////////////////////////////////////////////
        // If you are using a system which delineates between binary/text mode
        // for descriptors the behaviour is undefined if you don't set the
        // necessary flags for binary mode.
        fd (const std::filesystem::path &path, int flags);
        fd (const std::filesystem::path &path, int flags, mode_t);

        fd (fd &&) noexcept;
        fd& operator= (fd &&) noexcept;
        fd& operator= (int);

        // The int constructor steals the fd. So don't pass in something that
        // you don't want closed at destruct time. This should really only be
        // used when interfacing with results of syscalls that we don't wrap.
        explicit fd (int);

        // copy constructors are removed in favour of explicit calls to dup.
        // This should reduce unexpected or expensive copies as much as
        // possible; one should not be doing this unless it is absolutely
        // required.
        fd (const fd&) = delete;
        fd dup (void) const;
        static fd dup (int);

        ~fd ();

        ///////////////////////////////////////////////////////////////////////
        struct ::stat stat (void) const;


        ///////////////////////////////////////////////////////////////////////
        void close (void);
        void reset (int);
        void reset (void);
        int release (void);

        //---------------------------------------------------------------------
        [[nodiscard]] ssize_t read (void *buf, size_t count);
        [[nodiscard]] ssize_t write (const void *buf, size_t count);
        [[nodiscard]] ssize_t pwrite (const void *buf, size_t count, size_t offset);


        //---------------------------------------------------------------------
        [[nodiscard]] off_t lseek (off_t offset, int whence);


        ///////////////////////////////////////////////////////////////////////
        operator int (void) const;
        int native (void) const { return m_fd; }

    private:
        int m_fd;
    };
}