/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Created in Samsung Ukraine R&D Center (SRK) under a contract between
 * LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
 * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 *
 * Created on: Mar 17, 2016
 * Author: Oleksandr Usatov <o.usatov@samsung.com>
 * Brief: Trustlet entry point.
 */

#include "TigerTci.h"
#include "TigerLogging.h"
#include "TigerMacroses.h"
#include "TigerMbedTlsHooks.h"
#include "TigerCore.h"
#include "TzwMemory.h"
#include "TzwString.h"

#include "ta_banner_print.h"

extern const char *tigerAppVersion;
const char *TIGERFP_TA_NAME="TIGERFP";
static uint8_t gQseeLogMask = 0;

/**
 * Function is the service constructor, which the system calls when it creates a new instance of the service.
 **/
void tz_app_init(void) {
    gQseeLogMask = qsee_log_get_mask();
    qsee_log_set_mask(LOG_MASK);

    print_banner(TIGERFP_TA_NAME, tigerAppVersion);

    setupMbedTlsHooks();
}

/**
 *  Function is the service destructor, which the system calls when the instance is being destroyed.
 **/
void tz_app_shutdown(void) {
    LOG_I("tigerfp is shutdown.");

    qsee_log_set_mask(gQseeLogMask);
}

/**
 *  This function calls when the client invokes a command within the given app.
 **/
void tz_app_cmd_handler(void* cmd, uint32_t cmdlen, void* rsp, uint32_t rsplen) {
    qsc_send_cmd_t* pCmd = (qsc_send_cmd_t*) cmd;
    qsc_send_cmd_rsp_t* pRsp = (qsc_send_cmd_rsp_t*) rsp;

    if ((!rsp) || (!rsplen)) {
        LOG_E("Null response parameters.");
        return;
    }

    if ((!cmd) || (!cmdlen)) {
        LOG_E("Null request parameters.");
        return;
    }

    if (cmdlen < sizeof(qsc_send_cmd_t)) {
        LOG_E("cmdlen = %u < %u = sizeof(qsc_send_cmd_t)", cmdlen, sizeof(qsc_send_cmd_t));
        return;
    }

    if (rsplen < sizeof(qsc_send_cmd_rsp_t)) {
        LOG_E("rsplen = %u < %u = sizeof(qsc_send_cmd_rsp_t)", rsplen, sizeof(qsc_send_cmd_rsp_t));
        return;
    }

    uint32_t commandId = pCmd->cmd_id;
    TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

    do {

#if !defined(TIGERFP_RELEASE) && defined(DEV_TA_DUMP_INOUT)
            logRawByteArrayHex((uint8_t*)pCmd->data, pCmd->len, "Request");
#endif
        status = processCommand(commandId, (void*) pCmd->data, pCmd->len, (void*) pRsp->data, pRsp->len);
#if !defined(TIGERFP_RELEASE) && defined(DEV_TA_DUMP_INOUT)
            logRawByteArrayHex((uint8_t*)pRsp->data, pRsp->len, "Response");
#endif
        if (status != TEE_SUCCESS) {
            LOG_E("Failure while %s: %s", getTciCommandIdStr(pCmd->cmd_id), getTeeErrorText(status));
        } else {
            LOG_I("%s: %s", getTciCommandIdStr(pCmd->cmd_id), getTeeErrorText(status));
        }

#if defined(TRANSMIT_LOG_TO_CA)
#ifdef TIGERFP_RELEASE
        if(TEE_SUCCESS != status) {
#endif /*TIGERFP_RELEASE*/
            int len = 0, total_len = 0;
            qsc_send_cmd_rsp_t *logOut = (qsc_send_cmd_rsp_t*)(rsp);
            char *ptr = (char*)logOut->log_buf;
            logOut->log_len= 0;
            while(!isStackLogEmpty()) {
                char *str = popStackLog(&len);

                if( LOGGER_BUF_LEN < logOut->log_len){
                    LOG_Raw("LOGGER_BUF_LEN is too samll to contain all TA log");
                    LOG_Raw("Missing log: %s", str);
                    total_len += (len + 4);
                    continue;
                }

                *((uint32_t*)ptr) = len;
                ptr += 4;

                strncpy(ptr, str, len);
                ptr += len;

                logOut->log_len += (len + 4);
                total_len +=(len + 4);

                tzwFree(str);
            }
            if( LOGGER_BUF_LEN < logOut->log_len){
                LOG_Raw("We need to extend length of logger to 0x%08x", total_len);
            }
#if 0
        {
            int len = 0;
            qsc_send_cmd_rsp_t *logOut =  (qsc_send_cmd_rsp_t*)(rsp);
            char *ptr = (char*)logOut->log_buf;
            logOut->log_len= 0;
            while(!isStackLogEmpty()) {
                if( LOGGER_BUF_LEN < logOut->log_len){
                    LOG_Raw("LOGGER_BUF_LEN is too samll to contain all TA log");
                    break;
                }
                char *str = popStackLog(&len);
                *((uint32_t*)ptr) = len;
                ptr += 4;

                strncpy(ptr, str, len);
                ptr += len;

                logOut->log_len += (len + 4);

                tzwFree(str);
            }
        }
#endif

#ifdef TIGERFP_RELEASE
		}
#endif /*TIGERFP_RELEASE*/

#endif /*TRANSMIT_LOG_TO_CA*/
    } while (0);


    pRsp->status = status;
}
