// com.tts.initial.html5.gif
define( [
	"jquery"
],
	function (
		jq
	) {

		"use strict";

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

			var instance,
				shellElement,
				parameters = metadata.parameters,
				staticImgElement,
				animatedImgElement,
				containerElement,
				staticImage,
				animatedImage,
				timedAnimation,
				emptyImage = context.getPath() + "empty.png",
				isOnMouseMove = false,
				mode = parameters.asNumber( "mode", 1 ),
				buttonInitialized = false,
				id = metadata.getId(),
				delay = parameters.asNumber( "delay", 0 ),
				isInAuthoringMode = false,
				hasStageTriggerSupport = false,
				pointerUpEventName, pointerDownEventName, pointerMoveEventName, pointerLeaveEventName;
				
			// create an object shield so we are able to select and drag element
			function createAuthoringShield( shellElement ) {
				var authoringView = jq( document.createElement( "div" ) );

				authoringView.css( {
					"width": "100%",
					"height": "100%",
					"position": "absolute",
					"opacity": "0.15",
					"background-image": "url(\"" + context.getPath() + "invis.png\")",
					"text-align": "center",
					"line-height": metadata.getHeight() + "px",
					"font-size": "24px"
				} )
				.text( "Animated GIF" );
				shellElement.append( authoringView );
			}

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

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

			function onMouseMove() {
				if ( !isOnMouseMove) {
					if ( ( mode == 2 || mode == 6 ) ) {
						startAnimation();
					}
					fireTriggerOnMouseMove();
					isOnMouseMove = true;
                }
			}

			function onMouseLeave( e ) {
				if ( !isMouseLeaveEvent( e ) ) {
					return;
                }
				if ( mode == 3 ) {
					startAnimation();
				}
				if ( mode == 6 ) {
					stopAnimation();
				}
				isOnMouseMove = false;
				fireTriggerOnMouseLeave();
			}

			function onMouseDown( e ) {
				cancelEvent( e );
				lockNavigation();
				if ( mode == 4 ) {
					startAnimation();
				}
				fireTriggerOnMouseDown();
			}

			function onMouseUp( e ) {
				cancelEvent( e );
				unlockNavigation();

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

				if ( mode == 5 ) {
					startAnimation();
				}
				fireTriggerOnMouseUp();
			}

			function cancelEvent( e ) {
				context.device.cancelEvent( e );
			}

			function isOnTarget( e ) {

				var elem = e.target,
					origEvent = e.originalEvent,
					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 isMouseLeaveEvent( e ) {
				var event = e.toElement || e.relatedTarget;

				if ( containerElement[0].contains( event ) ) {
					return false;
				}
				return true;
			}

			function fireTriggerOnMouseMove() {
				setTimeout( function () {
					context.page.event.trigger( instance, "tg_move" );
				}, 10 );
			}

			function fireTriggerOnMouseLeave() {
				setTimeout( function () {
					context.page.event.trigger( instance, "tg_leave" );
				}, 10 );
			}

			function fireTriggerOnMouseDown() {
				setTimeout( function () {
					context.page.event.trigger( instance, "tg_down" );
				}, 10 );
			}

			function fireTriggerOnMouseUp() {
				setTimeout( function () {
					context.page.event.trigger( instance, "tg_up" );
				}, 10 );
			}

			function initPointerEventNames() {

				if ( pointerUpEventName ) {
					return;
				}

				if ( context.stage.isInPreviewMode() ) {
					pointerUpEventName = "mouseup";
					pointerDownEventName = "mousedown";
					pointerMoveEventName = "mousemove";
					pointerLeaveEventName = "mouseend mouseout";
					return;
				}

				pointerUpEventName = context.device.getUpEvents();
				pointerDownEventName = context.device.getDownEvents();
				pointerMoveEventName = context.device.getMoveEvents();
				pointerLeaveEventName = context.device.getReleaseEvents();
			}

			function bindEvents() {

				if ( isInAuthoringMode ) {
					return;
				}

				if ( !containerElement || !buttonInitialized ) {
					return;
				}

				removeEvents();
				context.device.attachFirstSupportedEvent( containerElement, pointerDownEventName, onMouseDown );
				context.device.attachFirstSupportedEvent( containerElement, pointerMoveEventName, onMouseMove );
				context.device.attachFirstSupportedEvent( containerElement, pointerLeaveEventName, onMouseLeave );
				context.device.attachFirstSupportedEvent( containerElement, pointerUpEventName, onMouseUp );
			}

			function removeEvents() {
				unlockNavigation();
				if ( !containerElement || !buttonInitialized ) {
					return;
				}

				initPointerEventNames();
				context.device.removeFirstSupportedEvent( containerElement, pointerDownEventName, onMouseDown );
				context.device.removeFirstSupportedEvent( containerElement, pointerMoveEventName, onMouseMove );
				context.device.removeFirstSupportedEvent( containerElement, pointerLeaveEventName, onMouseLeave );
				context.device.removeFirstSupportedEvent( containerElement, pointerUpEventName, onMouseUp );
			}

			function createAnimatedImage() {
				if ( buttonInitialized ) {
					return;
				}

				buttonInitialized = true;

				staticImage = parameters.get( "static_image", null ).fileName ? context.stage.getSharedPath() + parameters.get( "static_image", null ).fileName : null;
				animatedImage = parameters.get( "animated_image", null ).fileName ? context.stage.getSharedPath() + parameters.get( "animated_image", null ).fileName : null;

				containerElement = jq( document.createElement( "div" ) )
					.attr( {
						"id": "gifContainer" + id
					} )
					.css( {
						"position": "absolute",
						"width": "100%",
						"height": "100%"
					} )

				staticImgElement = jq( document.createElement( "img" ) )
					.css( {
						"position": "absolute",
						"width": "100%",
						"height": "100%",
						"display": "none"
					} )
					.attr( {
						"id": "gifStaticImg" + id,
						"src": staticImage ? staticImage : emptyImage
					} )

				animatedImgElement = jq( document.createElement( "img" ) )
					.css( {
						"position": "absolute",
						"width": "100%",
						"height": "100%",
						"display": "none"
					} )
					.attr( {
						"id": "gifAnimatedImg" + id,
						"src": emptyImage
					} )

				containerElement.append( animatedImgElement );
				containerElement.append( staticImgElement );

				shellElement.append( containerElement );

				if ( staticImage ) {
					staticImgElement.css( {
						"display": "block"
					} )
				}

				if ( mode == 1 ) {
					startAnimation();
				}
			}

			function startAnimation() {
				stopAnimation();

				if ( delay > 0 ) {
					timedAnimation = setTimeout( function () {
						showAnimatedImg();
					}, delay );
				} else {
					showAnimatedImg();
                }
			}

			function stopAnimation() {
				if ( timedAnimation ) {
					clearTimeout( timedAnimation );
					timedAnimation = null;
				}

				hideAnimatedImg();
			}

			function showAnimatedImg() {
				if ( animatedImage ) {
					animatedImgElement.attr( {
						"src": animatedImage + "?" + performance.now()
					} )
					.on( "load", function () {
						animatedImgElement.css( {
							"display": "block"
						} )
						if ( staticImage ) {
							staticImgElement.css( {
								"display": "none"
							} )
						}
					})
				}
			}

			function hideAnimatedImg() {
				if ( animatedImage ) {
					animatedImgElement.css( {
						"display": "none"
					} )
					if ( staticImage ) {
						staticImgElement.css( {
							"display": "block"
						} )
					}
				}
			}

			function removeAnimatedImage() {
				if ( animatedImgElement ) {
					stopAnimation();
					animatedImgElement.remove();
					animatedImgElement = null;
				}

				if ( staticImgElement ) {
					staticImgElement.remove();
					staticImgElement = null;
				}

				if ( containerElement ) {
					containerElement.remove();
					containerElement = null;
				}

				isOnMouseMove = false;
				buttonInitialized = null;
				staticImage = null;
				animatedImage = null;
			}

		// revealing public API
		return {
			onLoading: function () {
				instance = this;
				context.page.event.bindOnEnter( instance );
				context.page.event.bindOnExit( instance );
				hasStageTriggerSupport = !!context.stage.trigger;
				shellElement = jq( context.getElement() );
				isInAuthoringMode = !!context.stage.isInAuthoringMode();
				if ( isInAuthoringMode ) {
					createAuthoringShield( shellElement );
				}
			},
			onEnterPage: function () {
				createAnimatedImage();
				bindEvents();
			},
			onExitPage: function () {
				removeEvents();
				removeAnimatedImage();
			}
		};
	};
});
