#include "Vendor_Interface.h"
#include "TZ_Vendor_tl.h"
#include "TZ_Vendor_debug_tl.h"
#include "tl_tui_bc_error_msg.h"
#include "TuiControl.h"
#include "TuiState.h"
#include "TuiButton.h"
#include "TuiKeypad.h"
#include "TuiPng.h"
#include "TuiTextBox.h"
#include "TuiImageView.h"
#include "TuiTouch.h"
#include "TuiScreen.h"
#include "TuiBackupScreenController.h"
#include "TuiRestoreScreenController.h"
#include "TuiPopupScreenController.h"

extern TouchBuffer touchBuffer[MAX_MULTI_TOUCH];

Node gControlList;
Node* gControlNode;

void setControlNode(Node* controlNode) {
	gControlNode = controlNode;
	gControlList.next = gControlNode;
}

bool isInControl(Control control, TouchEvent touchEvent) {
	if (control.isTouchable == 0) {
		return false;
	}

	if (control.location.x1 <= touchEvent.x && control.location.x1 + control.width > touchEvent.x &&
		control.location.y1 <= touchEvent.y && control.location.y1 + control.height > touchEvent.y) {
		return true;
	}
	return false;
}

bool isValidControl(Control control) {
	if (control.kindOfControl != NONE_CONTROL_TYPE) {
		return true;
	}
	return false;
}

bool storeTouchedControl(TouchEvent event, Control* control) {
	uint32_t i;
	DBG_LOG("%s storeTouchedControl x:%d y:%d type:%d, Id:%d", LOG_TAG, event.x, event.y, event.type, control->id);
	if (event.type == PRESSED_TOUCH_EVENT) {
		//check same control id
		for (i = 0; i < MAX_MULTI_TOUCH; ++i) {
			if (touchBuffer[i].controlId == control->id) {
				return false;
			}
		}

		DBG_LOG("%s storeTouchedControl empty buffer", LOG_TAG);
		//check empty buffer
		for (i = 0; i < MAX_MULTI_TOUCH; ++i) {
			if (touchBuffer[i].touchState == NONE_TOUCH_EVENT) {
				touchBuffer[i].controlId = control->id;
				touchBuffer[i].touchState = (ETouchEventType)event.type;
				control->state = PRESSED_CONTROL_STATE;
				DBG_LOG("%s storeTouchedControl store. id:%d, i:%d", LOG_TAG, control->id, i);
				return true;
			}
		}
		DBG_LOG("%s storeTouchedControl pressed is not stored", LOG_TAG);
		return false;
	}
	else if(event.type == RELEASED_TOUCH_EVENT) {
		//check empty buffer for qsee
		//It gets event 'released'. But if buffer which includes pressed control is empty, it allows RELEASED_CONTROL_STATE.
		if (touchBuffer[0].controlId == 0 && touchBuffer[1].controlId == 0) {
			control->state = RELEASED_CONTROL_STATE;
			return true;
		}

		for (i = 0; i < MAX_MULTI_TOUCH; ++i) {
			if (touchBuffer[i].controlId == control->id) {
				touchBuffer[i].touchState = NONE_TOUCH_EVENT;
				touchBuffer[i].controlId = 0;
				control->state = RELEASED_CONTROL_STATE;
				DBG_LOG("%s storeTouchedControl store. id:%d, i:%d", LOG_TAG, control->id, i);
				return true;
			}
		}
		//releaseAllControl();
		return false;
	}

	return false;
}

Node* pickingTouchedControl(TouchEvent touchEvent) {
	DBG_LOG("%s pickingTouchedControl x:%d y:%d type:%d", LOG_TAG, touchEvent.x, touchEvent.y, touchEvent.type);
	Node* node;
	Node* latestNode = NULL;
	for (node = gControlList.next; node != NULL; node = node->next) {
		if (isInControl(node->control, touchEvent)) {
			if (node->control.state != DISABLE_CONTROL_STATE && node->control.state != INVISIBLE_CONTROL_STATE) {
				latestNode = node;
			}
		}
	}
	if (latestNode == NULL) {
		DBG_LOG("%s bctui pickingTouchedControl cannot find node", LOG_TAG);
		return NULL;
	}

	if (latestNode->control.childCount == 0) {
		//check multi-touch
		if (false == storeTouchedControl(touchEvent, &latestNode->control)) {
			return NULL;
		}
	}

	return latestNode;
}

Node* pickingFocusedControl(EControl controlType) {
	Node *node;
	for (node = gControlList.next; node != NULL; node = node->next) {
		if (node->control.kindOfControl == controlType	&& node->control.focused == TRUE) {
			return node;
		}
	}
	return NULL;
}

Node* pickingControlByState(EControlState state) {
	Node *node;
	for (node = gControlList.next; node != NULL; node = node->next) {
		if (node->control.state == state) {
			return node;
		}
	}
	return NULL;
}

Node* pickingControlById(uint32_t controlId) {
	Node *node;
	for (node = gControlList.next; node != NULL; node = node->next) {
		if (node->control.id == controlId) {
			return node;
		}
	}
	return NULL;
}

ResponseControl executeControl(TouchEvent touchEvent) {
	ResponseControl rc;
	initResponseControl(&rc);

	Node *node = pickingTouchedControl(touchEvent);

	if (node == NULL) {
		DBG_LOG("pickingTouchedControl is NULL");
		releaseAllControl();
		return rc;
	}
	//execute
	if (node->control.execute == NULL) {
		DBG_LOG("node->control.execute is NULL");
		return rc;
	} else {
		DBG_LOG("control id : %d, state:0x%x", node->control.id, node->control.state);
		rc = node->control.execute(&node->control);
	}
	return rc;
}

void releaseAllControl() { // need refactoring draw api to fuction pointer.
	Node *node;
	uint32_t i;

	for (i = 0; i < MAX_MULTI_TOUCH; ++i) {
		touchBuffer[i].touchState = NONE_TOUCH_EVENT;
		touchBuffer[i].controlId = 0;
		touchBuffer[i].counter = 0;
	}

	/*
	node = pickingFocusedControl(TEXT_VIEW_BOX_CONTROL_TYPE);
	if (node != NULL) {
		node->control.focused = FALSE;
		node->control.state = RELEASED_CONTROL_STATE;
		drawTextBox(&node->control);
	}
	*/

	for (node = gControlList.next; node != NULL; node = node->next) {
		if (node->control.kindOfControl == BUTTON_CONTROL_TYPE) {
			if (node->control.state == PRESSED_CONTROL_STATE) {
				node->control.state = RELEASED_CONTROL_STATE;
				drawButton(&node->control);
			}
		}
		if (node->control.kindOfControl == TEXT_VIEW_BOX_CONTROL_TYPE) {
			if (node->control.state == PRESSED_CONTROL_STATE) {
				node->control.state = RELEASED_CONTROL_STATE;
				//there is no pressed & released image on TEXT_VIEW_BOX_CONTROL_TYPE
			}
		}
	}
}

ResponseControl executeIcon(Control *control) {
	ResponseControl rc;
	initResponseControl(&rc);

	return rc;
}
ResponseControl executeSoftKey(Control *control) {
	ResponseControl rc;
	initResponseControl(&rc);

	return rc;
}

uint32_t makeNode(uint32_t nodeNumber, Control *control) {
	gControlNode[nodeNumber].control = *control;

	if (gControlList.next == NULL) {
		gControlList.next = &gControlNode[nodeNumber];
		gControlNode[nodeNumber].pre = &gControlList;
		gControlNode[nodeNumber].next = NULL;
		return 1;
	}
	else {
		Node* tempNode;
		uint32_t nodeCount = 0;
		for (tempNode = gControlList.next; tempNode != NULL; tempNode = tempNode->next) {
			if (nodeCount >= MAX_CONTROL) {
			    DBG_LOG("error : nodecount has been exceeded");
				return (uint32_t)-1; //error
			}
			if (tempNode->next == NULL) {
				tempNode->next = &gControlNode[nodeNumber];
				gControlNode[nodeNumber].pre = tempNode;
				gControlNode[nodeNumber].next = NULL;
				break;
			}
		}
	}
		
	return TUI_SUCCESS;
}

bool addControl(Control *control) {
	int32_t nodeNumber = TIMA_ERROR_TUI;

	for (uint32_t i = 0; i < MAX_CONTROL; ++i) {
		if (gControlNode[i].control.kindOfControl == NONE_CONTROL_TYPE) {
			nodeNumber = i;
			break;
		}
	}
	if (nodeNumber == TIMA_ERROR_TUI) {
	    DBG_LOG("nodenumber is not allocated");
		return false; // error;
	}

	if (control->width == 0 || control->height == 0) { // if !png
		if (control->originResource != NULL) {
			getPngWidthAndHeight(control->originResource, &(control->width), &(control->height));
		} else if (control->eventResource != NULL) {
			getPngWidthAndHeight(control->eventResource, &(control->width), &(control->height));
		} else {
            DBG_LOG("setting control resource failed");
			return false;
		}
	}
	makeNode(nodeNumber, control);

	return true;
}

void clearNode(Node* node) {
	if (node->control.id >= ID_CONTROL_BUTTON_SOFTKEY_CANCEL) {
		if (node->control.eventResource != NULL) {
			TZ_free(node->control.eventResource);
			node->control.eventResource = NULL;
		}
		node->control.eventResourceSize = 0;

		if (node->control.originResource != NULL) {
			TZ_free(node->control.originResource);
			node->control.originResource = NULL;
		}
		node->control.originResourceSize = 0;

		if (node->control.extraResource != NULL) {
			TZ_free(node->control.extraResource);
			node->control.extraResource = NULL;
		}
		node->control.extraResourceSize = 0;
	}
	node->control.kindOfControl = NONE_CONTROL_TYPE;
	node->control.execute = NULL;
	node->control.id = 0;
	node->next = NULL;
	node->pre = NULL;
}

void deleteControl(uint32_t id) {
	Node* node;
	for (node = gControlList.next; node != NULL; node = node->next) {
		if (node->control.id == id) {
			node->pre->next = node->next;
			// free
			clearNode(node);
		}
	}
}

void deleteControlNode(Node* node) {
	for (uint32_t i = 0; i < MAX_CONTROL; ++i) {
		clearNode(&node[i]);
	}
}

void deleteAllControl() {
	DBG_LOG("%s deleteAllControl start", LOG_TAG);

	switch (getScreenState()) {
	case BACKUP_SCREEN_STATE:
	case BACKUP_SCREEN_QUIZ_STATE:
	case POPUP_SCREEN_BACKUP_EXIT_STATE:
		deleteControlNode(getBackupScreenControlNode(BACKUP_SCREEN_STATE));
		deleteControlNode(getBackupScreenControlNode(BACKUP_SCREEN_QUIZ_STATE));
		deleteControlNode(getPopupScreenControlNode());
		break;
	case POPUP_SCREEN_RESTORE_EXIT_STATE:
	case POPUP_SCREEN_RESTORE_FAILED_CHECKSUM_STATE:
		deleteControlNode(getRestoreScreenControlNode());
		deleteControlNode(getPopupScreenControlNode());
		break;
	default:
		deleteControlNode(gControlNode);
		break;
	}
	DBG_LOG("%s deleteAllControl end", LOG_TAG);
}

ResponseControl noneExecution(Control *control) {
	ResponseControl rc;
	initResponseControl(&rc);

	return rc;
}

uint32_t initControl() {
	clearTouchEvent();
	releaseAllControl();
	return TUI_SUCCESS;
}

void setFocus(Control* control, uint32_t focus) {
	control->focused = focus;
	DBG_LOG("%s setFocus id=%d", LOG_TAG, control->id);
}

void initResponseControl(ResponseControl* rc_out) {
	rc_out->charValue = '\0';
	rc_out->textInfo.text = NULL;
	rc_out->changeState = NONE_TUI_STATE;
}

void drawControlNode() {
	DBG_LOG("start to draw control node");
	Node* node;
	for (node = gControlList.next; node != NULL; node = node->next) {
		if (node->control.state == INVISIBLE_CONTROL_STATE) {
			continue;
		}
		switch (node->control.kindOfControl) {
		case TEXT_EDIT_BOX_CONTROL_TYPE:
		case TEXT_VIEW_BOX_CONTROL_TYPE:
			drawTextBox(&node->control);
			break;
		case BUTTON_CONTROL_TYPE:
			drawButton(&node->control);
			break;
		case KEYPAD_CONTROL_TYPE:
			drawKeypad(&node->control);
			break;
		case IMAGE_VIEW_CONTROL_TYPE:
			drawImageView(&node->control);
			break;
		default:
			DBG_LOG("Failed to draw control : %d", node->control.kindOfControl);
			break;
		}
	}
	showFrameBuffer();
}
