/*
@file app_main.c
*/

#include "CICCCGrdmROTCred.h"
#include "CICCCGrdmBLCred.h"
#include "CICCCGrdmICCCCred.h"
#include "CICCCGrdmDefaultCred.h"

#include "CICCCGrdmROTCred_open.h"
#include "CICCCGrdmBLCred_open.h"
#include "CICCCGrdmICCCCred_open.h"
#include "CICCCGrdmDefaultCred_open.h"
#include "object.h"
#include "ICredentials.h"

#include "app_version.h"

#include "app_main.h"
#include "app_service.h"
#include "app_credential_iccc.h"
#include "app_allowlist.h"
#include "app_grdm_status.h"
#include "tz_iccc_grdm_api.h"

/**
 * Modify the app name to your specific app name
 */
char TZ_APP_NAME[] = {"icccgrd"};

int32_t tz_module_open(uint32_t uid, Object cred, Object *objOut)
{
    uint32_t ret = Object_ERROR_INVALID;
    char caller_ta_name[32] = {0, };
    size_t caller_ta_name_size = 0;

    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : tz buildinfo: version %s", TAG, TZ_ICCC_GRDM_VERSION);
    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : tz_module_open() uid: %d", TAG, uid);

    ret = get_app_name(cred, caller_ta_name, 32, &caller_ta_name_size);
    if (!Object_isOK(ret)) {
        qsee_log(QSEE_LOG_MSG_DEBUG, "%s : tz_module_open() error on get_app_name", TAG);
        ret = TZ_GRDM_ICCC_FAILURE;
        goto error;
    }

    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : caller_ta_name = %s && caller_ta_name_size = %d", TAG, caller_ta_name, caller_ta_name_size);

    ret = check_ta_cmd_permission(caller_ta_name, strlen(caller_ta_name), uid);
    if (ret != TZ_GRDM_ICCC_SUCCESS) {
        qsee_log(QSEE_LOG_MSG_DEBUG, "%s : check command permission failed to TA %s on execute command %d", TAG, caller_ta_name, uid);
        goto error;
    }

    switch (uid) {
        case CICCCGrdmROTCred_UID:
            return CICCCGrdmROTCred_open(cred, objOut);
        case CICCCGrdmBLCred_UID:
            return CICCCGrdmBLCred_open(cred, objOut);
        case CICCCGrdmICCCCred_UID:
            return CICCCGrdmICCCCred_open(cred, objOut);
        case CICCCGrdmDefaultCred_UID:
            return CICCCGrdmDefaultCred_open(cred, objOut);
        default:
            ret = Object_ERROR_INVALID;
            break;
    }

error:
  *objOut = Object_NULL;
  return ret;
}

/**
  @brief
    Add any app specific initialization code here
    QSEE will call this function after secure app is loaded and authenticated
*/
static uint8_t qsee_log_mask;

void tz_app_init(void)
{
    //qsee_log_set_mask(QSEE_LOG_MSG_ERROR | QSEE_LOG_MSG_FATAL | QSEE_LOG_MSG_DEBUG | QSEE_LOG_MSG_HIGH);
    qsee_log_mask = qsee_log_get_mask();
    qsee_log_set_mask(QSEE_LOG_MSG_ERROR | QSEE_LOG_MSG_FATAL | QSEE_LOG_MSG_DEBUG);
    /*  App specific initialization code*/
    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : Init ", TAG);
}

/**
  @brief
    App specific command handler
    App executes code based on input command
*/
void tz_app_cmd_handler(void* cmd, uint32 cmdlen, void* rsp, uint32 rsplen)
{
    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : tz buildinfo: version %s", TAG, TZ_ICCC_GRDM_VERSION);

    uint32_t ret = TZ_GRDM_ICCC_SUCCESS;
    tciMessage_t *sendmsg = NULL;
    tciMessage_t *respmsg = NULL;
    uint32_t cmd_id;

    if (cmd == NULL || cmdlen < sizeof(tciMessage_t) 
        || rsp == NULL || rsplen < sizeof(tciMessage_t)
        || ((cmd < rsp) && ((void *)((uint8_t *)cmd + cmdlen) > rsp))
        || ((rsp < cmd) && ((void *)((uint8_t *)rsp + rsplen) > cmd))) {
        qsee_log(QSEE_LOG_MSG_DEBUG, "%s : invalid cmd or rsp buffer", TAG);
        return;
    }

    sendmsg = (tciMessage_t*)qsee_malloc(sizeof(tciMessage_t));
    respmsg = (tciMessage_t*)qsee_malloc(sizeof(tciMessage_t));
    if (!sendmsg) {
        qsee_log(QSEE_LOG_MSG_DEBUG, "%s : sendmsg pointer is NULL", TAG);
        goto exit;
    }
    memset((void *)sendmsg, 0, sizeof(tciMessage_t));    
    memcpy((void *)sendmsg, cmd, sizeof(tciMessage_t));

    if (!respmsg) {
        qsee_log(QSEE_LOG_MSG_DEBUG, "%s : respmsg pointer is NULL", TAG);
        goto exit;
    }
    memset((void *)respmsg, 0, sizeof(tciMessage_t));
    memcpy((void *)respmsg, rsp, sizeof(tciMessage_t));

    cmd_id = sendmsg->header.id;
    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : tz_app_cmd_handler: cmd_id: %d", TAG, cmd_id);

    switch (cmd_id) {
        case CMD_ICCC_GRDM_ATTESTATION:
            qsee_log(QSEE_LOG_MSG_DEBUG, "%s : received command: %d!", TAG, cmd_id);
            ret = grdm_ICCC_attestation(&sendmsg->payload.attestation, &respmsg->payload.attestation);
            break;
        case CMD_BOOT_GRDM_SET_GRDM_STATUS:
            qsee_log(QSEE_LOG_MSG_DEBUG, "%s : received command: %d!", TAG, cmd_id);
            ret = grdm_ICCC_set_GRDM_status(&sendmsg->payload.bootloader);
            break;
        default:
            qsee_log(QSEE_LOG_MSG_DEBUG, "%s : received unknown command: %d!", TAG, cmd_id);
            ret = TZ_GRDM_ICCC_UNKNOWN_CMD;
            break;
    }

  respmsg->header.id = RSP_ID(cmd_id);
  respmsg->header.status = ret;

exit:
    if(sendmsg) {
        memcpy(cmd, (void *)sendmsg, sizeof(tciMessage_t));
        qsee_free(sendmsg);
    }

    if(respmsg) {
        memcpy(rsp, (void *)respmsg, sizeof(tciMessage_t));
        qsee_free(respmsg);
    }

    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : tz_app_cmd_handler: ret: %d", TAG, ret);
}

/**
  @brief
    App specific shutdown
    App will be given a chance to shutdown gracefully
*/
void tz_app_shutdown(void)
{
    /* app specific shutdown code*/
    qsee_log(QSEE_LOG_MSG_DEBUG, "%s : shutdown", TAG);
    return;
}
