#include <stdarg.h>

#include "tc_private/tc_handle.h"
#include "tc_private/tc_private.h"

#include "log/log.h"

#include "tc_tpm2.h"
#include "tpm2_common.h"

#include "tc_type.h"
#include "tc_errcode.h"

struct tpm2_hash_ctx
{
    TC_HANDLE        handle;
    TC_ALG           alg_hash;
    TC_BUFFER       *plain_text;
    TC_BUFFER       *digest_msg;
};

TC_RC tpm2_hash_init(struct api_ctx_st *api_ctx, int num, ...)
{
    TC_RC rc = TC_SUCCESS;
    struct tpm2_hash_ctx* hctx = (struct tpm2_hash_ctx*)malloc(sizeof(struct tpm2_hash_ctx));

    va_list ap;
    va_start(ap, num);
    hctx->handle = va_arg(ap, TC_HANDLE);
    hctx->alg_hash = va_arg(ap, TC_ALG);
    hctx->plain_text = va_arg(ap, TC_BUFFER*);
    hctx->digest_msg = va_arg(ap, TC_BUFFER*);
    va_end(ap);

    api_ctx->data = (HANDLE_DATA*)hctx;
    return rc;
}

TC_RC tpm2_hash_free(struct api_ctx_st *api_ctx)
{
    TC_RC rc = TC_SUCCESS;  
    free(api_ctx->data); 
    api_ctx->data = NULL;
    api_ctx->cmd_code = API_NULL;
    return rc;
}

TC_RC tpm2_hash(API_CTX *ctx)
{
    TC_RC rc = TC_SUCCESS;

    struct tpm2_hash_ctx* hctx = (struct tpm2_hash_ctx*)ctx->data;
    TC_HANDLE_CTX* tc_handle_ctx = (TC_HANDLE_CTX*)(hctx->handle);

    TPM2B_DIGEST digest = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer);
    TPM2B_MAX_BUFFER digest_buffer = TPM2B_TYPE_INIT(TPM2B_MAX_BUFFER, buffer);
    TPMT_TK_HASHCHECK validation;

    if (hctx->plain_text->size > TPM2_MAX_DIGEST_BUFFER) {
        log_error("The length of the data to be hashed exceeds the limit\n");
        return TC_HASH_BUFFER_OVERSIZE;
    }
    digest_buffer.size = hctx->plain_text->size;
    memcpy(digest_buffer.buffer,
           hctx->plain_text->buffer,
           hctx->plain_text->size);

    TPMI_ALG_HASH alg_hash = TPM2_ALG_ERROR;

    switch (hctx->alg_hash)
    {
    case TC_SHA256:
        alg_hash = TPM2_ALG_SHA256;
        break;
    case TC_SM3:
        alg_hash = TPM2_ALG_SM3_256;
        break;
    case TC_SHA1:
        alg_hash = TPM2_ALG_SHA1;
        break;    
    default:
        log_error("unrecogize the tpm2_hash algorithms, %d\n", hctx->alg_hash);
        return TC_UNDEFINE_ALGO;
    }

    rc = Tss2_Sys_Hash((TSS2_SYS_CONTEXT*)tc_handle_ctx->handle.tc_context,
                        NULL,
                        &digest_buffer,
                        alg_hash,
                        TPM2_RH_OWNER,
                        &digest,
                        &validation,
                        NULL);

        hctx->digest_msg->buffer = (uint8_t*)malloc(digest.size);
        memcpy(hctx->digest_msg->buffer, digest.buffer, digest.size);
        hctx->digest_msg->size = digest.size;
end:
    if (rc != TSS2_RC_SUCCESS) {
        log_error("Failed to run api_hash:0x%0x\n", rc);
        rc = TC_COMMAND_HASH;
    }
    return rc;
}