/*
 * Copyright 2021 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 INCLUDED_BUILDBOXRUN_OCI
#define INCLUDED_BUILDBOXRUN_OCI

#include <buildboxcommon_mergeutil.h>
#include <buildboxcommon_runner.h>

#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <string>

namespace buildboxcommon {
namespace buildboxrun {
namespace oci {

class OCIRunner : public Runner {
  public:
    ActionResult execute(const Command &command, const Digest &inputRootDigest,
                         const Platform &platform) override;

    bool parseArg(std::string_view arg) override;

    void fetchDockerImage(const std::string &imageName) const;

    /* Creates a container to run the specified container image, imageName.
     * Then, exports the image's file system into a tar file, and extracts the
     * tar file into the specified directory, filePath. */
    void extractFileSystemFromImage(const std::string &imageName,
                                    const std::string &filePath) const;

    const Digest uploadImageFileSystem(const std::string &directory) const;

    /* Fetch the image from its registry, retrieve its file system, and
     * upload it to CAS. */
    const Digest fetchAndUploadImage(const std::string &imageName) const;

    class ContainerHost;

  private:
    /* Given two digests representing two filesystems with the same root,
     * returns a new digest representing the merged filesystem. All necessary
     * digests in the tree will be populated. */
    Digest mergeFilesystemDigest(const DirectoryTree &inputRootTree,
                                 const DirectoryTree &ociTree);

    /* Prepares a Digest representing a Directory that contains a rootfs
     * folder, inside which contains the contents in fsDigest. */
    Digest prepareNestedDigest(const Digest &fsDigest);

    std::map<std::string, std::uint64_t> d_resourceLimits;

  protected:
    /* Returns the Digest of the OCI bundle as specified in the Platform
     * properties. The function will first look for an Asset identifier
     * property if the Asset client in the runner is populated. If it's not
     * populated or such a property is not found, it looks for another property
     * that contains the digest hash/size. */
    Digest getBundleDigest(const Platform &platform);
};

} // namespace oci
} // namespace buildboxrun
} // namespace buildboxcommon

#endif
