#include "TuiConfirmScreenController.h"
#include "TZ_Vendor_tl.h"
#include "tci.h"
#include "tl_spay_tui_msg.h"
#include "process_cmd_coldwallet.h"
#include "TuiScreen.h"
#include "Vendor_Interface.h"
#include "tl_tui_bc_error_msg.h"
#include "TuiTouch.h"
#include "TuiControl.h"
#include "TuiState.h"
#include "SecureObject.h"
#include "TuiRotation.h"
#include "TuiLayout.h"

typedef void(*touchCallback)(uint32_t x, uint32_t y, uint32_t type);
uint32_t resumeScreen(void);
uint32_t excuteTouchCallBack(uint32_t x_out, uint32_t y_out, uint32_t type_out);

uint32_t initTuiScreen(void);
uint32_t initBackUpScreen(uint8_t* soBuffer, uint32_t soBufferLength);
uint32_t initRestoreScreen(void);
uint32_t initRestoreScreenTextLink(void);
uint32_t initConfirmScreen(uint8_t* soBuffer, uint32_t soBufferLength);
uint32_t cmdGetSo(uint8_t* soBuffer, uint32_t *soBufferLength);
uint32_t processState(uint32_t state);
uint32_t getResponseLength(uint32_t commandId);

//////////for test
uint8_t mnemonicData[240] = "lava roast sugar forward seat cash radar verify caution frame river photo luggage panda inflict sheriff warfare sponsor humble uncover endless lyrics pattern security";
uint8_t test_str[] = "type:BTC,to:0x30897cc6c9d69f6a2c2f1c651d51f22219f1a4f6,value:0.02593054 BTC,to:0xe5278edbe6d95004691d76b9d49af0647eec255d,value:0.07936319 BTC,fee:0.00108400 BTC";
//////////////////

static uint8_t unwrappedTransactionSo[BC_TUI_TRANSACTION_SO_BUFFER_SIZE];
static uint32_t unwrappedTransactionSoLength = sizeof(unwrappedTransactionSo);
static uint8_t wrappedTransactionSo[BC_TUI_TRANSACTION_SO_BUFFER_SIZE];
static uint32_t wrappedTransactionSoLength = sizeof(wrappedTransactionSo);

uint32_t process_cmd_coldwallet(uint32_t commandId, tciMessage_t * sendmsg, uint32_t sendmsg_len, tciMessage_t * respmsg, uint32_t respmsg_len) {
	uint32_t ret = TZ_API_OK;
	TuiState retState = getState();
	uint8_t* imageData;

	DBG_LOG("%s cw command : %x", LOG_TAG, commandId);

#ifdef TBASE_API_LEVEL
  if (commandId == SPAY_TUI_CMD_DRV_QTY) {
      DBG_LOG("SPAY_TUI_CMD_DRV_QTY should be ignored in tlMain!");
      return SPAY_TUI_NO_NOTIFY_MASK;
  }
#endif
	TZ_bzero(&respmsg->payload.rsp.data.commonRsp, sizeof(respmsg->payload.rsp.data.commonRsp));
	IS_BUFFER_VALID(sendmsg_len, spayTuiCommand_t, respmsg_len, spayTuiRsp_t) {
		DBG_LOG("%s Command and Response buffers validated", LOG_TAG);
	} else {
		STORE_TA_ERROR("Invalid command and response buffer lengths: sendmsg_len=%d size(spayTuiCommand_t)=%d, respmsg_len=%d, size(spayTuiRsp_t)=%d",
			sendmsg_len, sizeof(spayTuiCommand_t), respmsg_len,sizeof(spayTuiRsp_t));
		return TIMA_ERROR_INVALID_ARGUMENT;
	}
		
	//**** when need touch, we should save cmdId. If cmd needs touch, it must use commonRsp_t
	switch (commandId) {
		case BC_TUI_CMD_SET_LAYOUT_PARAMS:
			initLayoutWith(sendmsg->payload.cmd.data.layoutParams);

#if defined(TEST_LEGACY_LAYOUT)
			if(sendmsg->payload.cmd.data.layoutParams.DISPLAY_SUPPORT_TYPE & (1<<8)) {
				if (!testInitLayout()) {
					ret = processState(getState());

					respmsg->payload.rsp.data.commonRsp.retCode = getState();	// all response has retCode
					respmsg->spayhdr.header.status = 0;
					respmsg->spayhdr.header.id = RSP_ID(commandId);
					respmsg->spayhdr.header.len = getResponseLength(commandId);

					TTY_LOG("%s process_cmd retCode:0x%x, ret:0x%x, id:0x%x", LOG_TAG, respmsg->payload.rsp.data.commonRsp.retCode, ret, respmsg->spayhdr.header.id);

					return TZ_API_ERROR;
				}
			}
#endif
			break;

		case BC_TUI_CMD_START_BACKUP_SCREEN:
			memset(wrappedTransactionSo, 0, sizeof(wrappedTransactionSo));
			if (sizeof(wrappedTransactionSo) < sendmsg->payload.cmd.data.backupScreen.mnemonic_so.len) {
			    TTY_LOG("buffer size too small - buf_size : %d, n : %d", sizeof(wrappedTransactionSo), sendmsg->payload.cmd.data.backupScreen.mnemonic_so.len);
			    return TIMA_ERROR_INVALID_ARGUMENT;
			}

			memcpy(wrappedTransactionSo, sendmsg->payload.cmd.data.backupScreen.mnemonic_so.buf, sendmsg->payload.cmd.data.backupScreen.mnemonic_so.len);
			wrappedTransactionSoLength = sendmsg->payload.cmd.data.backupScreen.mnemonic_so.len;
			changeScreenState(BACKUP_SCREEN_STATE);
			break;

		case BC_TUI_CMD_SET_BACKUP_QUIZ_ORDER:
			if ((getPreState() & SESSION_ON_TUI_STATE) == SESSION_ON_TUI_STATE) {
				changeState(SETTING_BACKUP_QUIZ_ORDER_SESSION_ON_TUI_STATE);
			} else {
				changeState(SETTING_BACKUP_QUIZ_ORDER_TUI_STATE);
			}
			setBackupQuizOrder(sendmsg->payload.cmd.data.quizOrder.firstWord, sendmsg->payload.cmd.data.quizOrder.secondWord, sendmsg->payload.cmd.data.quizOrder.thirdWord);
			break;

		case BC_TUI_CMD_START_RECOVERY_SCREEN:
			memset(wrappedTransactionSo, 0, sizeof(wrappedTransactionSo));
			if (sizeof(wrappedTransactionSo) < sendmsg->payload.cmd.data.recoveryScreen.mnemonic_so.len) {
			    TTY_LOG("buffer size too small - buf_size : %d, n : %d", sizeof(wrappedTransactionSo), sendmsg->payload.cmd.data.recoveryScreen.mnemonic_so.len);
			    return TIMA_ERROR_INVALID_ARGUMENT;
			}

			memcpy(wrappedTransactionSo, sendmsg->payload.cmd.data.recoveryScreen.mnemonic_so.buf, sendmsg->payload.cmd.data.recoveryScreen.mnemonic_so.len);
			wrappedTransactionSoLength = sendmsg->payload.cmd.data.recoveryScreen.mnemonic_so.len;
			changeScreenState(RECOVERY_SCREEN_STATE);
			break;

		case BC_TUI_CMD_START_RESTORE_SCREEN:
			changeScreenState(RESTORE_SCREEN_STATE);
			break;

		case BC_TUI_CMD_START_CONFIRM_SCREEN: // 0x6000002
			memset(wrappedTransactionSo, 0, sizeof(wrappedTransactionSo));
			if (sizeof(wrappedTransactionSo) < sendmsg->payload.cmd.data.confirmScreen.transaction_so_cmd.len) {
			    TTY_LOG("buffer size too small - buf_size : %d, n : %d", sizeof(wrappedTransactionSo), sendmsg->payload.cmd.data.confirmScreen.transaction_so_cmd.len);
			    return TIMA_ERROR_INVALID_ARGUMENT;
			}

			memcpy(wrappedTransactionSo, sendmsg->payload.cmd.data.confirmScreen.transaction_so_cmd.buf, sendmsg->payload.cmd.data.confirmScreen.transaction_so_cmd.len);
			wrappedTransactionSoLength = sendmsg->payload.cmd.data.confirmScreen.transaction_so_cmd.len;
            setStartY(sendmsg->payload.cmd.data.confirmScreen.startY);
			changeScreenState(CONFIRM_SCREEN_STATE);
			break;

		case BC_TUI_CMD_GET_SO:
			TZ_bzero(&respmsg->payload.rsp.data.bcTransactionSoRsp, sizeof(respmsg->payload.rsp.data.bcTransactionSoRsp));
			respmsg->payload.rsp.data.bcTransactionSoRsp.transaction_so.len = (uint32_t) sizeof(respmsg->payload.rsp.data.bcTransactionSoRsp.transaction_so.buf);

			ret = cmdGetSo(respmsg->payload.rsp.data.bcTransactionSoRsp.transaction_so.buf, &respmsg->payload.rsp.data.bcTransactionSoRsp.transaction_so.len);
			break;

		case BC_TUI_CMD_SET_SCREEN_BACKGROUND:
			TTY_LOG("Background Resource : %d %d %d", sendmsg->payload.cmd.data.screenBackground.imageWidth, sendmsg->payload.cmd.data.screenBackground.imageHeight, sendmsg->payload.cmd.data.screenBackground.imageSize);
			if (sendmsg->payload.cmd.data.screenBackground.imageSize > RESOURCE_BUFFER_SIZE) {
				TTY_LOG("image size too big");
				return TIMA_ERROR_INVALID_ARGUMENT;
			}

			if ((getPreState() & SESSION_ON_TUI_STATE) == SESSION_ON_TUI_STATE) {
				changeState(SETTING_BACKGROUND_SESSION_ON_TUI_STATE);
			} else {
				changeState(SETTING_BACKGROUND_TUI_STATE);
			}
			imageData = setBackground(sendmsg->payload.cmd.data.screenBackground.imageSize, sendmsg->payload.cmd.data.screenBackground.imageWidth, sendmsg->payload.cmd.data.screenBackground.imageHeight);
			if (imageData == NULL) {
				TTY_LOG("Failed to set background");
				changeState(FAILED_TUI_STATE);
			}
			break;

		case BC_TUI_CMD_SET_TOUCHABLE_VIEW:
			TTY_LOG("BC_TUI_CMD_SET_TOUCHABLE_VIEW : %d", sendmsg->payload.cmd.data.screenView.viewId);
			DBG_LOG("View : %d, %d, %d, %d", sendmsg->payload.cmd.data.screenView.startX, sendmsg->payload.cmd.data.screenView.startY,
				sendmsg->payload.cmd.data.screenView.viewWidth, sendmsg->payload.cmd.data.screenView.viewHeight);
			DBG_LOG("Resource : %d, %d, %d", sendmsg->payload.cmd.data.screenView.eventSize, sendmsg->payload.cmd.data.screenView.originSize, sendmsg->payload.cmd.data.screenView.extraSize);

			if ((getPreState() & SESSION_ON_TUI_STATE) == SESSION_ON_TUI_STATE) {
				changeState(SETTING_TOUCHABLE_VIEW_SESSION_ON_TUI_STATE);
			} else {
				changeState(SETTING_TOUCHABLE_VIEW_TUI_STATE);
			}
			setScreenView(sendmsg->payload.cmd.data.screenView.viewId, sendmsg->payload.cmd.data.screenView.startX, sendmsg->payload.cmd.data.screenView.startY,
				sendmsg->payload.cmd.data.screenView.viewWidth, sendmsg->payload.cmd.data.screenView.viewHeight,
				sendmsg->payload.cmd.data.screenView.eventSize, sendmsg->payload.cmd.data.screenView.originSize, sendmsg->payload.cmd.data.screenView.extraSize);

			if (isExsitScreenView() &&
				((getState() == SETTING_TOUCHABLE_VIEW_TUI_STATE || getState() == SETTING_TOUCHABLE_VIEW_SESSION_ON_TUI_STATE) ||
				(getState() == SETTING_DRAWABLE_VIEW_TUI_STATE || getState() == SETTING_DRAWABLE_VIEW_SESSION_ON_TUI_STATE))) {
					uint8_t *buf = sendmsg->payload.cmd.data.screenView.resource.buf;
					uint32_t len = sendmsg->payload.cmd.data.screenView.eventSize;
					if (saveScreenViewResource(buf, len) != TUI_SUCCESS) {
						TTY_LOG("Failed to saveScreenViewResource");
						return TIMA_ERROR_INVALID_ARGUMENT;
					}

					buf += len;
					len = sendmsg->payload.cmd.data.screenView.originSize;
					if (saveScreenViewResource(buf, len) != TUI_SUCCESS) {
						TTY_LOG("Failed to saveScreenViewResource");
						return TIMA_ERROR_INVALID_ARGUMENT;
					}

					buf += len;
					len = sendmsg->payload.cmd.data.screenView.extraSize;
					if (saveScreenViewResource(buf, len) != TUI_SUCCESS) {
						TTY_LOG("Failed to saveScreenViewResource");
						return TIMA_ERROR_INVALID_ARGUMENT;
					}
				} else {
				    TTY_LOG("Failed to set resource data");
				}


			break;

		case BC_TUI_CMD_SET_DRAWABLE_VIEW:
			TTY_LOG("BC_TUI_CMD_SET_DRAWABLE_VIEW : %d", sendmsg->payload.cmd.data.screenView.viewId);
			DBG_LOG("View : %d, %d, %d, %d", sendmsg->payload.cmd.data.screenView.startX, sendmsg->payload.cmd.data.screenView.startY,
				sendmsg->payload.cmd.data.screenView.viewWidth, sendmsg->payload.cmd.data.screenView.viewHeight);
			DBG_LOG("Resource : %d, %d, %d", sendmsg->payload.cmd.data.screenView.eventSize, sendmsg->payload.cmd.data.screenView.originSize, sendmsg->payload.cmd.data.screenView.extraSize);

			if ((getPreState() & SESSION_ON_TUI_STATE) == SESSION_ON_TUI_STATE) {
				changeState(SETTING_DRAWABLE_VIEW_SESSION_ON_TUI_STATE);
			} else {
				changeState(SETTING_DRAWABLE_VIEW_TUI_STATE);
			}
			setScreenView(sendmsg->payload.cmd.data.screenView.viewId, sendmsg->payload.cmd.data.screenView.startX, sendmsg->payload.cmd.data.screenView.startY,
				sendmsg->payload.cmd.data.screenView.viewWidth, sendmsg->payload.cmd.data.screenView.viewHeight,
				sendmsg->payload.cmd.data.screenView.eventSize, sendmsg->payload.cmd.data.screenView.originSize, 0);

            if (isExsitScreenView() &&
                ((getState() == SETTING_TOUCHABLE_VIEW_TUI_STATE || getState() == SETTING_TOUCHABLE_VIEW_SESSION_ON_TUI_STATE) ||
                (getState() == SETTING_DRAWABLE_VIEW_TUI_STATE || getState() == SETTING_DRAWABLE_VIEW_SESSION_ON_TUI_STATE))) {
                uint8_t *buf = sendmsg->payload.cmd.data.screenView.resource.buf;
                uint32_t len = sendmsg->payload.cmd.data.screenView.eventSize;

				if (saveScreenViewResource(buf, len) != TUI_SUCCESS) {
					TTY_LOG("Failed to saveScreenViewResource");
					return TIMA_ERROR_INVALID_ARGUMENT;
				}

                buf += len;
                len = sendmsg->payload.cmd.data.screenView.originSize;
				if (saveScreenViewResource(buf, len) != TUI_SUCCESS) {
					TTY_LOG("Failed to saveScreenViewResource");
					return TIMA_ERROR_INVALID_ARGUMENT;
				}

         		} else {
                    TTY_LOG("Failed to set resource data");
      			}

			break;

		case BC_TUI_CMD_SEND_RESOURCE_DATA:
			TTY_LOG("BC_TUI_CMD_SEND_RESOURCE_DATA : %d, %d", sendmsg->payload.cmd.data.screenResource.index, sendmsg->payload.cmd.data.screenResource.resource.len);
			changeState(getPreState());
			if (isExsitBackground() && (getState() == SETTING_BACKGROUND_TUI_STATE || getState() == SETTING_BACKGROUND_SESSION_ON_TUI_STATE)) {
				saveBackgroundResource(sendmsg->payload.cmd.data.screenResource.index, sendmsg->payload.cmd.data.screenResource.resource.buf, sendmsg->payload.cmd.data.screenResource.resource.len);
			} else if (isExsitScreenView() &&
					((getState() == SETTING_TOUCHABLE_VIEW_TUI_STATE || getState() == SETTING_TOUCHABLE_VIEW_SESSION_ON_TUI_STATE) ||
					(getState() == SETTING_DRAWABLE_VIEW_TUI_STATE || getState() == SETTING_DRAWABLE_VIEW_SESSION_ON_TUI_STATE))) {
				saveScreenViewResource(sendmsg->payload.cmd.data.screenResource.resource.buf, sendmsg->payload.cmd.data.screenResource.resource.len);
			}
			break;

	    case BC_TUI_CMD_SEND_RESOURCE_DATA_ARRAY:
	        if (setResourceDataArray(sendmsg->payload.cmd.data.screenResourceArray.type,sendmsg->payload.cmd.data.screenResourceArray.buf) == false)
	        	return TIMA_ERROR_INVALID_ARGUMENT;
	        break;

		case BC_TUI_CMD_UPDATE_SCREEN:
			DBG_LOG("BC_TUI_CMD_UPDATE_SCREEN");
			DBG_LOG("getPreState() : %x", getPreState());
			DBG_LOG("getState() : %x", getState());
			DBG_LOG("getScreenState() : %x", getScreenState());
			if ((getPreState() & SESSION_ON_TUI_STATE) != SESSION_ON_TUI_STATE) {
				switch (getScreenState()) {
				case BACKUP_SCREEN_STATE:
				case RECOVERY_SCREEN_STATE:
					ret = initBackUpScreen(wrappedTransactionSo, wrappedTransactionSoLength);
					break;
				case RESTORE_SCREEN_STATE:
					ret = initRestoreScreen();
					break;
				case RESTORE_SCREEN_TEXT_LINK_STATE:
					ret = initRestoreScreenTextLink();
					break;
				case CONFIRM_SCREEN_STATE:
					ret = initConfirmScreen(wrappedTransactionSo, wrappedTransactionSoLength);
					break;
				default:
					break;
				}
			} else {
				changeState(SESSION_ON_TUI_STATE);
				if (getPreScreenState() != NONE_SCREEN_STATE && getPreScreenState() != getScreenState()) {
					if (isExsitBackground()) {
						ret = showBackground();
						if (ret == SUCCESS_BC_TUI) {
							if (getScreenState() == BACKUP_SCREEN_QUIZ_STATE) {
								redrawScreen(BACKUP_SCREEN_QUIZ_STATE);
							} else if (getScreenState() == BACKUP_SCREEN_STATE) {
								redrawScreen(BACKUP_SCREEN_STATE);
							} else {
								drawControlNode();
							}
						} else if (ret == ERROR_BC_TUI_FAILED_DRAW_IMAGE) {
							changeState(INVALID_IMAGE_TUI_STATE);
						} else if (ret == ERROR_BC_TUI_NO_SESSION) {
							changeState(CANCELLED_TUI_STATE);
						} else {
							changeState(FAILED_TUI_STATE);
						}
					}
				}
			}
			resumeScreen();
			break;

		case SPAY_TUI_CMD_CHECK_RET_CODE:
			//it is come from tlc to return result for start_secure_touch of qsee.
			if (getState() == SESSION_ON_TUI_STATE) { // sw debt.
				changeState(CANCELLED_TUI_STATE);
			}
			break;

		case SPAY_TUI_CMD_CLOSE: // qsee
			DBG_LOG("qwerty SPAY_TUI_CMD_CLOSE");
			if (getState() != OK_TUI_STATE && getState() != FAILED_TUI_STATE) {
				changeState(CANCELLED_TUI_STATE);
			}
			break;



		default:
			TTY_LOG("%s has no command : %x", LOG_TAG, commandId);
	}

	//process touch event(teegris). thread holding.
	if (getState() == SESSION_ON_TUI_STATE)
		createTouchThread(commandId);

	ret = processState(getState());

	respmsg->payload.rsp.data.commonRsp.retCode = getState();	// all response has retCode
	respmsg->spayhdr.header.status = 0;
	respmsg->spayhdr.header.id = RSP_ID(commandId);
	respmsg->spayhdr.header.len = getResponseLength(commandId);

	TTY_LOG("%s process_cmd retCode:0x%x, ret:0x%x, id:0x%x", LOG_TAG, respmsg->payload.rsp.data.commonRsp.retCode, ret, respmsg->spayhdr.header.id);

#ifdef TBASE_API_LEVEL
	// Set cmd ID to TUI driver event. This is necessary since driver event is dispatched
	// to trustlet as if a TLC command. The difference is that real TLC cmds always set cmd ID.
	if (commandId != SPAY_TUI_CMD_DRV_QTY)
      sendmsg->spayhdr.header.id = SPAY_TUI_CMD_DRV_QTY;
#endif

	return ret;
}

uint32_t excuteTouchCallBack(uint32_t x_out, uint32_t y_out, uint32_t type_out) {
	rotateCoodinate(&x_out, &y_out, getRotationType());
	uint32_t ret = doTouchEvent(x_out, y_out, type_out);
	showFrameBuffer();
	return ret;
}

uint32_t initTuiScreen() {
	DBG_LOG("initTuiScreen");
	uint32_t ret = SUCCESS_BC_TUI;
	registerTuiTouchCallback(&excuteTouchCallBack);

	uint8_t* bgImage = NULL;
	uint32_t bgImageSize = 0;
	uint32_t bgImageWidth = 0;
	uint32_t bgImageHeight = 0;
	if (isExsitBackground() == true) {
		DBG_LOG("Get exist background");
		bgImage = getBackground(&bgImageSize, &bgImageWidth, &bgImageHeight);
		if (validatePngResource(bgImage, bgImageSize, bgImageWidth, bgImageHeight) == false) {
			DBG_LOG("Background validation fail %d:%d,%d", bgImageSize, bgImageWidth, bgImageHeight);
			bgImage = NULL;
			bgImageSize = 0;
		}
	}
	ret = startTuiSession(bgImage, bgImageSize);
	if (ret == TUI_SUCCESS) {
		changeState(SESSION_ON_TUI_STATE);
	} else { // no_session retry??
		changeState(SESSION_OFF_TUI_STATE);
	}
	return ret;
}

uint32_t initBackUpScreen(uint8_t* soBuffer, uint32_t soBufferLength) {
	uint32_t ret = SUCCESS_BC_TUI;

	uint8_t sourceTextBuffer[BC_TUI_TRANSACTION_SO_BUFFER_SIZE] = { 0, };
	if (soBufferLength > BC_TUI_TRANSACTION_SO_BUFFER_SIZE)
		return ERROR_BC_TUI;
	memcpy(sourceTextBuffer, soBuffer, soBufferLength);

	ret = initTuiScreen();
	if (ret == TUI_SUCCESS) {
		uint8_t unwrappedData[sizeof(backupScreen_t)];
		uint32_t dataSize = sizeof(backupScreen_t);
		ret = TZ_unwrap_session_data((uint8_t *)BC_CORE_APP_NAME, sizeof(BC_CORE_APP_NAME), sourceTextBuffer, soBufferLength, unwrappedData, &dataSize);

		if (ret != TZ_API_OK) {
			TTY_LOG("%s TZ_unwrap_session_data failed: 0x%x", LOG_TAG, ret);
			changeState(FAILED_TUI_STATE);
			return ret;
		}

		ret = compareSoSource(soBuffer, soBufferLength, (uint8_t *)AUTH_SO_SRC_BC_CORE_UUID, sizeof(AUTH_SO_SRC_BC_CORE_UUID) - 1);
		if (ret == false) {
			TTY_LOG("%s Cannot verify the source of wrapped_keyinformation", LOG_TAG);
			changeState(FAILED_TUI_STATE);
			return ret;
		}

		ret = startBackupScreen(unwrappedData);
		if (ret == TUI_SUCCESS) {
			showFrameBuffer();
		} else if (ret == ERROR_BC_TUI_FAILED_DRAW_IMAGE) {
			changeState(INVALID_IMAGE_TUI_STATE);
		} else {
			changeState(FAILED_TUI_STATE);
		}
	}
	return ret;
}

uint32_t initRestoreScreen() {
	uint32_t ret = SUCCESS_BC_TUI;

	ret = initTuiScreen();
	if (ret == TUI_SUCCESS) {
		ret = startRestoreScreen();
		if (ret == TUI_SUCCESS) {
			showFrameBuffer();
		} else if (ret == ERROR_BC_TUI_FAILED_DRAW_IMAGE) {
			changeState(INVALID_IMAGE_TUI_STATE);
		} else {
			changeState(FAILED_TUI_STATE);
		}
	}
	return ret;
}

uint32_t initRestoreScreenTextLink() {
	uint32_t ret = SUCCESS_BC_TUI;
	initTuiScreen();
	ret = initTuiBackground();
	if(ret == TUI_SUCCESS){
		changeScreenState(RESTORE_SCREEN_STATE);
		drawControlNode();
	}
	else {
		changeState(FAILED_TUI_STATE);
	}
	return ret;
}

uint32_t initConfirmScreen(uint8_t* soBuffer, uint32_t soBufferLength) {
	uint32_t ret = SUCCESS_BC_TUI;
	uint8_t transactionTextBuffer[BC_TUI_TRANSACTION_SO_BUFFER_SIZE] = { 0, };

	uint8_t sourceTransactionTextBuffer[BC_TUI_TRANSACTION_SO_BUFFER_SIZE] = { 0, };
	if (soBufferLength > BC_TUI_TRANSACTION_SO_BUFFER_SIZE)
		return ERROR_BC_TUI;
	memcpy(sourceTransactionTextBuffer, soBuffer, soBufferLength);
	DBG_LOG("%s tc str wrapped : %s", LOG_TAG, soBuffer);

	ret = initTuiScreen();
	if (ret == TUI_SUCCESS) {
		memset(unwrappedTransactionSo, 0, sizeof(unwrappedTransactionSo));
		unwrappedTransactionSoLength = sizeof(unwrappedTransactionSo);

		ret = TZ_unwrap_session_data((uint8_t *)BC_CORE_APP_NAME, sizeof(BC_CORE_APP_NAME), sourceTransactionTextBuffer, soBufferLength, unwrappedTransactionSo, &unwrappedTransactionSoLength);

		DBG_LOG("%s in confirm unwrap === ", LOG_TAG);
		DBG_DUMP(unwrappedTransactionSo, unwrappedTransactionSoLength);

		if (ret != TZ_API_OK) {
			TTY_LOG("%s TZ_unwrap_session_data failed: 0x%x", LOG_TAG, ret);
			changeState(FAILED_TUI_STATE);
			return ERROR_BC_TUI;
		}
		if (compareSoSource(soBuffer, soBufferLength, (uint8_t *)AUTH_SO_SRC_BC_CORE_UUID, sizeof(AUTH_SO_SRC_BC_CORE_UUID) - 1) == false) {
			TTY_LOG("%s Cannot verify the source of wrapped_keyinformation", LOG_TAG);
			changeState(FAILED_TUI_STATE);
			return ERROR_BC_TUI;
		}
		if (sizeof(transactionTextBuffer) < unwrappedTransactionSoLength) {
			TTY_LOG("%s so buffer size < so", LOG_TAG);
			changeState(FAILED_TUI_STATE);
			return ERROR_BC_TUI;
		}
		strcpy((char*)transactionTextBuffer, (char*)unwrappedTransactionSo); // teegris does not support strlpcy()

		ret = startConfirmScreen(transactionTextBuffer);
		if (ret == TUI_SUCCESS) {
			showFrameBuffer();
		} else if (ret == ERROR_BC_TUI_FAILED_DRAW_IMAGE) {
			changeState(INVALID_IMAGE_TUI_STATE);
		} else {
			changeState(FAILED_TUI_STATE);
		}
	}
	return ret;
}

uint32_t cmdGetSo(uint8_t* soBuffer, uint32_t *soBufferLength) {
	uint32_t ret = SUCCESS_BC_TUI;

	DBG_LOG("%s getso len : %d, soBufferLength : %d", LOG_TAG, unwrappedTransactionSoLength, *soBufferLength);
	DBG_DUMP(unwrappedTransactionSo, unwrappedTransactionSoLength);

	if (BC_TUI_TRANSACTION_SO_BUFFER_SIZE < unwrappedTransactionSoLength) {
		TTY_LOG("%s so buffer size < so", LOG_TAG);
		changeState(FAILED_TUI_STATE);
		return ERROR_BC_TUI;
	}

	ret = TZ_wrap_session_data((uint8_t*)BC_CORE_APP_NAME, BC_CORE_APP_NAME_LEN,
		(uint8_t*)unwrappedTransactionSo, unwrappedTransactionSoLength, (uint8_t*)soBuffer, (uint32_t*)soBufferLength);

	if (ret != SUCCESS_BC_TUI) {
		TTY_LOG("%s failed wrap so!", LOG_TAG);
		changeState(FAILED_TUI_STATE);
		TZ_bzero(unwrappedTransactionSo, sizeof(unwrappedTransactionSo));
		return ERROR_BC_TUI;
	}

	TTY_LOG("%s tr so len : %d", LOG_TAG, *soBufferLength);
	DBG_DUMP(soBuffer, *soBufferLength);

	TZ_bzero(unwrappedTransactionSo, sizeof(unwrappedTransactionSo));

	changeState(GET_TRANSACTION_SO_STATE);

	return ret;
}

uint32_t getResponseLength(uint32_t commandId) {
	uint32_t length;
	switch (commandId) {
		case BC_TUI_CMD_GET_SO:
			length = sizeof(bcTransactionSoRsp_t);
			break;
		default:
			length = sizeof(commonRsp_t);
			break;
	}
	return length;
}

uint32_t processState(uint32_t state) {
	uint32_t ret = TUI_SUCCESS;
	TTY_LOG("%s getState : 0x%x", LOG_TAG, (uint32_t)state);

	uint8_t* soData;
	uint32_t soDataLen;

	switch (state) {
		case SESSION_OFF_TUI_STATE:
		case OK_TUI_STATE:
		case CANCELLED_TUI_STATE:
		case FAILED_TUI_STATE:
		case INVALID_IMAGE_TUI_STATE:
			setPreState(getState());
			ret |= getNotifyMask(true); // 0x29000000
			deleteAllControl();
			closeTuiSession();
			break;

		case TEXT_LINK_TUI_STATE:
			setPreState(getState());
			ret |= getNotifyMask(true); // 0x29000000
			closeTuiSession();
			break;

		case WRONG_FP_TUI_STATE:
		case TRY_AGAIN_FP_TUI_STATE:
			if (getState() != getPreState()) {
				setPreState(getState());
				ret |= getNotifyMask(true); // 0x29000000
			}
			else {
				ret |= getNotifyMask(false); // 0x2A000000
			}
			break;

		case SESSION_ON_TUI_STATE:
		case NONE_TUI_STATE:
			// does not send rsp to tlc
			setPreState(getState());
			ret |= getNotifyMask(false); // 0x2A000000
			break;

		case CONFIRMED_TUI_STATE:
			changeState(OK_TUI_STATE);
			ret |= getNotifyMask(true); // 0x29000000
			deleteAllControl();
			closeTuiSession();
			break;

		case RESTORED_TUI_STATE:
			memset(unwrappedTransactionSo, 0, sizeof(unwrappedTransactionSo));
			unwrappedTransactionSoLength = sizeof(unwrappedTransactionSo);

			soData = getOutputSoData(&soDataLen);

			memcpy(unwrappedTransactionSo, soData, soDataLen);
			unwrappedTransactionSoLength = soDataLen;

			changeState(OK_TUI_STATE);
			ret |= getNotifyMask(true); // 0x29000000
			deleteAllControl();
			closeTuiSession();
			break;

		case GET_TRANSACTION_SO_STATE:
			changeState(OK_TUI_STATE);
			ret |= getNotifyMask(true); // 0x29000000
			deleteAllControl();
			break;

		case SETTING_BACKGROUND_TUI_STATE:
		case SETTING_BACKGROUND_SESSION_ON_TUI_STATE:
		case SETTING_TOUCHABLE_VIEW_TUI_STATE:
		case SETTING_TOUCHABLE_VIEW_SESSION_ON_TUI_STATE:
		case SETTING_DRAWABLE_VIEW_TUI_STATE:
		case SETTING_DRAWABLE_VIEW_SESSION_ON_TUI_STATE:
		case SETTING_BACKUP_QUIZ_ORDER_TUI_STATE:
		case SETTING_BACKUP_QUIZ_ORDER_SESSION_ON_TUI_STATE:
			changeState(OK_TUI_STATE);
			ret |= getNotifyMask(true); // 0x29000000
			break;

		case REQUEST_TEXT_RESTORE_WRONG_INPUT_TUI_STATE:
		case UPDATE_SCREEN_BACKUP_TUI_STATE:
		case UPDATE_SCREEN_BACKUP_QUIZ_TUI_STATE:
		case UPDATE_SCREEN_RECOVERY_TUI_STATE:
		case UPDATE_SCREEN_RESTORE_TUI_STATE:
		case UPDATE_SCREEN_CONFIRM_TUI_STATE:
		case UPDATE_SCREEN_POPUP_BACKUP_EXIT_TUI_STATE:
		case UPDATE_SCREEN_POPUP_RESTORE_EXIT_TUI_STATE:
		case UPDATE_SCREEN_POPUP_RESTORE_FAILED_CHECKSUM_TUI_STATE:
		case REQUEST_TEXT_BACKUP_FIRST_WRONG_INPUT_TUI_STATE:
		case REQUEST_TEXT_BACKUP_SECOND_WRONG_INPUT_TUI_STATE:
		case REQUEST_TEXT_BACKUP_THIRD_WRONG_INPUT_TUI_STATE:
			ret |= getNotifyMask(true); // 0x29000000
			break;

		default:
			TTY_LOG("%s cannot catch state : 0x%x, ret=%d", LOG_TAG, (uint32_t)getState(), ret);
			deleteAllControl();
			ret = FAILED_TUI_STATE;
			ret |= getNotifyMask(true);
			break;
	}

	return ret;
}

uint32_t resumeScreen() {
	clearTouchEvent();
	releaseAllControl();
	return 0;
}
