#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_evictcontrol_ctx
{
    TC_HANDLE        handle;
    bool             enable;
    uint32_t         persist_index;
    uint32_t         key_index;
    uint32_t         hierarchy;
    TC_BUFFER       *hierarchy_auth_msg;
};

TC_RC tpm2_evictcontrol_init(struct api_ctx_st *api_ctx, int num, ...)
{
    TC_RC rc = TC_SUCCESS;
    struct tpm2_evictcontrol_ctx* ectx = (struct tpm2_evictcontrol_ctx*)malloc(sizeof(struct tpm2_evictcontrol_ctx));

    va_list ap;
    va_start(ap, num);
    ectx->handle = va_arg(ap, TC_HANDLE);
    ectx->enable = va_arg(ap, int);
    ectx->persist_index = va_arg(ap, uint32_t);
    ectx->key_index = va_arg(ap, uint32_t);
    ectx->hierarchy = va_arg(ap, uint32_t);
    ectx->hierarchy_auth_msg = va_arg(ap, TC_BUFFER*);
    va_end(ap);

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

TC_RC tpm2_evictcontrol_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_evictcontrol(API_CTX *ctx)
{
    TC_RC rc = TC_SUCCESS;

    struct tpm2_evictcontrol_ctx* ectx = (struct tpm2_evictcontrol_ctx*)ctx->data;
    TC_HANDLE_CTX* tc_handle_ctx = (TC_HANDLE_CTX*)(ectx->handle);


    TSS2L_SYS_AUTH_RESPONSE sessionsDataout;
    TSS2L_SYS_AUTH_COMMAND sessionsData = {
        .auths    = {{.sessionHandle = TPM2_RS_PW}},
        .count    = 1
    };

    if (ectx->hierarchy_auth_msg != NULL) {
        if (ectx->hierarchy_auth_msg->size > sizeof(TPMU_HA)) {
            log_error("The hierarchy authorization authentication password exceeds the limit\n");
            return TC_AUTH_HMAC_OVERSIZE;
        }        
        sessionsData.auths[0].hmac.size = ectx->hierarchy_auth_msg->size;
        memcpy(sessionsData.auths[0].hmac.buffer,
               ectx->hierarchy_auth_msg->buffer,
               ectx->hierarchy_auth_msg->size);
    }

    if (ectx->enable) {
        if (ectx->key_index > tc_handle_ctx->handle.tc_object->count) {
            log_error("Invalid object index\n");
            return TC_OBJECT_INDEX;
        }
        rc = Tss2_Sys_EvictControl((TSS2_SYS_CONTEXT*)tc_handle_ctx->handle.tc_context,
                                    ectx->hierarchy,
                                    tc_handle_ctx->handle.tc_object->node_info[ectx->key_index]->obj_handle,
                                    &sessionsData,
                                    ectx->persist_index,
                                    &sessionsDataout);
    }else{
        rc = Tss2_Sys_EvictControl((TSS2_SYS_CONTEXT*)tc_handle_ctx->handle.tc_context,
                                    ectx->hierarchy,
                                    ectx->persist_index,
                                    &sessionsData,
                                    ectx->persist_index,
                                    &sessionsDataout);
    }

    if (rc == TSS2_RC_SUCCESS) {
        if (ectx->enable) {
            tc_handle_ctx->handle.tc_object->node_info[ectx->key_index]->persist_index = ectx->persist_index;
        }

    }else{
        log_error("Failed to run api_evictcontrol:0x%0x\n", rc);
        rc = TC_COMMAND_EVICTCONTROL;
    }
   
    return rc;
}