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

	"use strict";

	function SourceElementBuilder( context, metadata, offsetService ){

		var parameters = metadata.parameters,
			isStandardPlayer = context.getPlayerName() === "standard",

			colors = getColors(),

			positioningDiv = jq(context.getPositioningElement()),
			backgroundImage,

			cssIndexAlwaysOnTop = metadata.parameters.asBool("z_index_always_on_top", true),
			cssIndexForDragging = "1000",
			cssIndexMemory = null,

			fonts = [
				'Arial, Helvetica, sans-serif',
				'"Times New Roman", Times, serif',
				'Verdana, Geneva, sans-serif',
				'"Courier New", Courier, monospace',
				'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif',
				'"Droid Serif", "Times New Roman", Times, serif'
			];

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

		function getCoreStyles() {
			return {
				"cursor": "default",
				"width": metadata.getWidth() + "px",
				"height":  metadata.getHeight() + "px"
			};
		}

		function createStartArea() {

			var borderSize = parameters.asNumber("border-size", 2),
				borderSizeAM = parameters.asNumber("border-size-am", 2),
				isAssessmentMode = context.stage.isInAssessmentMode(),
				setDifferentAssessmentDesign = (isAssessmentMode && parameters.asBool("different-assessment-design")) ? true : false,
				startDiv = jq(document.createElement("div"))
				.addClass("drag_start_element")
				.css({
					"width": (metadata.getWidth() - (2 * (setDifferentAssessmentDesign ? borderSizeAM : borderSize))) + "px",
					"height": (metadata.getHeight() - (2 * (setDifferentAssessmentDesign ? borderSizeAM : borderSize))) + "px",
					"position": "absolute",
					//"border" : context.stage.isInAuthoringMode() ? "0" : "1px dotted #ff0000",
					"z-index" : "1"
				}),
			  positioningElement = jq(context.getPositioningElement()),
			  downEvents = context.device.getDownEvents( positioningElement.get(0).nodeName ),
			  onFirstPointerDown = function(){
				  initializeStartArea( startDiv );
				  positioningElement.off( downEvents, onFirstPointerDown );
			  };

			positioningElement.on( downEvents, onFirstPointerDown );

			return startDiv;
		}

		function initializeStartArea( startDiv ){
			var positioningElement = context.getPositioningElement();
			offsetService.setGlobalOffset( startDiv, offsetService.getGlobalOffset( positioningElement ) );
		}

		function createDragSourceElement() {

			var fontFamily = parameters.asNumber("font-family", 0),
				fontSize = parameters.get("font-size", "14") + "px",
				borderSize = parameters.asNumber("border-size", 2),
				borderSizeAM = parameters.asNumber("border-size-am", 2),
				dragDiv = jq(document.createElement("div")),
				isAssessmentMode = context.stage.isInAssessmentMode(),
				setDifferentAssessmentDesign = (isAssessmentMode && parameters.asBool("different-assessment-design")) ? true : false;

			dragDiv.addClass("drag_element")
			  .html( parameters.get("text", ""))
			  .css({
				  "width": metadata.getWidth() + "px",
				  "height":  metadata.getHeight() + "px",
				  "position": "absolute",
				  "cursor" : "pointer",
				  "z-index" : "1",
				  "font-family": getFont(fontFamily),
				  "font-size": fontSize,
				  "font-weight": "bold",
				  "font-style": "normal",
				  "color": parameters.get("color", "#919191"),
				  "line-height": fontSize,
				  "padding-left": (parameters.asNumber("padding-left", 15) - borderSize) + "px",
				  "padding-right": (parameters.asNumber("padding-right", 15) - borderSize) + "px",
				  "padding-top": (parameters.asNumber("padding-top", 15) - borderSize) + "px",
				  "text-align": parameters.get("text_orientation", "center"),
				  "background-color": colors.default.background,
				  "box-sizing": "border-box",
				  "-webkit-tap-highlight-color": "rgba(0,0,0,0)",
				  "outline": "0 none", // TTPS-16468
				  "box-shadow": "0 0 1px rgba(0, 0, 0, 0.05)" // TTPS-16468
			  });

			if (setDifferentAssessmentDesign) {
				dragDiv.css({
					"border": (borderSizeAM !== 0) ? borderSizeAM + "px solid " + colors.default.border : 0
				})
			} else {
				dragDiv.css({
					"border": (borderSize !== 0) ? borderSize + "px solid " + colors.default.border : 0
				})
			}

			backgroundImage = createBackgroundImageModel( dragDiv );

			return dragDiv;
		}

		function setZIndexForDragging(){

			if( !cssIndexAlwaysOnTop && !cssIndexMemory ){
				cssIndexMemory = positioningDiv.css("z-index");
			}

			positioningDiv.css({
				"z-index" :  cssIndexForDragging
			});
		}

		function restoreZIndex(){

			if( cssIndexAlwaysOnTop || !cssIndexMemory ){
				return;
			}

			positioningDiv.css({
				"z-index" : cssIndexMemory
			});

			cssIndexMemory = null;
		}

		function getColors() {
			var isAssessmentMode = context.stage.isInAssessmentMode(),
				setDifferentAssessmentDesign = (isAssessmentMode && parameters.asBool("different-assessment-design")) ? true : false;

			return setDifferentAssessmentDesign ? {
				"default" : {
					"border": asRgbaValue("border-color-am", "#cccccc", "border-transparency-am"),
					"background": asRgbaValue("background-color-am", "#cccccc", "background-transparency-am")
				},
				"solvedCorrect" : {
					"border": asRgbaValue("border-color-correct-am", "#74b65b", "border-transparency-am"),
					"background": asRgbaValue("background-color-correct-am", "#cccccc", "background-transparency-am")
				},
				"solvedWrong" : {
					"border": asRgbaValue("border-color-incorrect-am", "#74b65b", "border-transparency-am"),
					"background": asRgbaValue("background-color-incorrect-am", "#cccccc", "background-transparency-am")
				},
				"bestPractice" : {
					"border": asRgbaValue("border-color-best-solution-am", "#74b65b", "border-transparency-am"),
					"background": asRgbaValue("background-color-best-solution-am", "#cccccc", "background-transparency-am")
				}
			} : {
				"default": {
					"border": asRgbaValue("border-color", "#cccccc", "border-transparency"),
					"background": asRgbaValue("background-color", "#cccccc", "background-transparency")
				},
				"solvedCorrect": {
					"border": asRgbaValue("border-color-correct", "#74b65b", "border-transparency"),
					"background": asRgbaValue("background-color-correct", "#cccccc", "background-transparency")
				},
				"solvedWrong": {
					"border": asRgbaValue("border-color-incorrect", "#74b65b", "border-transparency"),
					"background": asRgbaValue("background-color-incorrect", "#cccccc", "background-transparency")
				},
				"bestPractice": {
					"border": asRgbaValue("border-color-best-solution", "#74b65b", "border-transparency"),
					"background": asRgbaValue("background-color-best-solution", "#cccccc", "background-transparency")
				}
			};
		}

		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 createBackgroundImageModel( jqElement ) {

			var backgroundImage = metadata.parameters.get("bg_image", null),
                backgroundImageAssessment = metadata.parameters.get( "bg_image_assessment", null ),
			  backgroundFileName = "",
			  bgHeight = 0,
                bgLayer = jqElement,
                isAssessmentMode = context.stage.isInAssessmentMode();

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

			if (backgroundImage) {
				backgroundFileName = context.stage.getSharedPath() + backgroundImage.fileName;
				bgHeight = backgroundImage.height / 7;

				if( backgroundFileName && backgroundFileName.length > 0 ){
					bgLayer.css({
						"background-image": "url(\"" + backgroundFileName + "\")",
						"background-position" :"0px 0px"
					});
				}
			}

			return {
				setDefaultStyle : function(){
					bgLayer.css("background-position", "0px 0px");
				},
				setMouseOverStyle : function(){
					bgLayer.css("background-position", "0px -" + bgHeight + "px");
				},
				setDragStyle : function(){
					bgLayer.css("background-position", "0px -" + 2 * bgHeight + "px");
				},
				setOnTargetStyle : function(){
					bgLayer.css("background-position", "0px -" + 3 * bgHeight + "px");
				},
				setCorrectStyle : function(){
					bgLayer.css("background-position", "0px -" + 4 * bgHeight + "px");
				},
				setWrongStyle : function(){
					bgLayer.css("background-position", "0px -" + 5 * bgHeight + "px");
				},
				setBestPracticeStyle : function(){
					bgLayer.css({
						"cursor": "default",
						"background-position": "0px -" + 6 * bgHeight + "px"
					});
				}
			};
		}

		function reorderChildren( parent ) {

			reorderChildrenZIndex();

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

			// Give the html4 player a little bit time, to setup images by javascript.
			// Otherwise images will be displayed in black.
			if( isStandardPlayer ) {
				setTimeout(function () {
					reorderChildrenHirachy(parent);
				}, 200 );
				return;
			}

			reorderChildrenHirachy( parent );
		}

		function reorderChildrenZIndex(){

			var children = context.getChildren(),
			  jqChild;

			jq.each( children, function( index, childElement ){

				jqChild = jq( childElement );
				jqChild.css({
					"z-index" : "10",
					"pointer-events" : "none"
				});
			});
		}

		return {
			build : function(){

				reorderChildrenZIndex();

				var shellElement = jq(context.getElement()),
				  positioningElement = jq(context.getPositioningElement()),
				  scStage = jq(context.getSCLayer()),
				  startDiv = createStartArea(),
				  sourceUIDiv = createDragSourceElement(),
				  animating = false;

				scStage.append( startDiv );
				initializeStartArea( startDiv );

				shellElement
				  .css( getCoreStyles() )
				  .append( sourceUIDiv );

				if( context.stage.isInAuthoringMode() ) {

					startDiv.css({
						"width": "100%",
						"height": "100%"
					});

					sourceUIDiv.css({
						"width": "100%",
						"height": "100%"
					});
				}
				else {

					if( cssIndexAlwaysOnTop ){
						positioningDiv.css({
							"z-index" :  cssIndexForDragging
						});
					}
				}

				removePointerEvents();

				function removePointerEvents(){
					positioningDiv.css({"pointer-events" : "none"});
					shellElement.css({"pointer-events" : "none"});
					startDiv.css({"pointer-events" : "none"});
					sourceUIDiv.css({"pointer-events" : "auto"});

					// to prevent "swipe to go back" on touch devices like phone or tablets.
					positioningDiv.css({"touch-action" : "none"});
					shellElement.css({"touch-action" : "none"});
					startDiv.css({"touch-action" : "none"});
				}

				function moveToOffset ( offset, skipAnimation ) {
					var duration = 400;

					if( skipAnimation ){
						duration = 0;
					}

					var desitinationOffset = offsetService.removeGroupOffset(positioningElement, offset),
					  onTransitionStart = function () {
						  animating = true;
						  /* TTPS-23960 Drag&Drop SmartComponents can't be dragged anymore if inside a step template in HTML4
						   * In some rare html4-player cases, the TransitionEnd-Event is not fired.
						   * So we use a timeout to ensure the release of animating control var.
						   */
						  setTimeout(function() {
							  animating = false;
						  }, duration + 10 )
					  },
					  onTransitionEnd = function () {
						  jq(this)
							.off("transitionstart webkitTransitionStart oTransitionStart", onTransitionStart)
							.off("transitionend webkitTransitionEnd oTransitionEnd", onTransitionEnd)
							.css({
								"transition-property": "",
								"transition-duration": "",
								"transition-timing-function": ""
							});
					  };
					positioningElement
					  .on("transitionstart webkitTransitionStart oTransitionStart", onTransitionStart)
					  .on("transitionend webkitTransitionEnd oTransitionEnd", onTransitionEnd)
					  .css({
						  "left": desitinationOffset.left + "px",
						  "top": desitinationOffset.top + "px",
						  "transition-property": "left, top",
						  "transition-duration": (duration / 1000) + "s",
						  "transition-timing-function": "cubic-bezier(.02, .01, .47, 1)"
					  });
				}

				return{
					initialize : function(){
						animating = false;
					},
					isInAnimation : function(){
						return animating;
					},
					setOffset : function( offset ){
						offsetService.setGlobalOffset( positioningElement.get(0), offset );
					},
					moveToOffset : moveToOffset,
					moveToStartOffset : function( skipAnimation ) {
						moveToOffset( offsetService.getGlobalOffset( startDiv ), skipAnimation );
					},

					getDragDiv : function() {
						return positioningElement;
					},

					setDragStyle : function(){
						setZIndexForDragging();
						backgroundImage.setDragStyle();
					},
					setDroppedStyle : function( isOnTarget ){

						sourceUIDiv.css({
							"cursor": "pointer"
						});

						isOnTarget ? backgroundImage.setOnTargetStyle() : backgroundImage.setDefaultStyle();

						restoreZIndex();
					},
					clearCursorStyle : function(){
						sourceUIDiv.css({
							"cursor" : "pointer !important"
						});
					},
					setUserSolutionStyle : function( isDroppedCorrectly ) {

						sourceUIDiv.css({
							"cursor": "default",
							"border-color": isDroppedCorrectly ? colors.solvedCorrect.border : colors.solvedWrong.border,
							"background-color": isDroppedCorrectly ? colors.solvedCorrect.background : colors.solvedWrong.background
						});

						isDroppedCorrectly ? backgroundImage.setCorrectStyle() : backgroundImage.setWrongStyle();
					},
					setBestPracticeSolutionStyle : function(){

						sourceUIDiv.css({
							"cursor": "default",
							"border-color" : colors.bestPractice.border,
							"background-color" : colors.bestPractice.background
						});
						backgroundImage.setBestPracticeStyle();
					},

					setMouseOverStyle : function() {
						backgroundImage.setMouseOverStyle();
					},

					resetStyle : function() {
						sourceUIDiv.css({
							"border-color": colors.default.border,
							"background-color": colors.default.background
						});
						backgroundImage.setDefaultStyle();
					}
				}
			}
		}
	}

	return SourceElementBuilder;
});
