// com.tts.initial.html5.quiz.button.choice
// HTML4 / HTML5: No differences
define( [
	"./accessibility.builder",
	"jquery",
	"./key.code"
	], function (
		AccessibilityBuilder,
		jq,
		KeyCode
	) {

	"use strict";

	/**
	 * @constructor
	 */
	return function (context, metadata) {
		var isStandardPlayer = context.getPlayerName() === "standard",
			instance = null,
			container = null,
			icon = null,
			clickZoneElement = null,
			groupId = null,
			choiceImage = "",
			choicePicWidth = 64,
			choicePicHeight = 32,
			BACKGROUND_POSITION = {},
			isChecked = false,
			isRight = false,
			elementType = "tRadio",
			elementVariableId = "",
        	pageEvaluatedId,
			elementVariableNameSpace = "com_tts_quiz",
			answerID = metadata.getId(),
			pointerDownEventNames = undefined,
			pointerMoveEventNames = undefined,
			pointerUpEventNames = undefined,
			pointerLeaveEventNames = undefined,
			isAssessmentMode = context.stage.isInAssessmentMode(),
			isBestPracticeSolution = false,
			accessibilityModeAvailable = true,
			accessibilityTooltip,
			accessibilityTabOrder = metadata.parameters.asNumber("tab-order", -1),
			exludeFromTabControl = metadata.parameters.asBool("exclude-from-tab-control", false),
			ariaLabel = ((metadata.parameters.get("aria-label", false) || "").trim() === "") ? false : metadata.parameters.get("aria-label", false),
			accessibilityKey = metadata.parameters.get("accessibility-key", "KeyNone" ),
			accessibilityLocation = metadata.parameters.asNumber( "accessibility-location", 0 ),
			accessibilityPositionX = metadata.parameters.asNumber( "accessibility-position-x", -6 ),
			accessibilityPositionY = metadata.parameters.asNumber( "accessibility-position-y", -6 );

		function buildVariableId() {
			var baseId = "checkedValue" + metadata.getId() + "_";
			if (elementType === "tCheck") {
				return baseId + answerID + "_" + groupId;
			}
			return baseId + groupId;
		}

		function initPointerEventNames() {

			if (pointerDownEventNames) {
				return;
			}

			var nodeName = getHotspotElementNodeName();
			pointerDownEventNames = context.device.getDownEvents(nodeName);
			pointerUpEventNames = context.device.getUpEvents(nodeName);
			pointerMoveEventNames = context.device.getMoveEvents(nodeName);
			pointerLeaveEventNames = context.device.getReleaseEvents(nodeName);

			// Hotfix: Chrome on iPad iOS does not distinguish pointerMoveEventNames and pointerLeaveEventNames
			if ((pointerMoveEventNames == pointerLeaveEventNames) && (pointerMoveEventNames == "touchmove")) {
				pointerLeaveEventNames = "pointerout";
			}
		}

		function getHotspotElementNodeName() {
			return "document";
		}

		function initializeParameters(parameters) {
			isRight = parameters.asBool("is_right");
			elementType = parameters.get("element_type");
			groupId = parameters.asNumber("toggle_group_id", 1);
			elementVariableId = buildVariableId();

			var savedVariableValue,
				backgroundImage = parameters.get( "state_picture", null ),
				backgroundImageAssessment = parameters.get( "state_picture_assessment", null ),
				path = context.getPath();

			if ( isAssessmentMode && backgroundImageAssessment ) {
				backgroundImage = backgroundImageAssessment;
            }

			if (backgroundImage) {
				choiceImage = context.stage.getSharedPath() + backgroundImage.fileName;
				choicePicWidth = backgroundImage.width;
				choicePicHeight = parseInt(backgroundImage.height / 12);
			} else if (elementType === "tRadio") {
				choiceImage = path + "radiobutton.png";
			} else {
				choiceImage = path + "checkbox.png";
			}

			BACKGROUND_POSITION = {
				"DEFAULT": "0px 0px",
				"HOVER": "0px " + -choicePicHeight + "px",
				"PRESSED": "0px " + (-2 * choicePicHeight) + "px",
				"INACTIVE": "0px " + (-3 * choicePicHeight) + "px",
				"SELECTED": "0px " + (-4 * choicePicHeight) + "px",
				"SELECTED_HOVER": "0px " + (-5 * choicePicHeight) + "px",
				"SELECTED_RIGHT": "0px " + (-6 * choicePicHeight) + "px",
				"SELECTED_WRONG": "0px " + (-7 * choicePicHeight) + "px",
				"NOT_SELECTED_WRONG": "0px " + (-8 * choicePicHeight) + "px",
				"NOT_SELECTED_RIGHT": "0px " + (-9 * choicePicHeight) + "px",
				"SAMPLE_SELECTED": "0px " + (-10 * choicePicHeight) + "px",
				"SAMPLE_NOT_SELECTED": "0px " + (-11 * choicePicHeight) + "px"
			};

			savedVariableValue = parseInt(context.stage.variable.get(elementVariableId, elementVariableNameSpace));
			savedVariableValue = !isNaN(savedVariableValue) ? savedVariableValue : 0;
			if (savedVariableValue && savedVariableValue === answerID) {
				isChecked = true;
			}

		}

		function isEvaluated() {

			if (context.stage.isInPreviewMode()) {
				return false;
			}

			if (isStandardPlayer) {
				return context.stage.variable.get(pageEvaluatedId, elementVariableNameSpace);
			}

			return context.page.quiz.hasQuestion() && context.page.quiz.getQuestion().isFinalized();
		}

		function createChoiceElement() {
			container = jq(context.getElement())
				.css({
					"width": choicePicWidth + "px",
					"height": choicePicHeight + "px"
				} );

			icon = jq(document.createElement("div"))
				.css({
					"position": "absolute",
					"background-image": "url(\"" + choiceImage + "\")",
					"background-repeat": "no-repeat",
					"background-position": (isChecked ? BACKGROUND_POSITION.SELECTED : BACKGROUND_POSITION.DEFAULT),
					"-webkit-tap-highlight-color": "rgba(0,0,0,0)",
					"width": choicePicWidth + "px",
					"height": choicePicHeight + "px",
					"padding-right": "2px"
				} );

			container.append( icon );

			accessibilityTooltip = new AccessibilityBuilder(accessibilityKey, accessibilityLocation, accessibilityPositionX, accessibilityPositionY, context).build();
			if (accessibilityTooltip.getElement() ) {
				container.append( accessibilityTooltip.getElement() );
			}

			context.stage.isInAuthoringMode()
				? createAuthoringShield()
				: createClickZoneElement();
		}

		function createAuthoringShield() {
			container.append(
				jq(document.createElement("div"))
					.css({
						"position": "absolute",
						"left": 0,
						"top": 0,
						"background-color": "transparent",
						"opacity": "0.4",
						"width": "100%",
						"height": "100%",
						"z-index": "9999"
					})
			);
		}

		function createClickZoneElement() {
			clickZoneElement = jq(document.createElement("button"))
				.attr({
					"id": answerID + "_ChoiceClickZone",
					"role": (elementType === "tRadio") ? "radio" : "checkbox",
					"aria-disabled": "false",
					"aria-checked": "false",
					"name": groupId
				})
				.css({
					"position": "absolute",
					"background-color": "transparent",
					"-webkit-tap-highlight-color": "rgba(0,0,0,0)",
					"width": choicePicWidth + "px",
					"height": choicePicHeight + "px",
					"cursor": "pointer",
					"padding": "0",
					"border": "none",
					"background": "none",
					"z-index": "9999"
				});

			if (ariaLabel) {
				clickZoneElement.attr({
					"aria-label": ariaLabel
				})
			}

			container.append(clickZoneElement);
		}

        function reset(){

            if (isStandardPlayer) {
                context.stage.variable.set(pageEvaluatedId, false, elementVariableNameSpace);
            }

            setChecked( false );
        }

		function setChecked(checked) {
			context.page.quiz.setSelected(instance, checked);
			isChecked = checked;

			if (checked) {
				icon.css("background-position", BACKGROUND_POSITION.SELECTED);
				context.page.event.trigger(instance, "toggleOn");

				if (!(context.stage.isInAuthoringMode()) && ariaLabel) {
					clickZoneElement.attr({
						"aria-checked": "true"
					});
				}
			} else {
				icon.css("background-position", BACKGROUND_POSITION.DEFAULT);
				context.page.event.trigger(instance, "toggleOff");

				if (!(context.stage.isInAuthoringMode()) && ariaLabel) {
					clickZoneElement.attr({
						"aria-checked": "false"
					});
				}
			}
		}

		function lockNavigation() {
			if(context.stage.trigger !== undefined) {
				context.stage.trigger.lock(answerID);
			}
		}

		function unlockNavigation() {
			if(context.stage.trigger !== undefined) {
				context.stage.trigger.unlock(answerID);
			}
		}

		function isOnTarget( e ) {
			var elem = e.target,
				origEvent = e.originalEvent,
				changedTouch;

			if ( !origEvent ) {
				return true;
			} else {
				changedTouch = origEvent.changedTouches && origEvent.changedTouches.length > 0 ? origEvent.changedTouches[0] : undefined;
			}

			if ( changedTouch ) {
				elem = document.elementFromPoint( changedTouch.clientX, changedTouch.clientY );
			}

			return e.target === elem;
		}

		function bindEvents() {

			if ( context.stage.isInAuthoringMode() ) {
				return;
			}

			removeEvents();

			if ( elementType === "tRadio" ) {
				context.page.group.event.bind( instance, groupId + elementType, "onSingleChoiceClick" );
			}

			var clickZoneHtmlElement = clickZoneElement.get( 0 );

			context.device.attachFirstSupportedEvent( clickZoneHtmlElement, pointerDownEventNames, onButtonPressed );
			context.device.attachFirstSupportedEvent( clickZoneHtmlElement, pointerUpEventNames, onButtonReleased );
			context.device.attachFirstSupportedEvent( clickZoneHtmlElement, pointerMoveEventNames, onMouseMove );
			context.device.attachFirstSupportedEvent( clickZoneHtmlElement, pointerLeaveEventNames, onMouseOut );
		}

		function onMouseOut() {
			unlockNavigation();
			icon.css( "background-position", ( isChecked ? BACKGROUND_POSITION.SELECTED : BACKGROUND_POSITION.DEFAULT ) );
        }

		function onMouseMove() {
			if ( icon.css( "background-position" ) != BACKGROUND_POSITION.PRESSED ) {
				icon.css( "background-position", ( isChecked ? BACKGROUND_POSITION.SELECTED_HOVER : BACKGROUND_POSITION.HOVER ) );
			}
		}

		function removeEvents() {

			initPointerEventNames();

			var clickZoneHtmlElement = clickZoneElement.get( 0 );

			context.device.removeFirstSupportedEvent( clickZoneHtmlElement, pointerDownEventNames, onButtonPressed );
			context.device.removeFirstSupportedEvent( clickZoneHtmlElement, pointerUpEventNames, onButtonReleased );
			context.device.removeFirstSupportedEvent( clickZoneHtmlElement, pointerMoveEventNames, onMouseMove );
			context.device.removeFirstSupportedEvent( clickZoneHtmlElement, pointerLeaveEventNames, onMouseOut );
		}

		function showResultSymbol(isCorrectAnswer, selectedByUser) {
			if (isCorrectAnswer) {
				icon.css("background-position", (selectedByUser ? BACKGROUND_POSITION.SELECTED_RIGHT : BACKGROUND_POSITION.NOT_SELECTED_WRONG));
			}
			else {
				icon.css("background-position", (selectedByUser ? BACKGROUND_POSITION.SELECTED_WRONG : BACKGROUND_POSITION.NOT_SELECTED_RIGHT));
			}
		}

		function onButtonPressed( e ) {
			context.device.cancelEvent( e );
			lockNavigation();
			icon.css( "background-position", BACKGROUND_POSITION.PRESSED );
		}

		function onButtonReleased( e ) {
			context.device.cancelEvent( e );
			unlockNavigation();

			icon.css( "background-position", ( isChecked ? BACKGROUND_POSITION.SELECTED : BACKGROUND_POSITION.DEFAULT ) );

			if ( !isOnTarget( e ) ) {
				return;
			}

			setChecked( !isChecked );

			icon.css( "background-position", ( isChecked ? BACKGROUND_POSITION.SELECTED : BACKGROUND_POSITION.DEFAULT ) );

			// save the user selection
			if ( isChecked ) {
				context.stage.variable.set( elementVariableId, answerID, elementVariableNameSpace );
			}
			else if ( elementType === "tCheck" ) {
				// Update variable value if the user deselects a checkbox.
				// This is not necessary for radio buttons, because there is only one variable for the whole question.
				context.stage.variable.set( elementVariableId, false, elementVariableNameSpace );
			}

			if ( elementType === "tRadio" ) {
				context.page.group.event.fire( instance, groupId + elementType, "onSingleChoiceClick" );
			}
		}

		function onAccessibilityKeyPressed() {
			icon.css("background-position", (isChecked ? BACKGROUND_POSITION.SELECTED : BACKGROUND_POSITION.DEFAULT));

			setChecked(!isChecked);

			icon.css("background-position", (isChecked ? BACKGROUND_POSITION.SELECTED : BACKGROUND_POSITION.DEFAULT));

			// save the user selection
			if (isChecked) {
				context.stage.variable.set(elementVariableId, answerID, elementVariableNameSpace);
			}
			else if (elementType === "tCheck") {
				// Update variable value if the user deselects a checkbox.
				// This is not necessary for radio buttons, because there is only one variable for the whole question.
				context.stage.variable.set(elementVariableId, false, elementVariableNameSpace);
			}

			if (elementType === "tRadio") {
				context.page.group.event.fire(instance, groupId + elementType, "onSingleChoiceClick");
			}
		}

		function calculateClickZonePosition() {
			var containerChildren,
				childElement,
				offset = container.offset(),
				childOffset,
				childMaxPos,
				position = {
					left: offset.left,
					top: offset.top,
					width: choicePicWidth,
					height: choicePicHeight
				};

			containerChildren = context.getChildren();
			if (!containerChildren || containerChildren.length === 0) {
				return position;
			}

			offset = container.offset();
			position.left = offset.left;
			position.top = offset.top;
			position.width = container.width() > parseInt(choicePicWidth) ? container.width() : parseInt(choicePicWidth);
			position.height = container.height() > parseInt(choicePicHeight) ? container.height() : parseInt(choicePicHeight);

			jq.each(containerChildren, function (i, e) {
				childElement = jq(e);
				if (!childElement.is(":visible")) {
					return;
				}

				childOffset = childElement.offset();

				if (childOffset.left < offset.left) {
					position.left = childOffset.left;
				}

				if (childOffset.top < offset.top) {
					position.top = childOffset.top;
				}

				childMaxPos = childOffset.left + childElement.width();
				if (childMaxPos > (position.left + position.width)) {
					position.width = (childOffset.left - position.left) + childElement.width();
				}

				childMaxPos = childOffset.top + childElement.height();
				if (childMaxPos > (position.top + position.height)) {
					position.height = (childOffset.top - position.top) + childElement.height();
				}
			});

			return position;
		}

		function adjustClickZoneSize() {
			var position = calculateClickZonePosition();
			clickZoneElement
				.offset(position)
				.width(position.width)
				.height(position.height);
		}

		function switchToUserSolution() {
			removeEvents();
			accessibilityModeAvailable = false;

			if (isStandardPlayer) {
				context.stage.variable.set(pageEvaluatedId, true, elementVariableNameSpace);
			}

			unlockNavigation();

			showResultSymbol( isRight, isChecked );

			isBestPracticeSolution = false;

			clickZoneElement.attr({
				"aria-disabled": "true"
			})

			if (isChecked) {
				if (!(context.stage.isInAuthoringMode()) && ariaLabel) {
					clickZoneElement.attr({
						"aria-checked": "true"
					});
				}
			} else {
				if (!(context.stage.isInAuthoringMode()) && ariaLabel) {
					clickZoneElement.attr({
						"aria-checked": "false"
					});
				}
			}
		}

		function switchToBestPracticeSolution() {
			removeEvents();
			accessibilityModeAvailable = false;
			unlockNavigation();
			icon.css( "background-position", ( isRight ? BACKGROUND_POSITION.SAMPLE_SELECTED : BACKGROUND_POSITION.SAMPLE_NOT_SELECTED ) );

			isBestPracticeSolution = true;

			clickZoneElement.attr({
				"aria-disabled": "true"
			})

			if (isRight) {
				if (!(context.stage.isInAuthoringMode()) && ariaLabel) {
					clickZoneElement.attr({
						"aria-checked": "true"
					});
				}
			} else {
				if (!(context.stage.isInAuthoringMode()) && ariaLabel) {
					clickZoneElement.attr({
						"aria-checked": "false"
					});
				}
			}
		}

		// revealing public API
		return {
			onLoading: function () {
				instance = this;

				isChecked = false;

				context.page.event.bindOnEnter(instance);
				context.page.event.bindOnExit( instance );
				context.stage.accessibility.bindOnAccessibilityModeChanged(instance);
				if (!isStandardPlayer) {
					context.page.event.bind(instance, "onTabNavigationOff");
					context.page.event.bind(instance, "onTabNavigationSelection");
					context.page.event.bind(instance, "onTabNavigationFire");
				}

				initializeParameters(metadata.parameters);
				createChoiceElement();
				context.page.quiz.add(instance, groupId + elementType, isRight);

				if( context.stage.isInAuthoringMode() ) {
					setChecked(isRight);
				}
			},

			onEnterPage: function () {
				pageEvaluatedId = metadata.page.getId() + "_evaluated";

                if (context.stage.isInAuthoringMode()) {
                	return;
                }

				adjustClickZoneSize();

				if ( !isStandardPlayer && isEvaluated() ) {
					isBestPracticeSolution ? switchToBestPracticeSolution() : switchToUserSolution();
					return;
				}

				if ( isStandardPlayer ) {
					reset();
				}

				bindEvents();
				if (!isStandardPlayer && !exludeFromTabControl) {
					accessibilityTooltip.registerTabNavigation(metadata.getId(), accessibilityTabOrder);
				}
			},

            onExitPage: function () {
				removeEvents();
			},

            onSingleChoiceClick: function (event, senderId) {
				if (senderId !== answerID) {
					setChecked(false);
				}
			},

			onUserSolution: switchToUserSolution,

			onBestPracticeSolution: switchToBestPracticeSolution,

			onAccessibilityModeChanged: function ( dataHTML5, dataHTML4 ) {
				if (!accessibilityModeAvailable) {
					return;
				}

				var params = dataHTML4 || dataHTML5;

				if ( params.isActive ) {
					accessibilityTooltip.show();
				} else {
					accessibilityTooltip.hide();
				}
			},

			onAccessibilityKeyPressed: function ( dataHTML5, dataHTML4 ) {
				if (!accessibilityModeAvailable) {
					return;
				}

				var params = dataHTML4 || dataHTML5;

				if ( params.keyCode == accessibilityTooltip.getKeyCode() ) {
					onAccessibilityKeyPressed();
					context.stage.accessibility.turnAccessibilityModeOff();
				}
			},

			onTabNavigationSelection: function (dataHTML5, dataHTML4, data) {
				if (data && data.id && data.id == metadata.getId()) {
					if (!accessibilityModeAvailable) {
						setTimeout(function () {
							context.page.event.fire(instance, "onInactiveTabNavigationSelection");
						}, 10);
						return;
					}
					clickZoneElement.trigger("focus");
				} else {
					clickZoneElement.trigger("blur");
				}
			},

			onTabNavigationOff: function (dataHTML5, dataHTML4) {
				clickZoneElement.trigger("blur");
			},

			onTabNavigationFire: function (dataHTML5, dataHTML4, data) {
				if (!accessibilityModeAvailable) {
					return;
				}

				if (data && data.id && data.id == metadata.getId()) {
					onAccessibilityKeyPressed();
					context.stage.accessibility.turnAccessibilityModeOff();
				}
			}
		};
	};
});
