define(['scripts/jquery-2.1.1.min'], function(jq) {
	return {
		ACTSocket: null,

		// higher is level, more important it is
		// 0 all (lock...)
		// 1 js event (resize...)
		// 2 receive message (refresh...)
		// 3 initialisation
		LogLevel: 3,
		Log: function(msg, level) {
			var level = level == null ? 0 : level;
			if (level >= this.LogLevel) {
				console.log(level + ":" + msg);
			}
		},

		Error: function(type, message) {
			console.error(type, message);

			var args = [];
			for (var i = 0; i < arguments.length; i++) {
				args.push(arguments[i]);
			}

			var obj = {
				$type: "Ansys.ACT.Core.UI.JSErrorWebObject, Ansys.ACT.Core, Culture=neutral, PublicKeyToken=null",
				ErrorType: type,
				Message: message,
				Args: args,
			}
			this.ACTSocket.send("JSError", obj);
		},

		GetOverflowsAndSetThemTo: function($elements, newOverflow) {
			var result = {}
			for (var i = 0; i < $elements.length; i++) {
				var $element = $($elements[i]);
				result[i] = [$element.css("overflow-x"), $element.css("overflow-y")];
				$element.css("overflow", newOverflow);
			}
			return result
		},

		SetOverflows: function ($elements, overflows) {
			for (var i = 0; i < $elements.length; i++) {
				var $element = $($elements[i]);
				$element.css("overflow-x", overflows[i][0]);
				$element.css("overflow-y", overflows[i][1]);
			}
		},

		GetScrollPosition: function($element) {
			return {left: $element.scrollLeft(), top: $element.scrollTop()};
		},

		SetScrollPosition: function($element, scrollInfo) {
			$element.scrollLeft(scrollInfo.left);
			$element.scrollTop(scrollInfo.top);
		},

		HasScrollBar: function($element) {
			return $element.get(0).scrollHeight > $element.height();
		},

		CreateTooltip: function($element, content, animations, options) {
			var options = options || {}
			$element.jqxTooltip({
				name: options.name || "",
				width: options.width || "auto",
				content: content,
				position: options.position || "mouse",
				autoHide: options.autoHide == null ? false : options.autoHide,
				showDelay: options.showDelay || 500,
				animationShowDelay: animations ? "fast" : 0,
				animationHideDelay: animations ? "fast" : 0,
				opacity: 1,
				disabled: options.disabled == null ? false : options.disabled,
			});
			var $newTooltips = $(".jqx-tooltip");
			$($newTooltips[$newTooltips.length - 1]).addClass("actDefault");

			$element.on("mouseleave", function(e) {
				$element.jqxTooltip("close");
			});

			$element.bind("destroyed", function() {
				$element.jqxTooltip("destroy");
			});

			return $($(".jqx-tooltip").last());
		},

		DestroyTooltip: function($element) {
			$element.jqxTooltip("destroy");
		},

		AnyElementIn: function(dict) {
			for (var key in dict) {
				return true;
			}
			return false;
		},

		StringIsNullOrEmpty: function(str) {
			return str == null || str == "";
		},

		GetPaddingSize: function($element) {
			return {
				width:  $element.outerWidth(false) - $element.width(),
				height: $element.outerHeight(false) - $element.height(),
			}
		},

		GetBorderSize: function($element) {
			var bottomBorderWidth = $element.css("border-bottom-width");
			bottomBorderWidth = bottomBorderWidth ? parseInt(bottomBorderWidth.split("px")[0]) : 0;
			var topBorderWidth = $element.css("border-top-width");
			topBorderWidth = topBorderWidth ? parseInt(topBorderWidth.split("px")[0]) : 0;
			var leftBorderWidth = $element.css("border-left-width");
			leftBorderWidth = leftBorderWidth ? parseInt(leftBorderWidth.split("px")[0]) : 0;
			var rightBorderWidth = $element.css("border-right-width");
			rightBorderWidth = rightBorderWidth ? parseInt(rightBorderWidth.split("px")[0]) : 0;

			return {
				width: leftBorderWidth + rightBorderWidth,
				height: topBorderWidth + bottomBorderWidth
			}
		},

		GetMarginSize: function($element) {
			return {
				width:  $element.outerWidth(true) - $element.outerWidth(false),
				height: $element.outerHeight(true) - $element.outerHeight(false)
			}
		},

		GetOuterSize: function($element) {
			return {
				width:  $element.outerWidth(true) - $element.width(),
				height: $element.outerHeight(true) - $element.height()
			}
		},

		OnKeyPressedReplace: function(element, evt, newChart) {
			var val = element.value;
			evt = evt || window.event;

			// Ensure we only handle printable keys, excluding enter and space
			var charCode = typeof evt.which == "number" ? evt.which : evt.keyCode;
			if (charCode && charCode > 32) {
				var keyChar = String.fromCharCode(charCode);

				// Transform typed character
				var start, end;
				if (typeof element.selectionStart == "number" && typeof element.selectionEnd == "number") {
					// Non-IE browsers and IE 9
					start = element.selectionStart;
					end = element.selectionEnd;
					element.value = val.slice(0, start) + newChart + val.slice(end);

					// Move the caret
					element.selectionStart = element.selectionEnd = start + 1;
				} else if (document.selection && document.selection.createRange) {
					// For IE up to version 8
					var selectionRange = document.selection.createRange();
					var textInputRange = element.createTextRange();
					var precedingRange = element.createTextRange();
					var bookmark = selectionRange.getBookmark();
					textInputRange.moveToBookmark(bookmark);
					precedingRange.setEndPoint("EndToStart", textInputRange);
					start = precedingRange.text.length;
					end = start + selectionRange.text.length;

					element.value = val.slice(0, start) + newChart + val.slice(end);
					start++;

					// Move the caret
					textInputRange = element.createTextRange();
					textInputRange.collapse(true);
					textInputRange.move("character", start - (element.value.slice(0, start).split("\r\n").length - 1));
					textInputRange.select();
				}

			}
		},

		UpdateOverflow: function($elements) {
			var overflows = this.GetOverflowsAndSetThemTo($elements, "hidden");
			this.SetOverflows($elements, overflows);
		},

		CallFunctions: function(functions) {
			var a = arguments;
			for (var i=0;i<functions.length;i++) {
				var func = functions[i];
				func(a[1], a[2], a[3], a[4], a[5], a[6]);
			}
		},

		StringArrayToLower: function(array) {
			var lowerArray = []
			for (var i = 0; i < array.length; i++) {
				lowerArray[i] = array[i].toLowerCase();
			}
			return lowerArray;
		},

		mousePosition: {x: 0, y: 0},
		GetMousePosition: function() {
			return this.mousePosition;
		},

		IsDraggable: function($element) {
			var instance = $element.draggable("instance");
			return typeof(instance) !== "undefined";
		},

		DestroyDraggable: function($element) {
			if (this.IsDraggable($element))
				$element.draggable("destroy");
		},

		CreateDraggable: function($element, scope) {
			this.DestroyDraggable($element);
			$element.draggable({
				appendTo: "body",
				helper: function() {
					// equivalent to helper: clone but we autorise mouse event under our draggable (mouseHover for example)
					return $(this).clone().css("pointer-events","none").appendTo("body").show();
				},
				revert: "invalid",
				scope: scope,
			});
		},

		IsDroppable: function($element) {
			var instance = $element.droppable("instance");
			return typeof(instance) !== "undefined";
		},

		DestroyDroppable: function($element) {
			if (this.IsDroppable($element))
				$element.droppable("destroy");
		},

		CreateDroppable: function($element, scope) {
			this.DestroyDroppable($element);
			$element.droppable({
				scope: scope,
			});
		},

		// itemSelector can be null, will ignore all element with the class name
		GetElementIndex: function($parent, $item, itemSelector) {
			var index = -1;
			var $children = $parent;
			while ($children.length != 0 && index == -1) {
				$children = $children.not("._IGNORE_GETELEMENTINDEX_");
				var index = jQuery.makeArray($children).indexOf($item[0]);
				$children = $children.children(itemSelector);
			}

			return index;
		},

		BetterMultiLevelSort: function(event, ui, $element) {
			var sortable = $element.sortable("instance");
			if (typeof(sortable) !== "undefined") {
				// ! here I will use fiew jquery's sortable attribute / methods
				var items = sortable.items;
				if (items.length < 2)
					return;

				var cursor = {
					left: sortable.positionAbs.left + sortable.offset.click.left,
					top: sortable.positionAbs.top + sortable.offset.click.top,
				};

				// found the closests items by direction
				var closests = {up: null, down: null, left: null, right: null};
				for (i = 0; i < items.length; i++) {
					var item = items[i];
					var $item = item.item;

					// sometimes these values are not up to date
					item.left   = $item.offset().left;
					item.top    = $item.offset().top;
					item.width  = $item.outerWidth();
					item.height = $item.outerHeight();

					if (item == sortable.currentItem[0] || $item[0] == ui.helper[0])
						continue;

					item.down  = item.top  + item.height;
					item.right = item.left + item.width;

					item.dUp    = cursor.top  - item.down;
					item.dLeft  = cursor.left - item.right;
					item.dDown  = item.top    - cursor.top;
					item.dRight = item.left   - cursor.left;

					// if we are in the item distance are inversed
					if (cursor.top > item.top && cursor.top < item.down) {
						var tmp = -item.dUp;
						item.dUp = -item.dDown;
						item.dDown = tmp;
					}
					if (cursor.left > item.left && cursor.left < item.right) {
						var tmp = -item.dLeft;
						item.dLeft = -item.dRight;
						item.dRight = tmp;
					}

					if (item.dUp    > 0 && (closests.up    == null || item.dUp    < closests.up.dUp))
						closests.up = item;
					if (item.dLeft  > 0 && (closests.left  == null || item.dLeft  < closests.left.dLeft))
						closests.left = item;
					if (item.dDown  > 0 && (closests.down  == null || item.dDown  < closests.down.dDown))
						closests.down = item;
					if (item.dRight > 0 && (closests.right == null || item.dRight < closests.right.dRight))
						closests.right = item;
				}

				// place the placeholder next to the deepest or closest item
				var up,down, dUp, dDown;
				if (sortable.option().axis == "x") {
					up    = closests.left;
					down  = closests.right;
					dUp   = up ? up.dLeft : 0;
					dDown = down ? down.dRight : 0;
				} else {
					up    = closests.up;
					down  = closests.down;
					dUp   = up ? up.dUp : 0;
					dDown = down ? down.dDown : 0;
				}

				var insertBefore;
				if (up == null)        insertBefore = true;
				else if (down == null) insertBefore = false;
				else
				{
					var upDepth   = up.item.parents().length;
					var downDepth = down.item.parents().length;

					if (upDepth == downDepth)
						insertBefore = dUp < dDown;
					else
						insertBefore = upDepth < downDepth;
				}

				if (insertBefore)
					ui.placeholder.insertBefore(down.item);
				else
					ui.placeholder.insertAfter(up.item);
			}
		},

		CaptureAndKeepClick: function() {
			this.captureClick = true;
		},

		TriggerKeepedClick: function() {
			this.captureClick = false;
			this.candidateClickEvent = null;
			if (this.clickEvent) {
				var keepedEvent = this.clickEvent;
				if (keepedEvent.button == 0)  // works with 1 at left click at one time. Now left click is 0...
				{
					var e = new jQuery.Event("click");
					e.pageX = keepedEvent.pageX;
					e.pageY = keepedEvent.pageY;
					e.clientX = keepedEvent.clientX;
					e.clientY = keepedEvent.clientY;
					e.target = keepedEvent.target;
					$(e.target).trigger(e);
				}

				this.clickEvent = null;
			}
		},

		Clamp: function(v, min, max) {
			return Math.min(Math.max(v, min), max);
		},

		PositionIsInElement: function($e, x, y) {
			var r = $e[0].getBoundingClientRect();
			return x > r.left && x < r.right && y > r.top && y < r.bottom;
		},

		// return true if $a contain $b in term of box
		ElementBoxContainsElementBox: function($a, $b) {
			var ra = $a[0].getBoundingClientRect();
			var rb = $b[0].getBoundingClientRect();
			return rb.left >= ra.left && rb.right <= ra.right
				&& rb.top >= ra.top && rb.bottom <= ra.bottom;
		},

		// to avoid useless refresh of panels
		ListOfComponentAreEqual: function(la, lb) {
			if (la.length != lb.length)
				return false;
			for (var i = 0; i < la.length; i++) {
				if (la[i].Model.Id != lb[i].Model.Id)
					return false;
			}
			return true;
		},

		// in case the css won't do it. Return the text ellipsed.
		ApplyEllipsis: function($element, text, maxHeight) {
			/*
				fix for the ellipis probleme
				if text-overflow: ellispsis work again just use it and remove that code
			*/

			// we need to move the element to an other place in case he's not visible yet
			var oldPosStyle = $element[0].style.position;
			$element.css("position", "absolute");
			// in case the width is specify
			var oldWidthStyle = $element[0].style.width;
			$element.css("width", "auto");

			$element.text("");
			var result = text;
			for (var i = 0; i < text.length; i++) {
				$element.text($element.text() + text[i]);
				if ($element.width() > $element.parent().width() ||
				   (maxHeight && $element.height() > maxHeight))
				{
					// remove 4 last letter and add 3 dots instead
					var titleText = $element.text();
					titleText = titleText.substr(0, titleText.length - 4) + "...";
					$element.text(titleText);
					result = titleText;
					break;
				}
			}
			$element.css("position", oldPosStyle);
			$element.css("width", oldWidthStyle);
			return result;
		},
	}
});
