/**
 * Created: tianfang.shi@samsung.com
 * Data:    17-7-10
 */
#include <qsee_timer.h>
#include <bits/limits.h>

#include "ta_logger.h"
#include "tzWrappers/TzwString.h"
#include "tzWrappers/TzwMemory.h"

#include "gp_oem.h"
#include "ifaa_fingerprint_id_table.h"
#include "ifaa_mem_utils.h"
#include "qsee_core.h"
/*#include "ifaa_log_utils.h"*/
#include "stdio.h"
#include "biometric_result.h"
#include "biometric_interrupt.h"
#include "qsee_core.h"
#include "string.h"

#define UNIQUE_ID_SIZE               (4 + 4 + 8)

TEE_Result TEE_GetDeviceID(uint8_t *deviceID, uint32_t *size) {
    LOG_D("Init deviveID");
    LOG_D("DeviceID size %u:", *size);
    uint8_t uniqueId[UNIQUE_ID_SIZE] = {0};
    uint8_t *pUuniq = uniqueId;
    // 1.bytes 0-3: Identify each silicon provider id, defined by SRC-T
    const uint32_t siliconProviderCode = 15;
    tzwMemMove(pUuniq, &siliconProviderCode, sizeof(siliconProviderCode));
    pUuniq += sizeof(siliconProviderCode);

// @deprecated
#if 0
    // 2.bytes 4-7: SoC model ID, defined by each silicon provider（like Qualcomm and Trustonic）. Example: MSM8996
#ifdef CHIP_NAME_MSM8998
    LOG_D("chipset name : msm8998");
    uint8_t chipId[4] = {'8', '9', '9', '8'};
#elif CHIP_NAME_SDM845
    LOG_D("chipset name : sdm845");
    uint8_t chipId[4] = {'m', '8', '4', '5'};
#elif CHIP_NAME_SDM660
    LOG_D("chipset name : sdm660");
    uint8_t chipId[4] = {'m', '6', '6', '0'};
#elif CHIP_NAME_SDM710
    LOG_D("chipset name : sdm710");
    uint8_t chipId[4] = {'m', '7', '1', '0'};
#elif CHIP_NAME_SDM450
    LOG_D("chipset name : sdm450");
    uint8_t chipId[4] = {'m', '4', '5', '0'};
#elif CHIP_NAME_SM8150
    LOG_D("chipset name : sm8150");
    uint8_t chipId[4] = {'8', '1', '5', '0'};
#elif CHIP_NAME_SM6150
    LOG_D("chipset name : sm6150");
    uint8_t chipId[4] = {'6', '1', '5', '0'};
#else
    LOG_D("Not defined chip name,Please defined it on SConscript like msm8998");
    uint8_t chipId[4] = {'0', '0', '0', '0'};
#endif
#endif

#ifdef __CHIPSET__
    uint8_t chipId[4] = {'0', '0', '0', '0'};
    char *chipsetName = __CHIPSET__;
    uint8_t len = strlen(chipsetName);

    LOG_D("chipset name : %s", chipsetName);
    for(int i = len - 4, j = 0; j < 4; j++){
        chipId[j] = chipsetName[i + j];
    }
#else
    LOG_D("Not defined chip name,Please defined it on SConscript like msm8998");
    uint8_t chipId[4] = {'0', '0', '0', '0'};
#endif

    logByteArrayHex(chipId, 4, "+CHIPID+");

    tzwMemMove(pUuniq, chipId, sizeof(chipId));
    pUuniq += sizeof(chipId);

    int realSerial = qsee_read_serial_num();
    size_t realSerialSize = sizeof(int);
    tzwMemMove(pUuniq, &realSerial, realSerialSize);
    pUuniq += realSerialSize;
    LOG_D("SerialNum %d, size: %zu", realSerial, realSerialSize);
    size_t bytesLeft = sizeof(uint64_t) - realSerialSize;
    if (bytesLeft > 0) {
        LOG_D("Filling %zu bytes", bytesLeft);
        // qsee_get_random_bytes(pUuniq, bytesLeft);
        while (bytesLeft > 0) {
            if (bytesLeft <= realSerialSize) {
                tzwMemMove(pUuniq, &realSerial, bytesLeft);
                pUuniq += bytesLeft;
                bytesLeft = 0;
            } else {
                tzwMemMove(pUuniq, &realSerial, realSerialSize);
                pUuniq += realSerial;
                bytesLeft -= realSerialSize;
            }
        }
    }
//    LOG_D("Data deviveID of uniqueId: %s", uniqueId);
    // Convert to HEX
    for (size_t i = 0; i < UNIQUE_ID_SIZE; ++i) {
        snprintf((char*) (deviceID + 2 * i), *size, "%02x", uniqueId[i]);
    }
    LOG_D("Data deviveID of HEX: %s", deviceID);
    return TEE_SUCCESS;
}

TEE_Result TEE_AuthenticatorSignDigest(void *digest, size_t digestLen,
                                       void *signature,
                                       size_t *signatureLen) {
    return TEE_SUCCESS;
}

int32_t TEE_GetAuthenticatorVersion(void) {
    return 1;
}

#define EXTENSION_DATA_SIZE 128

#if defined (SM8250)
    #define MAX_APP_NAME_LEN (128 + 1)
#elif defined (SM7225)
    #define MAX_APP_NAME_LEN 128
#elif defined (SM8350) || defined (SM8450)
    #define MAX_APP_NAME_LEN 128
#else
    #define MAX_APP_NAME_LEN (32)
#endif

TEE_Result TEE_GetFpLastIdentifiedResult(int32_t *id) {
    LOG_D("get last identified fid...");
    uint64_t current_time = qsee_get_uptime();
    uint64_t fp_result_time = 0;

    uint8_t extension_data_buffer[EXTENSION_DATA_SIZE] = {0};
    bio_buffer extension_data = {extension_data_buffer, EXTENSION_DATA_SIZE};

    uint8_t authenticator_name_buffer[MAX_APP_NAME_LEN] = {0};
    bio_buffer authenticator_name = {authenticator_name_buffer, MAX_APP_NAME_LEN};

    bio_result result = {BIO_FINGERPRINT_MATCHING,   false, BIO_NA, BIO_NA, BIO_NA};

    BIO_ERROR_CODE ret = bio_get_auth_result(&result, &fp_result_time, &extension_data, &authenticator_name);
    if(BIO_NO_ERROR != ret){
        LOG_E("fail to get auth result : %d", ret);
        return TEE_ERROR_COMMUNICATION;
    }

    char fp_ta_name1[10] = "dualfp";
    char fp_ta_name2[10] = "securefp";
	
    /*if(!(strcmp((const char *)authenticator_name_buffer, fp_ta_name1) == 0 || strcmp((const char*)authenticator_name_buffer, fp_ta_name2) == 0)){
        LOG_E("result not from FP TA. real ta name is : %s", authenticator_name_buffer);
        return TEE_ERROR_BAD_PARAMETERS;
    }*/

	if (!strstr((const char*) authenticator_name.data, fp_ta_name1)
        && !strstr((const char*) authenticator_name.data, fp_ta_name2)) {
        LOG_I("We only trust authenticator TA: %s or %s", fp_ta_name1, fp_ta_name2);
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if(current_time - fp_result_time > 2*1000){
/*#warning(LONG_BIT)*/
#if LONG_BIT == 32
/*#warning("LONG_BIT == 32")*/
        LOG_E("timeout error, result is invalid. time cap is: %lld", current_time - fp_result_time);
#elif LONG_BIT == 64
/*#warning("LONG_BIT == 64")*/
        LOG_E("timeout error, result is invalid. time cap is: %lu", current_time - fp_result_time);
#else
#error( "LONG_BIT is not defined in compiler")
#endif
        return TEE_ERROR_TIMEOUT;
    }
    /*
     * get fid from dualfp ta, result is
     *   read fid is:   extension_data.data
     *   fid index is:  result.user_entity_id
     *
     * Note: need to add logic to get IFAA specified fid
     */
/*#warning(LONG_BIT)*/
#if LONG_BIT == 32
/*#warning("LONG_BIT == 32")*/
    LOG_D("fingerprint index user_entity_id is : %llu.", (uint64_t) (result.user_entity_id) );
    LOG_D("fingerprint index user_id is : %llu.", (uint64_t) (result.user_id) );
    LOG_D("fingerprint index transaction_id is : %llu.", (uint64_t) (result.transaction_id) );
#elif LONG_BIT == 64
/*#warning("LONG_BIT == 64")*/
    LOG_D("fingerprint index user_entity_id is : %lu.", (uint64_t) (result.user_entity_id) );
    LOG_D("fingerprint index user_id is : %lu.", (uint64_t) (result.user_id) );
    LOG_D("fingerprint index transaction_id is : %lu.", (uint64_t) (result.transaction_id) );
#else
#error( "LONG_BIT is not defined in compiler")
#endif
    uint8_t fpData[128]={0};
   // fpData[extension_data.size]=0;
    tzwMemMove(fpData, extension_data.data + sizeof(int32_t), extension_data.size - sizeof(int32_t));
#ifdef __DEV_DEBUG__
    LOG_D("real fingerprint id size is : %d.", extension_data.size );
    LOG_D("real fingerprint id is : %s", fpData );
#endif
    *id = (int32_t) auto_get_ifaa_fid(FID_TABLE_PATH, FID_TABLE_PATH_LEN, fpData, result.user_entity_id);
    //LOG_D("fingerprint index id is : %llu.", (uint32_t) (result.user_entity_id) );
    return TEE_SUCCESS;
}

TEE_Result alipay_tz_invoke_command(uint8_t *in, size_t in_len,
                                    uint8_t *out, size_t *out_len) {
    return TEE_SUCCESS;
}

TEE_Result getEnrolledFingerPrint(SystemFidStruct *pEnrolledArray, uint8_t *realFidCnt) {

    LOG_FUNC_BEGIN;
    TA_ASSERT(pEnrolledArray != NULL);
    TA_ASSERT(realFidCnt != NULL);
    if(load_system_fid_table(pEnrolledArray, realFidCnt) != IFAA_ERR_SUCCESS) {
        LOG_E("load system table failed!");
        return TEE_ERROR_ACCESS_DENIED;
    }
    return TEE_SUCCESS;
}

TEE_Result TEE_GetFpList(uint8_t *idList, uint32_t *idListLen) {

    LOG_FUNC_BEGIN;
    TEE_Result result = TEE_SUCCESS;

    SystemFidStruct  enrolledFps[FID_TABLE_MAX] = {0};
    uint8_t realFidCnt = 0;

    result = getEnrolledFingerPrint(enrolledFps, &realFidCnt);

    LOG_D("getEnrolledFp result = 0x%08x, cnt = %d", result, realFidCnt);

    if(result == TEE_SUCCESS && realFidCnt > 0) {
        uint32_t ifaaIds[FID_TABLE_MAX] = {0};

        if(update_ifaa_fid(enrolledFps, ifaaIds, realFidCnt) == IFAA_ERR_SUCCESS) {
            *idListLen = realFidCnt*2*sizeof(uint32_t);
           uint8_t *pBuf = idList;
           for(uint32_t i = 0; i<realFidCnt; i++) {
                write32(pBuf, sizeof(uint32_t));
                pBuf += sizeof(uint32_t);
                write32(pBuf, ifaaIds[i]);
                pBuf += sizeof(uint32_t);
           }
        } else {
            LOG_E("TEE_GetFpList failed!");
            return TEE_ERROR_ACCESS_DENIED;
        }

    } else {
        LOG_D("TEE_GetFpList failed, status = 0x%08x", result);
    }
    LOG_FUNC_END;
    return result;
}
