#include "tf_wrapper.h"

#include "TzwStorage.h"
#include "TzwCommon.h"
#include "TigerMacroses.h"
#include "TzwMemory.h"
#include "TzwHash.h"
#include "TzwRpmb.h"

#include "TzwSerialNumber.h"
#include "uuid/uuid.h"

#include "TzwString.h"
#include "TzwTimer.h"
#include "TzwAuth.h"

#include "tlRpmbDriverApi.h"


#define LEN_SHA256_RES 32

struct {
	unsigned int is_rpmb : 1;
	unsigned int is_memory : 1;
	unsigned int is_hash : 1;
	unsigned int is_serialnum : 1;
	unsigned int is_string : 1;
	unsigned int is_timer : 1;
	unsigned int is_latest_auth_result : 1;
} flags;


void tm_all_run(){

	flags.is_rpmb = flags.is_memory = flags.is_hash = flags.is_serialnum =  0;
    flags.is_string = flags.is_timer = 0;
	flags.is_latest_auth_result = 1;

	if(flags.is_rpmb == 1){
	    tm_rpmb_run();
	}

	if(flags.is_memory == 1){
	    tm_memory_run();
	}

	if(flags.is_hash == 1){
	    tm_hash_run();
	}

	if(flags.is_serialnum == 1){
		tm_read_serialnumber_run();
	}
	
	if(flags.is_string == 1){
		tm_string_run();
	}

    if(flags.is_timer == 1){
		tm_timer_run();
	}

    if(flags.is_latest_auth_result == 1){
		tm_latest_auth_result_run();
	}
}

TEE_Result tm_rpmb_run(){

    LOG_I("Rpmb Test Start");

    TEE_Result status = TEE_ERROR_GENERIC;

//"byte is 48,65,6c,6c,6f,2c,20,52,70,6d,62,21"
	const char *content = "Hello, Rpmb!";

	status = rpmbWrite((uint8_t *)content,strlen(content));
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("Write RPMB");
	
	char readContent[1024] = {'\0'};

	status = rpmbRead((uint8_t *)readContent,strlen(content));
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("Read RPMB");

	if(memcmp(content,readContent,strlen(content)) == 0){
		LOG_I("Rpmb Test Success! content is %s",content);
		return TEE_SUCCESS;
	} else {
		LOG_E("Rpmb Test fail, Write content is %s but Read content  is %s",content,readContent);
		return TEE_ERROR_GENERIC;
	}	
}

void tm_memory_run(){
    LOG_I("Memory Test Start");

	TzwSfsObject_t lHandle = TEE_HANDLE_NULL;

	lHandle = tzwMalloc(sizeof(TEE_ObjectHandle));

//	TIGER_CHECK_BUFFER_ALLOCATED_BREAK(lHandle);

	if(NULL == lHandle){
		LOG_E("tzwMalloc fail!");
		return;
	}

	tzwFree(lHandle);
	lHandle = NULL;

	LOG_I("Memory Test Success!");
//	if(lHandle != NULL){
//		LOG_E("Memory Test fail, tzwFree fail!!");
//	} else {
//		LOG_I("Memory Test Success!");
//	}
}

TEE_Result tm_hash_run(){
    LOG_I("Hash Test Start");

    TzwHashOperation_t hashOperation = TEE_HANDLE_NULL;

	TzwErrorCode_t status = TEE_ERROR_GENERIC;

	status = tzwAllocateHashOperation(&hashOperation, TEE_ALG_SHA256);
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("allocate hashOperation");

	char *rawContent = "hello";
	status = tzwHashUpdate(hashOperation,rawContent,strlen(rawContent));
	status = tzwHashUpdate(hashOperation,"world",5);
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("hashUpdate");

	char result[LEN_SHA256_RES + 1] = {'\0'};
	size_t length = 32;
	status = tzwHashFinalize(hashOperation,NULL,0,result,&length);
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("1st hashFinalize");

	logRawByteArrayHex((uint8_t*)result,length,"1st hash result");

	tzwFreeHashOperation(hashOperation);

	//hash sha256  result of "helloworld"
	char expectRes[LEN_SHA256_RES] = {0x93,0x6a,0x18,0x5c,0xaa,0xa2,0x66,0xbb
	,0x9c,0xbe,0x98,0x1e,0x9e,0x05,0xcb,0x78,
	0xcd,0x73,0x2b,0x0b,0x32,0x80,0xeb,0x94,
	0x44,0x12,0xbb,0x6f,0x8f,0x8f,0x07,0xaf};

	if(memcmp(expectRes,result,LEN_SHA256_RES) == 0){
        LOG_I("Hash Test Success!");
	    return TEE_SUCCESS;
	} else {
        LOG_I("Hash Test Fail!");
		return TEE_ERROR_GENERIC;
	}
}


TEE_Result tm_read_serialnumber_run(){
    LOG_I("Read Serial Number Test Start");

	TEE_Result status = TEE_ERROR_GENERIC;

	TzwSerialNumber_t apSerialNum;

	status = tzwReadSerialNumber(&apSerialNum);
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("Read Serial Number");

	char serial[48] = {0};
	uuid_unparse(&apSerialNum.uuid,serial);

    LOG_I("Read Serial Number %s Test Success!", serial);
	
	return status;
}


#define TF_CHECK_COMPARE_PTR_SUCCESS_RETURN(msg) \
	if(tzwMemCompare(dst,src,strlen(src)) != 0){ \
	    LOG_E("fail to %s!",msg); \
		return status; \
	}
    
TEE_Result tm_string_run(){
    LOG_I("String Test Start");
    
	TEE_Result status = TEE_ERROR_GENERIC;

    char dst[1024] = {'\0'};
    const char* src = "hello,String";

	tzwMemMove(dst,src,strlen(src));	
	TF_CHECK_COMPARE_PTR_SUCCESS_RETURN("tzwMemMove");

	tzwMemFill(dst,'\0',sizeof(dst)/sizeof(char));	
	tzwMemFill(dst,'1',4);// the content is "1111"	

	unsigned long result = tzwStrtoul(dst,10);	
//	LOG_I("String Test result is %lu",result);
	assert(result==1111);		

	char* newdst = tzwStrncat(dst,src,5,5);
//	LOG_I("String Test newdst is %s",newdst);
	assert(tzwMemCompare(newdst,"1111hello",9) == 0);	

	LOG_I("String Test Success!");

	return status;
}

TEE_Result tm_timer_run(){
	LOG_I("Timer Test Start!");

	uint64_t res = systemTime();
	LOG_I("systemTime is %lu",res);	

    uint8_t randomBuffer[20] = {'\0'};
	TEE_Result status = tzwGenerateRandom(randomBuffer,20);	
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("tzwGenerateRandom");

	logRawByteArrayHex(randomBuffer,20,"stzwGenerateRandom result :");

    LOG_I("String Test Success!");
	
	return TEE_SUCCESS;
}

TEE_Result tm_latest_auth_result_run(){
	LOG_I("Auth Test Start!");

	uint32_t fpIndex = 0;
	uint8_t realFid[32] = {'\0'};
	uint32_t realFidSize = 0;

	TEE_Result status = TEE_ERROR_GENERIC;
	status = getLatestAuthResult(realFid,&realFidSize,&fpIndex);
	TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("tm_latest_auth_result_run");

	logRawByteArrayHex(realFid,realFidSize,"tm_latest_auth_result_run");

    LOG_I("Auth Test Success! fpIndex is %"PRIu32"@%p",fpIndex,&fpIndex);

	return TEE_SUCCESS;
}
