// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#ifndef ARGS_H
#define ARGS_H

#include "../pal/pal_utils.h"
#include "../pal/pal.h"
#include "../pal/trace.h"
#include "../deps/deps_format.h"
#include "libhost.h"

struct probe_config_t
{
    pal::string_t probe_dir;
    bool match_hash;
    bool patch_roll_fwd;
    bool prerelease_roll_fwd;
    const deps_json_t* probe_deps_json;

    bool only_runtime_assets;
    bool only_serviceable_assets;

    void print() const
    {
        trace::verbose(_X("probe_config_t: probe=[%s] match-hash=[%d] patch-roll-forward=[%d] prerelease-roll-forward=[%d] deps-json=[%p]"),
            probe_dir.c_str(), match_hash, patch_roll_fwd, prerelease_roll_fwd, probe_deps_json);
    }
    bool is_roll_fwd_set() const
    {
        return patch_roll_fwd || prerelease_roll_fwd;
    }

    probe_config_t(
        const pal::string_t& probe_dir,
        bool match_hash,
        bool patch_roll_fwd,
        bool prerelease_roll_fwd,
        const deps_json_t* probe_deps_json,
        bool only_serviceable_assets,
        bool only_runtime_assets)
        : probe_dir(probe_dir)
        , match_hash(match_hash)
        , patch_roll_fwd(patch_roll_fwd)
        , prerelease_roll_fwd(prerelease_roll_fwd)
        , probe_deps_json(probe_deps_json)
        , only_serviceable_assets(only_serviceable_assets)
        , only_runtime_assets(only_runtime_assets)
    {
        // Cannot roll forward and also match hash.
        assert(!is_roll_fwd_set() || !match_hash);
        // Will not roll forward within a deps json.
        assert(!is_roll_fwd_set() || probe_deps_json == nullptr);
        // Will not do hash match when probing a deps json.
        assert(!match_hash || probe_deps_json == nullptr);
    }

    static probe_config_t svc_ni(const pal::string_t& dir, bool patch_roll_fwd, bool prerelease_roll_fwd)
    {
        return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, true, true);
    }

    static probe_config_t svc(const pal::string_t& dir, bool patch_roll_fwd, bool prerelease_roll_fwd)
    {
        return probe_config_t(dir, false, patch_roll_fwd, prerelease_roll_fwd, nullptr, true, false);
    }

    static probe_config_t cache_ni(const pal::string_t& dir)
    {
        return probe_config_t(dir, true, false, false, nullptr, false, true);
    }
    
    static probe_config_t cache(const pal::string_t& dir)
    {
        return probe_config_t(dir, true, false, false, nullptr, false, false);
    }

    static probe_config_t fx(const pal::string_t& dir, const deps_json_t* deps)
    {
        return probe_config_t(dir, false, false, false, deps, false, false);
    }

    static probe_config_t additional(const pal::string_t& dir)
    {
        return probe_config_t(dir, false, false, false, nullptr, false, false);
    }
};

struct arguments_t
{
    pal::string_t own_path;
    pal::string_t app_dir;
    pal::string_t deps_path;
    pal::string_t core_servicing;
    std::vector<pal::string_t> probe_paths;
    pal::string_t dotnet_packages_cache;
    pal::string_t managed_application;

    int app_argc;
    const pal::char_t** app_argv;

    arguments_t();

    inline void print()
    {
        if (trace::is_enabled())
        {
            trace::verbose(_X("-- arguments_t: own_path=%s app_dir=%s deps=%s core_svc=%s packages_cache=%s mgd_app=%s"),
                own_path.c_str(), app_dir.c_str(), deps_path.c_str(), core_servicing.c_str(), dotnet_packages_cache.c_str(), managed_application.c_str());
            for (const auto& probe : probe_paths)
            {
                trace::verbose(_X("-- arguments_t: probe dir: [%s]"), probe.c_str());
            }
        }
    }
};

bool parse_arguments(const pal::string_t& deps_path, const std::vector<pal::string_t>& probe_paths, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args);

#endif // ARGS_H
