/*
 * Copyright 2019 Bloomberg Finance LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef BUILDBOXCOMMON_LOCALCASSTAGEDDIRECTORY_H
#define BUILDBOXCOMMON_LOCALCASSTAGEDDIRECTORY_H

#include <buildboxcommon_casclient.h>
#include <buildboxcommon_stageddirectory.h>
#include <buildboxcommon_systemutils.h>

namespace buildboxcommon {

class LocalCasStagedDirectory final : public StagedDirectory {

  public:
    explicit LocalCasStagedDirectory(
        const Digest &digest, const std::string &path,
        const std::shared_ptr<CASClient> &cas_client,
        const StageTreeRequest_StagingMode stagingMode,
        const ProcessCredentialsGetter &processCredentialsGetter =
            SystemUtils::getProcessCredentials,
        const std::vector<std::string> &postActionCommands = {},
        bool outputByPassedLocalCache = false,
        const std::optional<RemoteApisSocketConfig> &remoteApisSocket =
            std::nullopt);

    // Allow overwriting the root owner uid for testing instead of using
    // geteuid()
    explicit LocalCasStagedDirectory(
        const Digest &digest, const std::string &path,
        const std::shared_ptr<CASClient> &cas_client,
        const StageTreeRequest_StagingMode stagingMode,
        const uid_t rootOwnerUid,
        const ProcessCredentialsGetter &processCredentialsGetter =
            SystemUtils::getProcessCredentials,
        const std::vector<std::string> &postActionCommands = {},
        bool outputByPassedLocalCache = false,
        const std::optional<RemoteApisSocketConfig> &remoteApisSocket =
            std::nullopt);

    /**
     * Close the connection to the remote and unstage.
     *
     * (Done by `~CASClient::StagedDirectory()`)
     */
    ~LocalCasStagedDirectory() override;

    // These functions could be called for paths that do not exist.
    // In that case they will just return empty messages, without attempting
    // to request their staging.
    OutputFile captureFile(const char *relative_path,
                           const Command &command) const override;
    OutputDirectory
    captureDirectory(const char *relative_path, const Command &command,
                     int64_t *directoryTotalSize) const override;

    // It's illegal to copy a LocalCasStagedDirectory since destroying one copy
    // would cause the other's local directory to be deleted.
    LocalCasStagedDirectory(const LocalCasStagedDirectory &) = delete;
    LocalCasStagedDirectory &
    operator=(LocalCasStagedDirectory const &) = delete;

    // Define move constructor
    LocalCasStagedDirectory(LocalCasStagedDirectory &&other) = delete;

    // Define move assignment operator
    LocalCasStagedDirectory &
    operator=(LocalCasStagedDirectory &&other) = delete;

  private:
    std::shared_ptr<CASClient> d_cas_client;
    std::unique_ptr<CASClient::StagedDirectory> d_cas_client_staged_directory;
    int d_staged_directory_fd;
    uid_t d_rootOwnerUid;
    bool d_outputByPassedLocalCache;
};

} // namespace buildboxcommon

#endif // BUILDBOXCOMMON_LOCALCASSTAGEDDIRECTORY_H
