/*
 *  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


/*!\file vpx_decoder.c
 * \brief Provides the high level interface to wrap decoder algorithms.
 *
 */
#include <stdarg.h>
#include "vpx/vpx_integer.h"
#include "vpx/internal/vpx_codec_internal.h"
#include "vpx_version.h"

#define SAVE_STATUS(ctx,var) (ctx?(ctx->err = var):var)

int vpx_codec_version(void)
{
    return VERSION_PACKED;
}


const char *vpx_codec_version_str(void)
{
    return VERSION_STRING_NOSP;
}


const char *vpx_codec_version_extra_str(void)
{
    return VERSION_EXTRA;
}


const char *vpx_codec_iface_name(vpx_codec_iface_t *iface)
{
    return iface ? iface->name : "<invalid interface>";
}

const char *vpx_codec_err_to_string(vpx_codec_err_t  err)
{
    switch (err)
    {
    case VPX_CODEC_OK:
        return "Success";
    case VPX_CODEC_ERROR:
        return "Unspecified internal error";
    case VPX_CODEC_MEM_ERROR:
        return "Memory allocation error";
    case VPX_CODEC_ABI_MISMATCH:
        return "ABI version mismatch";
    case VPX_CODEC_INCAPABLE:
        return "Codec does not implement requested capability";
    case VPX_CODEC_UNSUP_BITSTREAM:
        return "Bitstream not supported by this decoder";
    case VPX_CODEC_UNSUP_FEATURE:
        return "Bitstream required feature not supported by this decoder";
    case VPX_CODEC_CORRUPT_FRAME:
        return "Corrupt frame detected";
    case  VPX_CODEC_INVALID_PARAM:
        return "Invalid parameter";
    case VPX_CODEC_LIST_END:
        return "End of iterated list";
    }

    return "Unrecognized error code";
}

const char *vpx_codec_error(vpx_codec_ctx_t  *ctx)
{
    return (ctx) ? vpx_codec_err_to_string(ctx->err)
           : vpx_codec_err_to_string(VPX_CODEC_INVALID_PARAM);
}

const char *vpx_codec_error_detail(vpx_codec_ctx_t  *ctx)
{
    if (ctx && ctx->err)
        return ctx->priv ? ctx->priv->err_detail : ctx->err_detail;

    return NULL;
}


vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx)
{
    vpx_codec_err_t res;

    if (!ctx)
        res = VPX_CODEC_INVALID_PARAM;
    else if (!ctx->iface || !ctx->priv)
        res = VPX_CODEC_ERROR;
    else
    {
        if (ctx->priv->alg_priv)
            ctx->iface->destroy(ctx->priv->alg_priv);

        ctx->iface = NULL;
        ctx->name = NULL;
        ctx->priv = NULL;
        res = VPX_CODEC_OK;
    }

    return SAVE_STATUS(ctx, res);
}


vpx_codec_caps_t vpx_codec_get_caps(vpx_codec_iface_t *iface)
{
    return (iface) ? iface->caps : 0;
}


vpx_codec_err_t vpx_codec_control_(vpx_codec_ctx_t  *ctx,
                                   int               ctrl_id,
                                   ...)
{
    vpx_codec_err_t res;

    if (!ctx || !ctrl_id)
        res = VPX_CODEC_INVALID_PARAM;
    else if (!ctx->iface || !ctx->priv || !ctx->iface->ctrl_maps)
        res = VPX_CODEC_ERROR;
    else
    {
        vpx_codec_ctrl_fn_map_t *entry;

        res = VPX_CODEC_ERROR;

        for (entry = ctx->iface->ctrl_maps; entry && entry->fn; entry++)
        {
            if (!entry->ctrl_id || entry->ctrl_id == ctrl_id)
            {
                va_list  ap;

                va_start(ap, ctrl_id);
                res = entry->fn(ctx->priv->alg_priv, ctrl_id, ap);
                va_end(ap);
                break;
            }
        }
    }

    return SAVE_STATUS(ctx, res);
}
