#include "common/msg.h"
#include "options/m_config.h"

#include "spirv.h"
#include "config.h"

extern const struct spirv_compiler_fns spirv_shaderc;

// in probe-order
enum {
    SPIRV_AUTO = 0,
    SPIRV_SHADERC, // generally preferred, but not packaged everywhere
};

static const struct spirv_compiler_fns *compilers[] = {
#if HAVE_SHADERC
    [SPIRV_SHADERC] = &spirv_shaderc,
#endif
    NULL
};

static const struct m_opt_choice_alternatives compiler_choices[] = {
    {"auto",        SPIRV_AUTO},
#if HAVE_SHADERC
    {"shaderc",     SPIRV_SHADERC},
#endif
    {0}
};

struct spirv_opts {
    int compiler;
};

#define OPT_BASE_STRUCT struct spirv_opts
const struct m_sub_options spirv_conf = {
    .opts = (const struct m_option[]) {
        {"spirv-compiler", OPT_CHOICE_C(compiler, compiler_choices)},
        {0}
    },
    .size = sizeof(struct spirv_opts),
};

bool spirv_compiler_init(struct ra_ctx *ctx)
{
    void *tmp = talloc_new(NULL);
    struct spirv_opts *opts = mp_get_config_group(tmp, ctx->global, &spirv_conf);
    int compiler = opts->compiler;
    talloc_free(tmp);

    for (int i = SPIRV_AUTO+1; i < MP_ARRAY_SIZE(compilers); i++) {
        if (compiler != SPIRV_AUTO && i != compiler)
            continue;
        if (!compilers[i])
            continue;

        ctx->spirv = talloc_zero(ctx, struct spirv_compiler);
        ctx->spirv->log = ctx->log,
        ctx->spirv->fns = compilers[i];

        const char *name = m_opt_choice_str(compiler_choices, i);
        strncpy(ctx->spirv->name, name, sizeof(ctx->spirv->name) - 1);
        MP_VERBOSE(ctx, "Initializing SPIR-V compiler '%s'\n", name);
        if (ctx->spirv->fns->init(ctx))
            return true;
        talloc_free(ctx->spirv);
        ctx->spirv = NULL;
    }

    MP_ERR(ctx, "Failed initializing SPIR-V compiler!\n");
    return false;
}
