#pragma once
///@file

#include "types.hh"
#include "serialise.hh"
#include "source-accessor.hh"
#include "file-system.hh"

namespace nix {

/**
 * \todo Fix this API, it sucks.
 */
struct ParseSink
{
    virtual void createDirectory(const Path & path) = 0;

    virtual void createRegularFile(const Path & path) = 0;
    virtual void receiveContents(std::string_view data) = 0;
    virtual void isExecutable() = 0;
    virtual void closeRegularFile() = 0;

    virtual void createSymlink(const Path & path, const std::string & target) = 0;

    /**
     * An optimization. By default, do nothing.
     */
    virtual void preallocateContents(uint64_t size) { };
};

/**
 * Recusively copy file system objects from the source into the sink.
 */
void copyRecursive(
    SourceAccessor & accessor, const CanonPath & sourcePath,
    ParseSink & sink, const Path & destPath);

/**
 * Ignore everything and do nothing
 */
struct NullParseSink : ParseSink
{
    void createDirectory(const Path & path) override { }
    void receiveContents(std::string_view data) override { }
    void createSymlink(const Path & path, const std::string & target) override { }
    void createRegularFile(const Path & path) override { }
    void closeRegularFile() override { }
    void isExecutable() override { }
};

/**
 * Write files at the given path
 */
struct RestoreSink : ParseSink
{
    Path dstPath;

    void createDirectory(const Path & path) override;

    void createRegularFile(const Path & path) override;
    void receiveContents(std::string_view data) override;
    void isExecutable() override;
    void closeRegularFile() override;

    void createSymlink(const Path & path, const std::string & target) override;

    void preallocateContents(uint64_t size) override;

private:
    AutoCloseFD fd;
};

/**
 * Restore a single file at the top level, passing along
 * `receiveContents` to the underlying `Sink`. For anything but a single
 * file, set `regular = true` so the caller can fail accordingly.
 */
struct RegularFileSink : ParseSink
{
    bool regular = true;
    Sink & sink;

    RegularFileSink(Sink & sink) : sink(sink) { }

    void createDirectory(const Path & path) override
    {
        regular = false;
    }

    void receiveContents(std::string_view data) override
    {
        sink(data);
    }

    void createSymlink(const Path & path, const std::string & target) override
    {
        regular = false;
    }

    void createRegularFile(const Path & path) override { }
    void closeRegularFile() override { }
    void isExecutable() override { }
};

}
