// HTML4 / HTML5: No differences
define(["jquery","css!./component.css"], function( jq ) {

	"use strict";

	// Memory Game was inspired by
	// https://codepen.io/natewiley/pen/HBrbL
	// © 2014 Nate Wiley
	// License -- MIT

	/**
	 * @constructor
	 */
	return function ( context, metadata ) {

		var m_instance,
			navigationNextAllowed = false,
			shellElement = jq(context.getElement()),
			memoryWrapper,
			playArea,
			playAreaId = "memoryCards_" + metadata.page.getId() + "_" + metadata.getId(),
			successMessage,
			allCardsA,
			cards,
			restartButton,
			parameters = metadata.parameters,
			guess = null,
			paused = false,
			numberOfTries = 0,
			fonts = [
				'Arial, Helvetica, sans-serif',
				'"Times New Roman", Times, serif',
				'Verdana, Geneva, sans-serif',
				'"Courier New", Courier, monospace',
				'Palanquin, Helvetica, sans-serif'
			];

        function createSuccessMessage() {
            var successMsg = parameters.get("success_text", "You rock!"),
                yourResultMsg = parameters.get("your_number_of_tries_text", "Your number of tries:"),
                retryButtonMsg = parameters.get("retry_button_text", "Erneut versuchen?"),
                fontFamily = parameters.asNumber("success_font_family", "1"),
                color = parameters.get("success_color", "#919191"),
                colorLink = parameters.get("success_link_color", "#333333"),
                successBackgroundColor = asRgbaValue("success_background_color", "#ffffff", "success_background_transparency"),
                successBorderColor = asRgbaValue("success_border_color", "#98a7b5", "success_border_transparency"),
                successBorderSize = parameters.get("success_border_size", "1"),
                usePartsOfAvailableSpace = 3,
                numTextRows = 4,
                lineHeightFactor = 1.6,
                successPaddingTop = Math.round(metadata.getHeight() / usePartsOfAvailableSpace),
                successLineHeight = Math.round(metadata.getHeight() / usePartsOfAvailableSpace / numTextRows),
                successFontSize = successLineHeight / lineHeightFactor;


            restartButton =  jq(document.createElement("span"))
                .addClass("restart")
                .text(retryButtonMsg)
                .css({
                    "color": colorLink,
                    "cursor": "pointer"
                });

            successMessage = jq(document.createElement("div"))
                .css({
                    "font-family": getFont( fontFamily ),
                    "color": color,
                    "border": successBorderSize + "px solid " + successBorderColor,
                    "background-color": successBackgroundColor,
                    "text-align": "center",
                    "padding-top": successPaddingTop,
                    "font-size": successFontSize + "px",
                    "line-height": successLineHeight + "px",
                    "position": "absolute",
                    "left": 0,
                    "top": 0,
                    "width": "100%",
                    "height": "100%",
                    "z-index": "9999"
                })
                .html(
                    '<div class="winner" style="padding: 0; margin: 0; font-weight: normal; ' +
                    'font-size: ' + (successFontSize * 2) + 'px; ' +
                    'line-height: ' + (successLineHeight * 2) + 'px;">' + successMsg + '</div>' +
                    '<div class="result">' + yourResultMsg + ' ' + numberOfTries + '</div>'
                )
                .hide();

            successMessage.append( restartButton );
        }

        function createPlayArea() {
            cards = getCardsDOM();

            playArea = jq(document.createElement("div"))
                .addClass("playArea")
                .attr("id", playAreaId);

            playArea.append(cards);
        }

		function createDOM() {
            createPlayArea();
			createSuccessMessage();

			memoryWrapper = jq(document.createElement("div"))
				.addClass("memoryGame")
				.append(playArea)
				.append(successMessage);

			shellElement.css({
				width : metadata.getWidth() + "px",
				height : metadata.getHeight() + "px"
			});

			shellElement.append( memoryWrapper );

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

		function getFont(index) {
			var fontIndex = (index > 0 && index <= fonts.length) ? index - 1 : 0;
			return fonts[fontIndex];
		}

		function asRgbaValue( colorParameterName, defaultColor, transparencyParameterName ) {

			var color = hexToRgb( parameters.get(colorParameterName, defaultColor)),
				alpha = asAlpha( parameters.asNumber(transparencyParameterName, 0) );

			return "rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + alpha + ")";
		}

		function hexToRgb( hex ) {

			var parsingResult = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
			if( parsingResult ) {
				return {
					r: parseInt(parsingResult[1], 16),
					g: parseInt(parsingResult[2], 16),
					b: parseInt(parsingResult[3], 16)
				};
			}

			return {
				r: 0,
				g: 0,
				b: 0
			};
		}

		function asAlpha( percentValue ) {
			return (100 - percentValue) / 100;
		}

		function getCardsDOM() {

			var parameters = metadata.parameters,
				borderSize = parameters.get("border_size", "1") + "px",
				borderColor = parameters.get("border_color", "#000000"),
				cardsMargin = parameters.get("margin", "5") + "px",
				rowCount = parameters.asNumber("rows", 2),
				cardWidth = Math.floor(100 / Math.ceil( allCardsA.length / rowCount )) + "%",
				cardHeight = Math.floor(100 / rowCount) + "%",
				backCoverImage = parameters.get("bg_image", null),
				backCoverURI = (backCoverImage) ? context.stage.getSharedPath() + backCoverImage.fileName : context.getPath() + "cover.jpg",
                cardsHTML = '';

			jq(allCardsA).each(function (k, v) {
				cardsHTML +=
					'<div class="card" data-id="' + v.id + '" style="padding: ' + cardsMargin + '; width: ' + cardWidth + '; height: ' + cardHeight + ';">' +
						'<div class="inside">' +
							'<div class="front" style="' +
                                'background-image: url(' + v.img + '); background-size: cover; background-position: center center; ' +
                                'border: ' + borderSize + ' solid ' + borderColor + ';">' +
                                '<div class="highlight">&nbsp;</div>' +
                            '</div>' +
							'<div class="back" style="background-image: url(' + backCoverURI + '); background-size: cover; ' +
                                'background-position: center center; border: ' + borderSize + ' solid ' + borderColor + ';">&nbsp;' +
                            '</div>' +
						'</div>' +
					'</div>';
			});

			return jq( cardsHTML );
		}

		function getAllCardParametersA() {
			var cardsParameterA = [],
				max = 20,
				currentImage;

			for( var i=1; i <= max; i++ ) {
				currentImage = parameters.get("card_" + i + "_image", null);
				if (!currentImage) {
                    continue;
                }

                cardsParameterA.push(
                    {
                        name: parameters.get('card_' + i + '_name',""),
                        img: context.stage.getSharedPath() + currentImage.fileName,
                        id: i
                    }
                );
			}

			// get default images if empty
			if( cardsParameterA.length === 0 ){
				cardsParameterA.push(
					{
						name: "Default image 1",
						img: context.getPath() + "default1.jpg",
						id: 1
					}
				);
				cardsParameterA.push(
					{
						name: "Default image 2",
						img: context.getPath() + "default2.jpg",
						id: 2
					}
				);
				cardsParameterA.push(
					{
						name: "Default image 3",
						img: context.getPath() + "default3.jpg",
						id: 3
					}
				);
			}

			return cardsParameterA;
		}

		// create an object shield so we are able to select and drag element
		function createAuthoringShield() {

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

		function shuffle() {
			var cards = document.getElementById( playAreaId );
			for (var i = cards.children.length; i >= 0; i--) {
				cards.appendChild(cards.children[Math.random() * i | 0]);
			}
		}

		function cardClicked() {
			var card = jq(this),
                cardInside = card.find(".inside");

            if (paused || cardInside.hasClass("matched") || cardInside.hasClass("picked")) {
            	return;
            }

			cardInside.addClass("picked");

            //
            card.find(".inside").css({"transition-duration":""});
            card.find(".inside > .front").css({"transition-duration":""});
            card.find(".inside > .back").css({"transition-duration":""});

            if (!guess) {
				guess = card.attr("data-id");
			}
			else if (guess === card.attr("data-id") && !card.hasClass("picked")) {
				numberOfTries++;
				card.parent().find(".picked").addClass("matched");
				guess = null;
			}
			else {
				numberOfTries++;
				guess = null;
				paused = true;

				setTimeout(function () {
					card.parent().find(".picked").removeClass("picked");
					paused = false;
				}, 600);
			}

			if (card.parent().find(".matched").length === allCardsA.length) {
				win();
			}

		}

		function reset() {
			context.stage.variable.set("tts_memoryGameResult" + metadata.getId(), false, "tts.memoryGame");

			playArea.hide();
			numberOfTries = 0;
			guess = null;
			paused = false;
			hideModal();
			cards.find(".inside").removeClass("picked");
			cards.find(".inside").removeClass("matched");
			shuffle();
			playArea.show("slow");

			// ToDo: turn feature back on once API method context.stage.navigation.logic.getNextPageAccess() is working
			// This feature has been disabled as long as the API method
			// context.stage.navigation.logic.getNextPageAccess()
			// is not yet working correctly. Next button, Evaluate button and Memory game can interact and block the
			// next button navigation. Without the mentioned method working, user is still able to navigate to next page
			// by using the arrow keys on the keyboard
			/*
			registerNavigationControlElement( m_instance, metadata.parameters.asBool("disableNextButton",false) );
			*/
		}

		function win() {
			context.stage.variable.set("tts_memoryGameResult" + metadata.getId(), numberOfTries, "tts.memoryGame");

			var yourResultMsg = parameters.get("your_number_of_tries_text", "Your number of tries:");

			successMessage.find(".result:first").text(yourResultMsg + ' ' + numberOfTries);

			paused = true;
			setTimeout(function () {
				showModal();
			}, 300);

			// ToDo: turn feature back on once API method context.stage.navigation.logic.getNextPageAccess() is working
			// This feature has been disabled as long as the API method
			// context.stage.navigation.logic.getNextPageAccess()
			// is not yet working correctly. Next button, Evaluate button and Memory game can interact and block the
			// next button navigation. Without the mentioned method working, user is still able to navigate to next page
			// by using the arrow keys on the keyboard
			/*
			setAllowNavigationNext( m_instance, metadata.parameters.asBool("disableNextButton",false) );
			*/
		}

		function showModal() {
			successMessage.fadeIn("slow");
		}

		function hideModal() {
			successMessage.hide();
		}

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

			var supportsPointerEvents = window && window.PointerEvent,
				canFireTouchend = "ontouchend" in document,
				canFireTouchmove = "ontouchmove" in document,
				canFireTouchcancel = "ontouchcancel" in document;

			cards.on(canFireTouchend ? "touchend" : (supportsPointerEvents ? "pointerup" : "mouseup"), cardClicked );
			restartButton.on(canFireTouchend ? "touchend" : (supportsPointerEvents ? "pointerup" : "mouseup"), reset);

			restartButton.on(canFireTouchmove ? "touchmove" : (supportsPointerEvents ? "pointermove" : "mousemove"), buttonHighlightOn);
			restartButton.on(canFireTouchcancel ? "touchcancel" : (supportsPointerEvents ? "pointerout" : "mouseout"), buttonHighlightOff);
		}

		function buttonHighlightOn(){
			var colorLinkHover = parameters.get("success_link_color_touch", "#000000");

			restartButton.css({
				"color" : colorLinkHover
			});
		}

		function buttonHighlightOff(){
			var colorLink = parameters.get("success_link_color", "#333333");

			restartButton.css({
				"color" : colorLink
			});
		}

		// ToDo: turn feature back on once API method context.stage.navigation.logic.getNextPageAccess() is working
		// This feature has been disabled as long as the API method
		// context.stage.navigation.logic.getNextPageAccess()
		// is not yet working correctly. Next button, Evaluate button and Memory game can interact and block the
		// next button navigation. Without the mentioned method working, user is still able to navigate to next page
		// by using the arrow keys on the keyboard
		/*
		function setAllowNavigationNext( controlInstance, navigationControlActive ){
			var buttonNextControlGroupId = "tts_button_next_control_" + metadata.page.getId();
			if( navigationControlActive ) {
				context.page.group.event.fire(controlInstance, buttonNextControlGroupId, "onActivateButtonNext", controlInstance);
			}
		}

		function registerNavigationControlElement( controlInstance, navigationControlActive ){
			var buttonNextControlGroupId = "tts_button_next_control_" + metadata.page.getId();
			if( navigationControlActive ) {
				context.page.group.event.fire(controlInstance, buttonNextControlGroupId, "onDeactivateButtonNext", controlInstance);
			}
		}
		*/

		return {
			onLoading : function () {
				m_instance = this;

				context.page.event.bindOnEnter(m_instance);

				allCardsA = jq.merge( getAllCardParametersA(), getAllCardParametersA() );
				createDOM();
				bindEvents();
				shuffle();

				if( context.stage.isInAuthoringMode() ) {
					context.stage.variable.set("tts_memoryGameResult" + metadata.getId(), false, "tts.memoryGame");
					return;
				}

                // check if this memory game has already been done
                var formerSuccessResult = context.stage.variable.get("tts_memoryGameResult" + metadata.getId(), "tts.memoryGame");

                if (formerSuccessResult) {
                    numberOfTries = formerSuccessResult;
                    win();
                }
			},

			onEnterPage : function () {
				// ToDo: turn feature back on once API method context.stage.navigation.logic.getNextPageAccess() is working
				// This feature has been disabled as long as the API method
				// context.stage.navigation.logic.getNextPageAccess()
				// is not yet working correctly. Next button, Evaluate button and Memory game can interact and block the
				// next button navigation. Without the mentioned method working, user is still able to navigate to next page
				// by using the arrow keys on the keyboard
				/*
				// check if this memory game has already been done
				var formerSuccessResult = context.stage.variable.get("tts_memoryGameResult" + metadata.getId(), "tts.memoryGame");

				if( !formerSuccessResult ){
					registerNavigationControlElement( m_instance, metadata.parameters.asBool("disableNextButton", false) );
				}
				*/
			},

			allowNavigationNext: function(){
				return navigationNextAllowed;
			}
		};
	};
});