/*
 * Copyright (C) Eugene 'Vindex' Stulin, 2025-2026
 *
 * Distributed under
 * the Boost Software License 1.0 or (at your option)
 * the GNU Lesser General Public License 3.0 or later.
 * This file is offered as-is, without any warranty.
 */

/**
 * The libfuse3 library broke backward compatibility several times.
 * Because of this we have to use several versions
 * of the `fuse_file_info` struct.
 * The correct version is determined at compile time.
 */
module oxfuse.fuse_file_info;

import std.algorithm : among;
import std.exception : enforce;
import std.stdio;

import oxfuse.libfuse_version : libfuseVersion;
import oxfuse.utils : compareVersions, NoData;

private alias V = libfuseVersion;
private alias cmp = compareVersions;

static if (cmp(V, "3.14.1") == '<')
public import oxfuse.fuse_file_info.v3_11_0;

static if (cmp(V, "3.14.1").among('=', '>') && cmp(V, "3.17.0") == '<')
public import oxfuse.fuse_file_info.v3_14_1;

static if (cmp(V, "3.17.0").among('=', '>'))
public import oxfuse.fuse_file_info.v3_17_x;


/**
 * Information about an open file, wrapper of fuse_file_info.
 * Contains a pointer to the C fuse_file_info structure and set of methods
 * to manage the contents of this structure. The fuse_file_info fields can also
 * be accessed directly if the required method is not present, example:
 * ```
 * override void open(string path, FileInfo fi) {
 *     fi.info.direct_io = 1;
 *     // ...
 * }
 * ```
 */
class FileInfo {
    /// Pointer to the fuse_file_info object.
    private fuse_file_info* info;

    /// Default constructor.
    this(fuse_file_info* ffi) {
        this.info = ffi;
    }

    /// Returns pointer to struct fuse_file_info from libfuse. Check for null!
    fuse_file_info* getRawPointer() {
        return info;
    }

    /// Checks if the fuse_file_info pointer is not empty.
    bool hasData() {
        return info != null;
    }

    /// 'Open' flags; available in open() and release().
    int getFlags() {
        enforce!NoData(this.hasData());
        return info.flags;
    }

    /// Can be used in open(), to use direct I/O on the current file.
    void enableDirectIo() {
        enforce!NoData(this.hasData());
        info.direct_io = 1;
    }

    /**
     * Sets the file handle field (`fh`). Often used to store a file descriptor.
     * May be filled in `create()`, `open()`, `opendir()`.
     * Available in most other file operations on the same file handle.
     */
    void setFh(ulong fh) {
        enforce!NoData(this.hasData());
        info.fh = fh;
    }

    /**
     * Gets file handle id.
     */
    ulong getFh() {
        enforce!NoData(this.hasData());
        return info.fh;
    }
}
alias FFI = FileInfo;
alias ffi_t = fuse_file_info;
