#include "TuiPinpadScreen.h"

uint8_t *resource[57];
uint32_t sizes[57];

#define PINPAD_STAR_SIZE	15
#define CHECK_INT_OVERFLOW(a, b) \
	((uint32_t)a + (uint32_t)b < (uint32_t)a || (uint32_t)a + (uint32_t)b < (uint32_t)b)
//extern preference_t g_preference; -> defined in process_cmd_pinpad.c of bc_tui
preference_t g_preference = {0, 0};

loadable_img_t g_loadable_img[RES_END - RES_BACKGROUND] = {0};
uint32_t idx_pinpad_end = IDX_PINPAD_CORRECT;
uint8_t g_pin[PIN_SIZE];
uint32_t g_pin_length = 0;
uint8_t g_pin_verify[PIN_SIZE];
uint32_t g_pin_verify_len = 0;
uint8_t g_min_pin_len = US_PIN_SIZE;
uint8_t g_pin_old[PIN_SIZE];    // existing pin
uint32_t g_pin_old_len = 0;
coordinate_t pin_coordinate[PIN_SIZE];
// the (x,y) for each star cache buffer. (optimization, only x needs to be an array. All y is the same)
uint8_t g_current_button;
uint64_t backspace_press_start;
uint8_t g_close_tui_after_verify;
uint64_t tui_verify_timestamp = 0;
bool g_display_normal_pinbox = true;
bool g_cancel_button_enabled = false;

uint8_t *gBgImage = NULL;
uint32_t gBgImageSize = 0;

static sPinSoftKey pinSoftKey;
static uint32_t currentPinScreenId = 0;

bool g_navigation_gesture = false;

extern bool g_certificate_verified;

void clearBackgroundResource() {
    if (gBgImage != NULL) {
        TZ_free(gBgImage);
        gBgImage = NULL;
    }
    gBgImageSize = 0;
}

uint32_t saveBackgroundResource(uint8_t* buf, uint32_t buflen) {
    clearBackgroundResource();

    TUI_LOG_DEBUG("%s buflen=%d", __func__, buflen);

    gBgImage = (uint8_t*)TZ_malloc(buflen);
    gBgImageSize = buflen;

    if (gBgImage == NULL) {
        TUI_LOG_DEBUG("%s allocation failed", __func__);
        return TUI_STATUS_FAIL;
    }
    memcpy(gBgImage, buf, buflen);

    return TUI_STATUS_SUCCESS;
}

uint32_t byteToDec(uint8_t *buf, uint32_t *offset) {
    uint32_t val;

    val = (buf[*offset] << 8) + buf[*offset + 1];
    *offset += 2;

    val = (val << 16) + (buf[*offset] << 8) + buf[*offset + 1];
    *offset += 2;

    return val;
}

tui_return_code_t setPinBoxImages(setPinBoxCmd_t *pinbox_resource) {
    uint8_t count = 0;
    uint8_t *buf = NULL;
    uint32_t total = 0;
    uint32_t offset = 0;
    uint32_t idx_start = 0;
    uint32_t coordinate_size = 0;
    uint32_t xLeft, yTop;
    uint32_t xRight, yBottom;
    uint32_t type = 0;
    sPinBoxLayout_t *pinbox_layout = NULL;
    sPinDotLayout_t *pindot_layout = NULL;
    tui_return_code_t ret = TUI_STATUS_SUCCESS;

    g_min_pin_len = pinbox_resource->number;

    type = pinbox_resource->type;
    buf = pinbox_resource->buf;
    coordinate_size = pinbox_resource->number;
    if(type == RESOURCE_PINBOX_RESET) {
        for (int i = IDX_NORMAL_PINBOX; i < IDX_BLANK_DOT + 1; i++) {
            if(resource[i] != NULL) {
                TZ_free(resource[i]);
                resource[i] = NULL;
            }
        }

        return TUI_STATUS_SUCCESS;
    } else if (type == RESOURCE_TYPE_PINBOX) {
        idx_start = IDX_NORMAL_PINBOX;
    } else if (type == RESOURCE_TYPE_PINDOT) {
        idx_start = IDX_NORMAL_DOT;
    } else {
        TUI_LOG("setPinBoxImages error, type=%d, count=%d", type, count);
        ret = TUI_SEND_PINBOX_IMAGES_FAILED;

        return ret;
    }

    total = byteToDec(buf, &offset);
    //offset = 4;
    count = buf[offset++];
    TUI_LOG("%s count=%d, idx_start=%d", __func__, count, idx_start);

	// It would be better to define a macro than using the numeric value directly. Also use the same constant in the buffer allocations.
	if(idx_start + count > 57) {
		TUI_LOG("setPinBoxImages error, attempt to access outside buffer");
		ret = TUI_SEND_PINBOX_IMAGES_FAILED;
        return ret;
	}
	
    for (int i = idx_start; i < idx_start + count; i++) {
		if (offset + sizeof(uint32_t) > RESOURCE_BUFFER_SIZE) {
			TUI_LOG("setPinBoxImages error, attempt to access outside buffer");
			ret = TUI_SEND_PINBOX_IMAGES_FAILED;
        	return ret;
		}
        sizes[i] = byteToDec(buf, &offset);

        if(resource[i] != NULL) {
            TZ_free(resource[i]);
        }
		//TODO: Is there any reasonable size to prevent unlimited memory consumption?
        if (sizes[i] != 0) {
            resource[i] = TZ_malloc(sizes[i]);
			if (resource[i] == NULL) {
				TUI_LOG("setPinBoxImages error, resource allocation error");
				ret = TUI_SEND_PINBOX_IMAGES_FAILED;
        		return ret;
			}

			if(offset + sizes[i] > RESOURCE_BUFFER_SIZE) {
				TUI_LOG("setPinBoxImages error, attempt to read resource which is bigger than the input itself.");
				ret = TUI_SEND_PINBOX_IMAGES_FAILED;
        		return ret;
			}
            memcpy(resource[i], buf + offset, sizes[i]);
            offset += sizes[i];
        }
    }

	// SRR-23459
	if (coordinate_size > PIN_MAX_SIZE) {
		TUI_LOG("setPinBoxImages error, pin size %d bigger than allowed max %d", coordinate_size, PIN_MAX_SIZE);
        	ret = TUI_SEND_PINBOX_IMAGES_FAILED;
        	return ret;
	}

    for (int i = 0; i < coordinate_size; i++) {
		if (offset + 2 * sizeof(uint32_t) > RESOURCE_BUFFER_SIZE) {
			TUI_LOG("setPinBoxImages error, attempt to access outside buffer");
			ret = TUI_SEND_PINBOX_IMAGES_FAILED;
        	return ret;
		}
		
		// TODO: Aren't there any reasonable limits for xLeft and yTop?
        xLeft = byteToDec(buf, &offset);
        yTop = byteToDec(buf, &offset);

        if (type == RESOURCE_TYPE_PINBOX) {
            pinbox_layout = (sPinBoxLayout_t *)(&g_pinpad_layout.pinbox_array[i]);
            pinbox_layout->xLeft = xLeft;
            pinbox_layout->yTop = yTop;
        } else if (type == RESOURCE_TYPE_PINDOT) {
            pindot_layout = (sPinDotLayout_t *)(&g_pinpad_layout.pindot_array[i]);
            pindot_layout->xLeft = xLeft;
            pindot_layout->yTop = yTop;
        }
    }

    return ret;
}

#define COUNT_PINPAD_IMAGES (IDX_PINPAD_VALIDATE_PRESSED - IDX_PINPAD_0 + 1)
#define COUNT_SOFTKEY_BACK 2 // Softkey back released + pressed
#define FREE_IMAGES 0xFF
tui_return_code_t setPinPadImages(screenResourceArray_t *pinpad_resource) {
    uint8_t count = 0;
    uint32_t total = 0;
    uint32_t offset = 0;
    uint32_t idx_start = 0;
    uint32_t coordinate_size = 0;
    uint32_t xLeft, yTop;
    uint32_t xRight, yBottom;
    pinpad_resource_type_t type = pinpad_resource->type;
    uint8_t *buf = pinpad_resource->buf;
    sPinPadKey_t *key_layout = NULL;
    tui_return_code_t ret = TUI_STATUS_SUCCESS;

    total = byteToDec(buf, &offset);
    //offset = 4;
    coordinate_size = buf[offset] / 2;
    TUI_LOG("%s image count=%d, idx_start=%d", __func__, buf[offset], idx_start);
    offset++;

    if(type == RESOURCE_PINPAD_RESET) {
        for (int i = 0; i < COUNT_PINPAD_IMAGES; i++) {
            if(resource[i] != NULL) {
                TZ_free(resource[i]);
                resource[i] = NULL;
            }
        }

        return TUI_STATUS_SUCCESS;
    } else if (type == RESOURCE_TYPE_PINPAD) {
        idx_start = IDX_PINPAD_0;
        count = COUNT_PINPAD_IMAGES;
        if (coordinate_size == IDX_PINPAD_CORRECT + 1) {
            TUI_LOG("received pinpad images without OK button. pinpad size = %d", coordinate_size);
            idx_pinpad_end = IDX_PINPAD_CORRECT;
        } else if (coordinate_size == IDX_PINPAD_VALIDATE + 1) {
            TUI_LOG("received pinpad images with OK button. pinpad size = %d", coordinate_size);
            idx_pinpad_end = IDX_PINPAD_VALIDATE;
        } else {
            TUI_LOG("pinpad size invalid!!, %d", coordinate_size);
        }
    } else if (type == RESOURCE_TYPE_SOFTKEY) {
        idx_start = IDX_PINPAD_SOFTKEY_BACK;
        count = COUNT_SOFTKEY_BACK;
    } else {
        TUI_LOG("setPinPadImages error, type=%d ", type);
        ret = TUI_SEND_PINPAD_IMAGES_FAILED;
        return ret;
    }

	// It would be better to define a macro than using the numeric value directly. Also use the same constant in the buffer allocations.
	if(idx_start + count > 57) {
		TUI_LOG("setPinBoxImages error, attempt to access outside buffer");
		ret = TUI_SEND_PINPAD_IMAGES_FAILED;
        return ret;
	}
	
    for (int i = idx_start; i < idx_start + count; i++) {
        // If ok btn images isn't included in buf, skip the index for validate btn
        if (i == IDX_PINPAD_VALIDATE || i == IDX_PINPAD_VALIDATE_PRESSED) {
            if (idx_pinpad_end == IDX_PINPAD_CORRECT) continue;
        }

		if (offset + sizeof(uint32_t) > RESOURCE_BUFFER_SIZE) {
			TUI_LOG("setPinBoxImages error, attempt to access outside buffer");
			ret = TUI_SEND_PINPAD_IMAGES_FAILED;
        	return ret;
		}
        sizes[i] = byteToDec(buf, &offset);

        if(resource[i] != NULL) {
            TZ_free(resource[i]);
        }

        if (sizes[i] != 0) {
            resource[i] = TZ_malloc(sizes[i]);
			if (resource[i] == NULL) {
				TUI_LOG("setPinBoxImages error, resource allocation error");
				ret = TUI_SEND_PINPAD_IMAGES_FAILED;
        		return ret;
			}

			if(offset + sizes[i] > RESOURCE_BUFFER_SIZE) {
				TUI_LOG("setPinBoxImages error, attempt to read resource which is bigger than the input itself.");
				ret = TUI_SEND_PINPAD_IMAGES_FAILED;
        		return ret;
			}

            memcpy(resource[i], buf + offset, sizes[i]);
            offset += sizes[i];
        }
    }

    for (int i = idx_start; i < idx_start + coordinate_size; i++) {
		if (offset + 4 * sizeof(uint32_t) > RESOURCE_BUFFER_SIZE) {
			TUI_LOG("setPinBoxImages error, attempt to access outside buffer");
			ret = TUI_SEND_PINPAD_IMAGES_FAILED;
        	return ret;
		}

        xLeft = byteToDec(buf, &offset);
        yTop = byteToDec(buf, &offset);
        xRight = byteToDec(buf, &offset);
        yBottom = byteToDec(buf, &offset);

        if (type == RESOURCE_TYPE_PINPAD) {
            if (i < 0 || i >= (sizeof(g_pinpad_layout.buttons_array) / sizeof(sPinPadKey_t))) {
                TUI_LOG("%s index error, out of bound. i=%d", __func__, i);
                ret = TUI_SEND_PINPAD_IMAGES_FAILED;
                return ret;
            }
            key_layout = (sPinPadKey_t *)(&g_pinpad_layout.buttons_array[i]);
        } else if (type == RESOURCE_TYPE_SOFTKEY) {
            key_layout = (sPinPadKey_t *)(&g_softkey[0]);
        }
        key_layout->xLeft = xLeft;
        key_layout->yTop = yTop;
        key_layout->xRight = xRight;
        key_layout->yBottom = yBottom;
        if (i == IDX_PINPAD_CORRECT || i == IDX_PINPAD_CORRECT_PRESSED) {
            key_layout->val = PAD_CORRECT_VAL;
            key_layout->type = PAD_CORRECT;
        } else if (i == IDX_PINPAD_VALIDATE || i == IDX_PINPAD_VALIDATE_PRESSED) {
            key_layout->val = PAD_VALIDATE_VAL;
            key_layout->type = PAD_VALIDATE;
        } else if (i == IDX_PINPAD_SOFTKEY_BACK || i == IDX_PINPAD_SOFTKEY_BACK_PRESSED) {
            key_layout->val = PAD_SOFTKEY_BACK_VAL;
            key_layout->type = PAD_SOFTKEY_BACK;
        } else {
            key_layout->val = i;
            key_layout->type = PAD_NUM;
        }
    }
    key_layout = (sPinPadKey_t *)(&g_pinpad_layout.buttons_array[idx_pinpad_end + 1]); // NO_KEY
    key_layout->xLeft = 0;
    key_layout->yTop = 0;
    key_layout->val = PAD_NOKEY_VAL;
    key_layout->type = NOKEY;
    pinSoftKey.softKey = g_softkey[0];

    if (total != offset - 4) {
        TUI_LOG("total size %d is not matched with written bytes %d", total, offset - 4);
    }

    return ret;
}

/** getTouchedKey() - Translate x,y coordinates into key
 *
 * @param x                 x coordinate of touch event
 * @param y                 y coordinate of touch event
 * @param[out] touched_key  key structure of touched key
 *
 * Loops over the layout structure to find the pressed key.
 * If found, copies the key description into touched_key.
 * Otherwise, <NULL> key is returned.
 *
 * @return  true upon success or false upon not found
 */
uint32_t getTouchedKey(uint32_t x, uint32_t y,
		       sPinPadKey_t *const touched_key) {
	const sPinPadKey_t *key;
	uint32_t ret = 0;
	sLayout_t *layout = (sLayout_t *) &g_pinpad_layout;
	*touched_key = layout->buttons_array[idx_pinpad_end + 1]; // NO_KEY
	// if the coordinates are not located in pinpad button, NO_KEY will be returned.

	key = &pinSoftKey.softKey;

	TUI_LOG_DEBUG("%s softkey: Compare (%d,%d) and (xLeft=%d yTop=%d xRight=%d yBottom=%d) isBHR=%d",
		      __func__, x, y,
		      key->xLeft, key->yTop, key->xRight, key->yBottom, g_preference.isBHR);
	if (x >= key->xLeft && x <= key->xRight &&
	    y <= key->yBottom && y >= key->yTop) {
		TUI_LOG_DEBUG("%s softkey: memcpy key -> touched_key", __func__);
		memcpy(touched_key, key, sizeof(sPinPadKey_t));
		return 0;
	}

	for (int i = IDX_PINPAD_0; i <= idx_pinpad_end; i++) {
		key = &layout->buttons_array[i];
		TUI_LOG_DEBUG("%s Compare (%d,%d) and (xLeft=%d yTop=%d xRight=%d yBottom=%d)",
			      __func__, x, y, key->xLeft, key->yTop, key->xRight, key->yBottom);
		if (x >= key->xLeft && x <= key->xRight &&
		    y <= key->yBottom && y >= key->yTop) {
			TUI_LOG_DEBUG("%s memcpy key -> touched_key", __func__);
			memcpy(touched_key, key, sizeof(sPinPadKey_t));
			break;
			//return true;
		}
	}

	return ret;
}

uint32_t drawPinpadImage(
			 uint32_t id,
			 uint32_t x,
			 uint32_t y
			) {
	uint8_t *png_buffer;
	uint32_t png_buffer_len;

	TUI_LOG_DEBUG("%s drawPinpadImage +++ id = %d", __func__, id);
	TUI_LOG_DEBUG("%s x =%d, y = %d", __func__, x, y);

	if (id < (sizeof(resource) / sizeof(resource[0]))) {
		png_buffer = resource[id];
		png_buffer_len = sizes[id];
	} else if (IDX_PINPAD_SOFTKEY_BACK == id) {
		png_buffer = pinSoftKey.originResource;
		png_buffer_len = pinSoftKey.originResourceSize;
		if (g_navigation_gesture) {
			png_buffer = pinSoftKey.extraResource;
			png_buffer_len = pinSoftKey.extraResourceSize;
		}
	} else if (IDX_PINPAD_SOFTKEY_BACK_PRESSED == id) {
		png_buffer = pinSoftKey.eventResource;
		png_buffer_len = pinSoftKey.eventResourceSize;
	} else {
		TUI_LOG_DEBUG("%s no image resource for %d", __func__, id);
		return TIMA_ERROR_TUI_NO_RESOURCE;
	}

	TUI_LOG_DEBUG("%s show image id = %d", __func__, id);

	if (png_buffer == NULL){
		TUI_LOG("buffer is null");
		return TIMA_ERROR_TUI_NO_RESOURCE;
	}

	uint32_t width = 0;
	uint32_t height = 0;
	uint32_t ret;
	ret = drawImage(x, y, png_buffer, png_buffer_len);
	TUI_LOG_DEBUG("%s drawPinpadImage ---", __func__);
	return ret;
}

/** add_pin() - Display PIN dot at index
 *
 * @param keynum    Digit that was entered
 *
 * @return  TLAPI_OK upon success or specific error
 */
uint32_t addPin(uint8_t keynum) {
	uint32_t x, y;
	uint32_t ret;
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();

	TUI_LOG_DEBUG("%s addPin +++", __func__);
	TUI_LOG_DEBUG("%s width = %d, height = %d", __func__, screenWidth, screenHeight);
	TUI_LOG_DEBUG("%s g_min_pin_len = %d, g_pinbox_width = %d g_pinbox_space = %d", __func__,
		      g_min_pin_len, g_pinbox_width, g_pinbox_space);
	uint32_t len = (screenWidth - g_min_pin_len * g_pinbox_width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;
	TUI_LOG_DEBUG("%s len = %d", __func__, len);

	x = g_pinpad_layout.pindot_array[g_pin_length].xLeft;
	y = g_pinpad_layout.pindot_array[g_pin_length].yTop;
	pin_coordinate[g_pin_length].x = x;
	pin_coordinate[g_pin_length].y = y;

	++g_pin_length;

	if (!g_display_normal_pinbox) {
		// display error pin dot if the png is available
		ret = drawPinpadImage(IDX_ERROR_DOT, x, y);
		if (ret) {
			return drawPinpadImage(IDX_NORMAL_DOT, x, y);
		} else {
			return 0;
		}
	} else {
		TUI_LOG_DEBUG("%s addPin --- (normal pinbox)", __func__);
		return drawPinpadImage(IDX_NORMAL_DOT, x, y);
	}
}

/** remove_pin() - Display blank image at index
 *
 * @return  TIMA_SUCCESS upon success or specific error
 */
uint32_t removePin() {
	--g_pin_length;
	return drawPinpadImage(IDX_BLANK_DOT, pin_coordinate[g_pin_length].x,
			       pin_coordinate[g_pin_length].y);
}
/**
*/
uint32_t removeAllPin() {
	uint32_t ret = 0;
	while (g_pin_length > 0) {
		ret = removePin();
		if (ret)
			break;
	}
	return ret;
}

/** setButtonImage() - set Image of one pinpad button
 *
 * @param touched_key    Button that was touched
 * @param pressed        Pressed or released
 *
 * Prepares the tlApiTuiSetImage() call to show the negative picture of the button.
 *
 * @return  TLAPI_OK upon success or specific error
 */
uint32_t setButtonImage(sPinPadKey_t key, bool pressed) {
	uint8_t provIdx;

	if (!g_certificate_verified) {
		TUI_LOG_DEBUG("%s %s: invalid certificate, display not updated.", __func__, __func__);
		return TIMA_ERROR_TUI_DISPLAY_ERROR;
	}

	if (key.val == PAD_SOFTKEY_BACK_VAL) {
		TUI_LOG_DEBUG("%s %s: PAD_SOFTKEY_BACK_VAL", __func__, __func__);
		provIdx = pressed ? IDX_PINPAD_SOFTKEY_BACK_PRESSED : IDX_PINPAD_SOFTKEY_BACK;
		TUI_LOG_DEBUG("%s %s: provIdx = %d", __func__, __func__, provIdx);
	} else {
		/* Calculate the provisionning index with the button value */
		TUI_LOG_DEBUG("%s %s: NUMBER KEY", __func__, __func__);
		provIdx = key.val + IDX_PINPAD_0;
		TUI_LOG_DEBUG("%s %s: key.val (%d) IDX_PINPAD_0 (%d)", __func__, __func__, key.val, IDX_PINPAD_0);
		TUI_LOG_DEBUG("%s %s: provIdx = %d", __func__, __func__, provIdx);
		if (pressed) {
			provIdx += IDX_DELTA_PRESSED;
		}
		TUI_LOG_DEBUG("%s %s: IDX_DELTA_PRESSED = %d", __func__, __func__, IDX_DELTA_PRESSED);
		TUI_LOG_DEBUG("%s %s: provIdx = %d", __func__, __func__, provIdx);
	}

	TUI_LOG_DEBUG("%s %s: drawPinpadImage", __func__, __func__);
	return drawPinpadImage(provIdx, key.xLeft, key.yTop);
}

/** setReleasedButtonImage() - set Image of one pinpad button
 *
 * @param value    Value of the button to display
 *
 * Prepares the tlApiTuiSetImage() call to show the picture of the released button.
 *
 * @return  TLAPI_OK upon success or specific error
 */
uint32_t setReleasedButtonImage(uint8_t value) {
	const sPinPadKey_t *key;
	uint32_t ret = TIMA_SUCCESS;
	sLayout_t *layout = (sLayout_t *) &g_pinpad_layout;

	key = &pinSoftKey.softKey;
	TUI_LOG("key->val:%d value=%d", key->val, value);

	// handling softkey
	if (key->val == value) {
		TUI_LOG("soft key check: setButtonImage");
		ret = setButtonImage(*key, false);
		return ret;
	}

	// handling number key
	for (int i = IDX_PINPAD_0; i <= idx_pinpad_end; i++) {
		key = &layout->buttons_array[i];
		if (key->val == value) {
			TUI_LOG("button val:%d value=%d", key->val, value);
			ret = setButtonImage(*key, false);
			break;
		}
	}
	return ret;
}

uint32_t processKeyEvent(uint32_t x, uint32_t y, bool pressed) {
	uint32_t ret = TIMA_SUCCESS;
	sPinPadKey_t touched_key;
	uint32_t ret_st = getPinpadState();
	TUI_LOG_DEBUG("%s processKeyEvent start: getPinpadState() = 0x%x", __func__, getPinpadState());

	// get which key is applicable with this x,y coordinate
	getTouchedKey(x, y, &touched_key);

	TUI_LOG_DEBUG("%s touched_key.type = %d, touched_key.val = %d, pressed = %d",
		      __func__, touched_key.type, touched_key.val, pressed);

	if (touched_key.type == PAD_CANCEL) {
		return MPOS_TUI_ST_CANCELLED;
	}

	if (pressed) {
		/* Set the pressed button image. But do not set it continuously during long press */
		if (touched_key.val != g_current_button
		    && g_current_button != PAD_KEY_OUT_VAL) {
			TUI_LOG_DEBUG("g_current_button 0x%x PAD_NOKEY_VAL 0x%x",
				      g_current_button, PAD_NOKEY_VAL);
			if (g_current_button != PAD_NOKEY_VAL) {
				/* Reset the picture of the previous touched button */
				TUI_LOG_DEBUG("TUI: release %d", g_current_button);
				ret = setReleasedButtonImage(g_current_button);
				g_current_button = PAD_KEY_OUT_VAL;
			} else if (touched_key.type != NOKEY) {
				TUI_LOG_DEBUG("TUI: set %d", touched_key.val);
				ret = setButtonImage(touched_key, pressed);
				g_current_button = touched_key.val;
				if (touched_key.val == PAD_CORRECT_VAL) {
					// blocked    
					//backspace_press_start = getUptime();
					//
				}
			}
			showFrameBuffer();
		} else if (g_current_button == PAD_CORRECT_VAL &&
			   backspace_press_start > 0) {
			/* blocked
			   if (getUptime() - backspace_press_start >=
			   BACKSPACE_LONG_PRESS) {
			   TUI_LOG_DEBUG
			   ("TUI: backspace is pressed over 2 seconds");
			   backspace_press_start = 0;
			   removeAllPin();
			   showFrameBuffer();
			   }
			   */
		}

		/* Return: don't process data on pressing event */
		return (ret == 0 ? getPinpadState() : MPOS_TUI_ST_CANCELLED);
	} else {
		/* Reset the picture of the previous touched button */
		if (g_current_button < PAD_KEY_OUT_VAL) {
			ret = setReleasedButtonImage(g_current_button);
			TUI_LOG_DEBUG("TUI: l=[%d] release=[%d]", __LINE__, g_current_button);
			if (ret != TIMA_SUCCESS) {
				return MPOS_TUI_ST_CANCELLED;
			}
		} else {
			TUI_LOG_DEBUG("%s Release but no button to reset. Do nothing.", __func__);
			g_current_button = PAD_NOKEY_VAL;
			return getPinpadState();
		}

		// if the released button is not the pressed button, do nothing
		if (touched_key.val != g_current_button) {
			g_current_button = PAD_NOKEY_VAL;
			TUI_LOG_DEBUG("TUI: showFrameBuffer() call forcely");
			showFrameBuffer();  //PLM P170327-03217 issue fixed.
			return getPinpadState();
		}
		g_current_button = PAD_NOKEY_VAL;
	}

	switch (touched_key.type) {
	case PAD_NUM:
		if (!g_certificate_verified)
			break;

		if (g_pin_length < g_min_pin_len) {
			g_pin[g_pin_length] = touched_key.val;
			for (int i = 0; i <= g_pin_length; i++) {
				TUI_LOG_DEBUG("g_pin[%d] : %d", i, g_pin[i]);
			}
			ret = addPin(touched_key.val);
			if (ret != TIMA_SUCCESS) {
				ret_st = MPOS_TUI_ST_CANCELLED;
				break;
			}
			if (g_pin_length == g_min_pin_len) {
				ret_st = ((getPinpadState() & _MPOS_TUI_ST_REMOVE_START) |
					  _MPOS_TUI_ST_ENTER);    // switch from start to enter

    			// Send input pin data to tz_mpos_auth when all digit entered
				TUI_LOG("ta to ta comm. open tz_mpos_auth");

				// [SPRINT1] : send pin data to mpos_auth TA
				ret = TA_Communication_mpos_encrypt_pin(g_pin_length, g_pin);
				if (ret != MPOS_TATA_SUCCESS) {
					TUI_LOG("ta comm failed, %d!", ret);
				}
			}
		} else {
			////STORE_TA_ERROR("%s Ignoring entered key.", __func__);
		}
		break;
	case PAD_CORRECT:
		if (!g_certificate_verified)
			break;

		if (g_pin_length > 0 && g_pin_length < PIN_SIZE) {
			ret = removePin();
			if (ret != TIMA_SUCCESS) {
				ret_st = MPOS_TUI_ST_CANCELLED;
			}
		}
		break;
	case PAD_CANCEL:
		// Ignore cancel button
		//STORE_TA_ERROR("%s CANCEL", __func__);
		//ret_st = MPOS_TUI_ST_CANCELLED;
		break;

	case PAD_VALIDATE:
		//STORE_TA_ERROR("%s PIN entered", __func__);
		ret_st = ((getPinpadState() & _MPOS_TUI_ST_REMOVE_START) | _MPOS_TUI_ST_ENTER);
		TUI_LOG("ta to ta comm. open tz_mpos_auth");

		// [SPRINT1] : send pin data to mpos_auth TA
		ret = TA_Communication_mpos_encrypt_pin(g_pin_length, g_pin);
		if (ret != MPOS_TATA_SUCCESS) {
			TUI_LOG("ta comm failed, %d!", ret);
		}
		break;
	case PAD_SOFTKEY_BACK:
		setPinpadState(MPOS_TUI_ST_CANCELLED);
		ret_st = getPinpadState();
		TUI_LOG_DEBUG("%s PAD_SOFTKEY_BACK", __func__);
		break;
	default:
		break;
	} /* switch(key) */
	showFrameBuffer();

	return ret_st;
}

// Display all PIN buttons
uint32_t displayPinButtons() {
	uint32_t ret;
	uint32_t screenWidth = getScreenWidth();
	uint32_t width, height;

	sPinPadKey_t *key;
	sLayout_t *layout = (sLayout_t *) &g_pinpad_layout;

	//softkey background region
	// TODO : add softkey background resource
	//drawPinpadImage(IDX_SOFTKEY_BG, 0, SCREEN_HEIGHT - (48) * SCREEN_PIX_PER_DP);
	//softekey backkey
	setReleasedButtonImage(PAD_SOFTKEY_BACK_VAL);

	/*
	ret = drawPinpadImage(IDX_INAPP_PIN_KEYPAD, 0, SCREEN_HEIGHT - (PINPAD_SOFTKEY_DP + PINPAD_HEIGHT_DP) * SCREEN_PIX_PER_DP);
	//number keypad background
	TUI_LOG_DEBUG("%s PINPAD_SOFTKEY_DP = %d", __func__, PINPAD_SOFTKEY_DP);
	TUI_LOG_DEBUG("%s PINPAD_HEIGHT_DP = %d", __func__, PINPAD_HEIGHT_DP);
	TUI_LOG_DEBUG("%s SCREEN_PIX_PER_DP = %f", __func__, SCREEN_PIX_PER_DP);
	ret = drawPinpadImage(IDX_INAPP_PIN_KEYPAD, 0, SCREEN_HEIGHT - (PINPAD_SOFTKEY_DP + PINPAD_HEIGHT_DP) * SCREEN_PIX_PER_DP);
	if (ret) {
		TUI_LOG_DEBUG("%s cannot display IDX_INAPP_PIN_KEYPAD!. ret=0x%x", __func__, ret);
		return ret;
	}

	// secure mark the above
	ret = drawPinpadImage(IDX_PINPAD_SECURE_MARK, PINPAD_COL1_LEFT_HD, STANDARD_SCREEN_WIDTH_DP - 118 + 9);
	if (ret) {
		TUI_LOG_DEBUG("%s cannot display SECURE_MARK! ret=0x%x", __func__, ret);
		return ret;
	}

	// secure icon inside of number keypad
	ret = drawPinpadImage(IDX_SECURE_ICON, PINPAD_SECURE_ICON_TOP, PINPAD_LINE1_TOP_HD - 102);
	if (ret) {
		TUI_LOG_DEBUG("%s cannot display SECURE_MARK! ret=0x%x", __func__, ret);
		return ret;
	}
	*/

	// draw number keypad
	for (int i = IDX_PINPAD_0; i <= idx_pinpad_end; i++) {
		key = &layout->buttons_array[i];
		ret = drawPinpadImage(key->val + IDX_PINPAD_0, key->xLeft, key->yTop);
		if (ret) {
			break;
		}
	}

	/*
	// knox image inside of button pinpad
	ret = drawPinpadImage(IDX_PINPAD_KNOX_IMAGE, PINPAD_COL3_LEFT_HD, PINPAD_LINE4_TOP_HD);
	if (ret) {
		TUI_LOG_DEBUG("%s cannot display KNOX_IMAGE! ret=0x%x", __func__, ret);
		return ret;
	}
	*/
	return ret;
}

// display PIN boxes
uint32_t displayPinBox(enum pin_box_type type) {
	uint32_t screenWidth = getScreenWidth();
	uint32_t screenHeight = getScreenHeight();
	int i;
	uint32_t ret = 0;
	int x = 0;
	uint32_t len = 0;
	sPinBoxLayout_t *pinbox_layout = NULL;

	TUI_LOG_DEBUG("%s display_pin_box +++", __func__);
	TUI_LOG_DEBUG("%s screenWidth = %d, screenHeight = %d", __func__,
		      screenWidth, screenHeight);

	len = (screenWidth - g_min_pin_len * g_pinbox_width - (g_min_pin_len - 1) * g_pinbox_space) >> 1;
	if (len > (screenWidth >> 1)) {
		TUI_LOG_DEBUG("%s: invalid value! g_min_pin_len=%d g_pinbox_width=%d g_pinbox_space=%d",
			       __func__, g_min_pin_len, g_pinbox_width, g_pinbox_space);
		return TIMA_ERROR_TUI_DISPLAY_ERROR;
	}

	TUI_LOG_DEBUG("%s: g_min_pin_len=%d g_pinbox_y=%d, g_pinbox_width=%d g_pinbox_height=%d g_pinbox_space=%d",
		__func__, g_min_pin_len, g_pinbox_y, g_pinbox_width, g_pinbox_height, g_pinbox_space);
	// display internal pin box
	for (i = 0; i < g_min_pin_len; i++) {
		pinbox_layout = (sPinBoxLayout_t *)(&g_pinpad_layout.pinbox_array[i]);
		x = len;    // the first PIN box
		TUI_LOG_DEBUG("%s first pinbox x = %d", __func__, x);
		drawPinpadImage(IDX_NORMAL_PINBOX + type, pinbox_layout->xLeft, pinbox_layout->yTop);

		if (ret) {
			TUI_LOG_DEBUG("%s unable to display internal PIN box!", __func__);
			break;
		} else {
			TUI_LOG_DEBUG("%s displayed internal PIN box at (%d, %d)!", __func__, pinbox_layout->xLeft, pinbox_layout->yTop);

			TUI_LOG_DEBUG
				("screenWidth=%d, g_min_pin_len=%d, g_pinbox_width=%d, g_pinbox_space=%d, g_pinbox_width=%d. g_pinbox_y=%d, g_pinbox_height=%d",
				 screenWidth, g_min_pin_len,
				 g_pinbox_width, g_pinbox_space,
				 g_pinbox_width, g_pinbox_y,
				 g_pinbox_height);

		}

	}
	TUI_LOG_DEBUG("%s display_pin_box ---", __func__);
	return ret;
}

/*
  Clean PIN and PIN dots
*/
void clearPinData() {
    // clear input PIN buffer
    memset(g_pin, 0, PIN_SIZE);
    g_pin_length = 0;
    g_current_button = PAD_NOKEY_VAL;
}

uint32_t launchPinpad(bool start_tui_session, enum pin_box_type pinbox_type, bool certificate_verified) {
	uint32_t ret;
	g_cancel_button_enabled = false;

	clearPinData();

	if (start_tui_session) {
		ret = openTuiSession(gBgImage, gBgImageSize);
		if (ret) {
			return ret;
		}

		// set softkey temporarily, this should be changed.
		if (certificate_verified) {
			pinSoftKey.softKey = g_softkey[0];

			displayPinButtons();
			if (ret) {
				TUI_LOG_DEBUG("%s Unable to display pin pad. ret=0x%x", __func__, ret);
			}

			ret = displayPinBox(pinbox_type);
			if (ret) {
				TUI_LOG_DEBUG("%s Unable to display pin box. ret=0x%x", __func__, ret);
			}
			TUI_LOG_DEBUG("%s display images done", __func__);
		}
	}

	showFrameBuffer();
	return ret;
}
