// com.tts.initial.html5.animated.menuslider
// HTML4 / HTML5: No differences
define(["jquery"], function (jq) {

	"use strict";

	/**
	 * @constructor
	 */
	return function (context, metadata) {
		var shellElement,
			menuSlider = jq( document.createElement( "div" ) ),
			animationDuration = 300,
            EVENT_THRESHOLD = 100,	// ignore start events for x ms.
			lastEventTime,
			closeOnlyOnClick = metadata.parameters.asBool( "close_only_on_click", false ),
			pointerUpEventName, pointerDownEventName, pointerMoveEventName, pointerLeaveEventName,
			isInAuthoringMode,
			hasStageTriggerSupport;

		function loadBackgroundImage() {
			var deferred = jq.Deferred(),
				promise = deferred.promise(),
				result = {
					width: 0,
					height: 0,
					fileName: ""
				},
				myImage = new Image();

			myImage.onload = function () {
				try {
					result.width = this.width;
					result.height = this.height;
				} finally {
					deferred.resolve(result);
				}
			};

			var backgroundImage = metadata.parameters.get("bg_image", null),
				backgroundFileName;

			// Determine background image
			if (backgroundImage) {
				backgroundFileName = context.stage.getSharedPath() + backgroundImage.fileName;
			} else {
				backgroundFileName = context.getPath() + "menu_" + metadata.parameters.get("bg_default", "1") + ".png";
			}
			result.fileName = backgroundFileName;
			myImage.src = backgroundFileName;

			return promise;
		}

		function decorateRotation(element, angle, width, height) {
			var cssRotate = "rotate(" + angle + "deg)",
				cssTransform = {
					"-webkit-transform": cssRotate,
					"-moz-transform": cssRotate,
					"-ms-transform": cssRotate,
					"-o-transform": cssRotate,
					"transform": cssRotate
				},
				halfWidth,
				halfHeight,
				cssRotationStyles;

			switch (angle) {
				case 90:
					halfHeight = height / 2.0;
					cssRotationStyles = jq.extend({}, cssTransform, {
						"transform-origin": (halfHeight + "px " + halfHeight + "px")
					});
					break;
				case 180:
					cssRotationStyles = jq.extend({}, cssTransform, {
						"transform-origin": "50% 50%"
					});
					break;
				case 270:
					halfWidth = width / 2.0;
					cssRotationStyles = jq.extend({}, cssTransform, {
						"transform-origin": (halfWidth + "px " + halfWidth + "px")
					});
					break;
				default:
			}

			if(cssRotationStyles) {
				element.css(cssRotationStyles);
			}

			// swap width and height if rotated
			if (angle === 90 || angle === 270) {
				modifyShellElementDimension(height, width);
			}

			return element;
		}

		function createAuthoringShield() {
			if (!context.stage.isInAuthoringMode()) {
				return;
			}
			shellElement
				.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"
						})
				)
				.css({
					"cursor": "default"
				});
		}

		function getParentShellElement() {
			var id = metadata.getId(),
				arrayElementIDs = id.split("I").filter(Boolean);

			if (arrayElementIDs.length > 0 && jq("#I" + arrayElementIDs[0]).length > 0) {
				return jq("#I" + arrayElementIDs[0]);
			}
			throw "Element not found!";
		}

        function isValidEvent( ) {
            return typeof lastEventTime === "undefined" || new Date().getTime() - lastEventTime > EVENT_THRESHOLD;
        }

		function slideElement( e ) {
			cancelEvent( e );
			if( !isValidEvent() ) {
				return;
			}

			var slideDirection = metadata.parameters.get("slide_direction", "left"),
				slideDistance = metadata.parameters.asNumber("slide_distance", "200"),
				shellParentElement = getParentShellElement();

			if (shellParentElement.attr("data-slide-state") === "closed") {
				switch (slideDirection) {
					case "right":
						animatedOpen(shellParentElement, {
							"margin-left": slideDistance + "px"
						});
						break;
					case "top":
						animatedOpen(shellParentElement, {
							"margin-top": + (-slideDistance) + "px"
						});
						break;
					case "bottom":
						animatedOpen(shellParentElement, {
							"margin-top": slideDistance + "px"
						});
						break;
					default:
						animatedOpen(shellParentElement, {
							"margin-left": + (-slideDistance) + "px"
						});
				}
			} else {
				animatedClose(shellParentElement);
			}
		}

		function animatedClose(jqElement) {
			if(!jqElement) {
				return;
			}

			jqElement
				.attr("data-slide-state", "closed")
				.animate({
					"margin-left": 0,
					"margin-top": 0
				}, animationDuration);
		}

		function animatedOpen(jqElement, cssStyles) {
			if( !jqElement ) {
				return;
			}

			if (closeOnlyOnClick) {
				jqElement.attr("data-slide-state", "openButclosableOnlyByClick")
			} else {
				jqElement.attr("data-slide-state", "open")
				closeOthers( jqElement );
			}
			jqElement.animate(cssStyles, animationDuration);
		}

		function closeOthers( jqElement ) {
			// if clicked anywhere except element it self
			jq('div[data-slide-state="open"]').each(function (i, elem) {
				if (jqElement.closest(jq(elem)).length > 0) {
					return;
				}

				animatedClose(jq(elem));
			});
		}

		function closeOthersByEvent( e ) {
			// TTPS-20487 - Hyperlinks not functional if menu slider SC has been displayed before
			// this cancel event blocks the usage of hyper links on the page
			//cancelEvent( e );
			closeOthers( jq(e.target) );
		}

		function addBodyMenuSlideListener() {
			var bodyElement = jq(document.body),
				bodyHasMenuSliderListener = bodyElement.data("menu-slider-listener") === "true",
				slideStopEvent = pointerUpEventName;

			if( bodyHasMenuSliderListener ) {
				return;
			}

			bodyElement
				.data( "menu-slider-listener", "true" )
				.on( slideStopEvent, closeOthersByEvent );
		}

		function removeBodyMenuSlideListener() {
			var bodyElement = jq( document.body ),
				bodyHasMenuSliderListener = bodyElement.data( "menu-slider-listener" ) === "true",
				slideStopEvent = pointerUpEventName;

			if ( !bodyHasMenuSliderListener ) {
				return;
			}
			bodyElement
				.data( "menu-slider-listener", "false" )
				.off( slideStopEvent, closeOthersByEvent );
		}

		function modifyShellElementDimension(width, height) {
			if(!shellElement) {
				return;
			}
			var cssStyles = {
				"width": width + "px",
				"height": height + "px"
			};
			shellElement
				.css(cssStyles)
				.closest(".ttkfPresObjRefFG")
					.css(cssStyles);
		}

		function initPointerEventNames() {
			if ( !pointerUpEventName ) {
				var nodeName = getHotspotElementNodeName();
				pointerDownEventName = context.device.getDownEvents( nodeName );
				pointerUpEventName = context.device.getUpEvents( nodeName );
				pointerMoveEventName = context.device.getMoveEvents( nodeName );
				pointerLeaveEventName = context.device.getReleaseEvents( nodeName );
			}
		}

		function getHotspotElementNodeName() {
			return menuSlider.get(0).nodeName
				? menuSlider.get(0).nodeName
				: "document";
		}

		function unlockNavigation() {
			if ( isInAuthoringMode || !hasStageTriggerSupport ) {
				return;
			}
			context.stage.trigger.unlock( metadata.getId() );
		}

		function cancelEvent( e ) {
			if ( e && e.preventDefault ) {
				e.preventDefault();
			}

			if ( e && e.stopPropagation ) {
				e.stopPropagation();
			}

			return false;
		}

		function bindEvents() {
			if ( isInAuthoringMode ) {
				return;
			}

			removeEvents();

			// HTML5. On HTML4 it has no effect.
			context.page.interaction.provokesFeedback( menuSlider, false );
			context.page.interaction.provokesAutosolve( menuSlider, false );

			context.device.attachFirstSupportedEvent( menuSlider, pointerDownEventName, cancelEvent );
			context.device.attachFirstSupportedEvent( menuSlider, pointerUpEventName, slideElement );

			addBodyMenuSlideListener();
		}

		function removeEvents() {
			unlockNavigation();

			initPointerEventNames();
			context.device.removeFirstSupportedEvent( menuSlider, pointerDownEventName, cancelEvent );
			context.device.removeFirstSupportedEvent( menuSlider, pointerUpEventName, slideElement );

			removeBodyMenuSlideListener();
		}

		// revealing public API
		return {
			onLoading: function () {
				isInAuthoringMode = !!context.stage.isInAuthoringMode();
				hasStageTriggerSupport = !!context.stage.trigger;

				shellElement = jq(context.getElement());

				context.page.event.bindOnEnter( this );
				context.page.event.bindOnExit( this );

				loadBackgroundImage().then(function (result) {
					modifyShellElementDimension(result.width, result.height);
					getParentShellElement().attr("data-slide-state", "closed");

					// Create menu slider
					var rotation = metadata.parameters.asNumber( "bg_rotate", "0" );

					menuSlider.css({
							"cursor": "pointer",
							"width": result.width + "px",
							"height": result.height + "px",
							"background-image": "url(\"" + result.fileName + "\")"
						});

					// Append menu slider to shell element
					shellElement.append(
						decorateRotation(menuSlider, rotation, result.width, result.height)
					);
				} );

				if ( isInAuthoringMode ) {
					createAuthoringShield();
				}
			},
			onEnterPage: function () {
				bindEvents();
			},

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