/**
 * Fix for IE11 by sencha
 * https://www.sencha.com/forum/showthread.php?281297-Ext.util.CSS.createStyleSheet-fails-in-IE11.
 */
Ext.util.CSS.createStyleSheet = function (cssText, id) {
	var CSS = this,
	    doc = document;
	var ss,
	    head = doc.getElementsByTagName("head")[0],
	    styleEl = doc.createElement("style");
	styleEl.setAttribute("type", "text/css");
	if (id) {
		styleEl.setAttribute("id", id);
	}
	try {
		styleEl.appendChild(doc.createTextNode(cssText));
	} catch (e) {
		styleEl.cssText = cssText;
	}
	head.appendChild(styleEl);
	ss = styleEl.styleSheet ? styleEl.styleSheet : styleEl.sheet || doc.styleSheets[doc.styleSheets.length - 1];
	CSS.cacheStyleSheet(ss);
	return ss;
};

Ext.ns("Terrasoft.utils.dom");

/**
 * @singleton
 */

/**
 * Returns the length of the selected text if the text is not selected - returns zero
 * @param {HTMLElement} el HTML element in which the selected text is present
 * @return {Number} length of the selected text
 */
Terrasoft.utils.dom.getSelectedTextLength = function (el) {
	var selectedText = "";
	if (el.selectionStart != null && el.selectionEnd != null) {
		var start = el.selectionStart;
		var end = el.selectionEnd;
		selectedText = el.value.substring(start, end);
	} else if (document.selection) {
		selectedText = document.selection.createRange().text;
	}
	return selectedText.length;
};

/**
 * Sets attribute value to body attribute.
 * @param {String} attribute Attribute.
 * @param {Mixed} value Attribute value.
 */
Terrasoft.utils.dom.setAttributeToBody = function (attribute, value) {
	var body = Ext.getBody();
	if (!body) {
		return;
	}
	var dataAttribute = {};
	dataAttribute[attribute] = value;
	body.set(dataAttribute);
};

/**
 * Checks whether the dom-element contains an el css class named className.
 * @param {HTMLElement} el dom-element in which the presence of the class is checked.
 * @param {String} className A string containing the names of the css class to search for.
 * @return {Boolean} true if the class with the specified name finds, false - if not found.
 */
Terrasoft.utils.dom.hasClassName = function (el, className) {
	return el.className.indexOf(className) !== -1;
};

/**
 * Adds css class to the html element.
 * @param {HTMLElement} el Html element.
 * @param {String} className Name of css class.
 */
Terrasoft.utils.dom.addClassName = function (el, className) {
	var classNames = el.className.split(/\s/);
	if (classNames.indexOf(className) === -1) {
		classNames.push(className);
		el.className = classNames.join(" ");
	}
};

/**
 * Removes the css class of html element.
 * @param {HTMLElement} el Html element.
 * @param {String} className Name of css class.
 */
Terrasoft.utils.dom.removeClassName = function (el, className) {
	var classNames = el.className.split(/\s/);
	var index = classNames.indexOf(className);
	if (index !== -1) {
		classNames.splice(index, 1);
		el.className = classNames.join(" ");
	}
};

/**
 * Returns the current position of the carriage, the count is from left to right
 * @param {HTMLElement} el HTML element in which the carriage is located
 * @return {Number} number of characters before the carriage
 */
Terrasoft.utils.dom.getCaretPosition = function (el) {
	var cursorPos = null;
	if (document.selection) {
		var range = document.selection.createRange();
		range.moveStart("textedit", -1);
		cursorPos = range.text.length;
	} else {
		cursorPos = el.selectionStart;
	}
	return cursorPos;
};

/**
 * Sets the carriage to the pos position
 * @param {HTMLElement} ctrl HTML element in which the card is inserted
 * @param {Number} pos The location in which the card is inserted
 */
Terrasoft.utils.dom.setCaretPosition = function (ctrl, pos) {
	if (ctrl.setSelectionRange) {
		ctrl.focus();
		ctrl.setSelectionRange(pos, pos);
	} else if (ctrl.createTextRange) {
		var range = ctrl.createTextRange();
		range.collapse(true);
		range.moveEnd("character", pos);
		range.moveStart("character", pos);
		range.select();
	}
};

/**
 * Returns only visible items from items array.
 * @param {Array} items Array of DOM nodes.
 * @param {Array} excludeNodes Array of DOM nodes to exclude from result.
 * @return {Array} Array of visible items.
 */
Terrasoft.utils.dom.getVisibleDomItems = function (items, excludeNodes) {
	var visibleItems = [];
	var exclude = excludeNodes || [];
	for (var i = 0, length = items.length; i < length; i++) {
		var item = items[i];
		if (exclude.indexOf(item) !== -1) {
			continue;
		}
		if (item.style.display !== "none") {
			visibleItems.push(item);
		}
	}
	return visibleItems;
};

/**
 * @member Terrasoft
 * @method getVisibleDomItems
 * @inheritdoc Terrasoft.utils.dom#getVisibleDomItems
 */
Terrasoft.getVisibleDomItems = Terrasoft.utils.dom.getVisibleDomItems;

/**
 * Converts from Em to Px.
 * @param {Number | String} value in Em. Can be passed as a number and a string. String value
 * should not contain spaces.
 * @throws {Terrasoft.NotImplementedException} An exception is thrown when the value in
 * wrong format, or not a number.
 * @return {Number}
 **/
Terrasoft.utils.dom.convertEmToPx = function (value) {
	var unitRe = /([+-]?\d*([.,]\d*)?)(px|em|%|en|ex|pt|in|cm|mm|pc)?$/i;
	var valueType = typeof value;
	var emValue = value;
	if (valueType === "string") {
		var unitData = unitRe.exec(value);
		if (!unitData) {
			throw new Terrasoft.UnsupportedTypeException();
		}
		var stringValue = unitData[1];
		stringValue = stringValue.replace(",", ".");
		emValue = parseFloat(stringValue);
		if (isNaN(emValue)) {
			throw new Terrasoft.UnsupportedTypeException();
		}
	} else if (valueType !== "number") {
		throw new Terrasoft.UnsupportedTypeException();
	}
	var body = Ext.getBody();
	var fontSizeStyle = body.getStyle("fontSize");
	var fontSizeData = unitRe.exec(fontSizeStyle);
	var fontSize = parseFloat(fontSizeData[1]);
	return fontSize * emValue;
};

/**
 * @member Terrasoft
 * @method convertEmToPx
 * short notation for {@link Terrasoft.utils.dom#convertEmToPx}
 * @inheritdoc Terrasoft.utils.dom#convertEmToPx
 */
Terrasoft.convertEmToPx = Terrasoft.utils.dom.convertEmToPx;

/**
 * Calculates the lineHeight property for the DOM tree element.
 * Some browsers (WebKit), return the "normal" value  if the lineHeight property is not overridden by styles.
 * The method calculates this property using a fake element.
 * @param {Ext.dom.Element} el The element for which you want to calculate.
 * @throws {Terrasoft.ArgumentNullOrEmptyException} An exception is thrown when the argument is not passed.
 * @return {Number} The value of the lineHeight property
 **/
Terrasoft.utils.dom.getLineHeight = function (el) {
	if (!el || !el.dom) {
		throw new Terrasoft.ArgumentNullOrEmptyException();
	}
	var node = el.dom;
	var cloneElement = node.cloneNode();
	cloneElement.innerHTML = "<br>";
	node.appendChild(cloneElement);
	var singleLineHeight = cloneElement.offsetHeight;
	cloneElement.innerHTML = "<br><br>";
	var doubleLineHeight = cloneElement.offsetHeight;
	node.removeChild(cloneElement);
	var lineHeight = doubleLineHeight - singleLineHeight;
	return lineHeight;
};

/**
 * @member Terrasoft
 * @method convertEmToPx
 * short notation for {@link Terrasoft.utils.dom#getLineHeight}
 * @inheritdoc Terrasoft.utils.dom#getLineHeight
 */
Terrasoft.getLineHeight = Terrasoft.utils.dom.getLineHeight;

/**
 * Converts DOM-node to Canvas.
 * @param {String} elementId Node Id.
 * @param {Object} options Options config.
 * Available options http://html2canvas.hertzen.com/documentation.html
 * @param {Function} callback Callback function.
 * @param {Object} scope Scope of callback function.
 * @return {Canvas} Canvas object.
 */
Terrasoft.utils.dom.convertElementToCanvas = function (elementId, options, callback, scope) {
	var createClone = function (elementId) {
		var clone;
		var element = $("#" + elementId);
		if (element) {
			var elementFirst = element.first();
			clone = elementFirst.clone(true);
			clone.insertBefore(element);
			element.attr("id", elementId + "_Origin");
			element.hide();
		}
		return clone;
	};

	var removeClone = function (elementId) {
		var element = $("#" + elementId + "_Origin");
		if (element) {
			var clone = $("#" + elementId);
			if (clone.length) {
				clone.remove();
			}
			if (element.length) {
				element.attr("id", elementId);
				element.show();
			}
		}
	};

	var convertSvgToCanvas = function (elementId) {
		var element = Ext.get(elementId);
		if (element) {
			var canvas = document.createElement("canvas");
			canvas.width = $(element).attr("width");
			canvas.height = $(element).attr("height");
			var ctx = canvas.getContext("2d");
			var img = document.createElement("img");
			img.onload = function () {
				ctx.drawImage(img, 0, 0);
			};
			var imgSrcTpl = "data:image/svg+xml;base64,{0}";
			var xmlSerializer = new XMLSerializer();
			var svgString = xmlSerializer.serializeToString(element.dom);
			var encodedURIComponent = encodeURIComponent(svgString);
			img.setAttribute("src", Ext.String.format(imgSrcTpl, btoa(window.unescape(encodedURIComponent))));
			return canvas;
		}
	};

	var replaceSvgElements = function (element) {
		var svgElements = $(element).find("svg");
		for (var i = 0; i < svgElements.length; i++) {
			var svgElement = svgElements[i];
			var canvas = convertSvgToCanvas(svgElement);
			$(svgElement).replaceWith(canvas);
		}
	};

	var element = document.getElementById(elementId);
	if (element) {
		var clone = createClone(elementId);
		replaceSvgElements(clone);
		var executeOptions = {
			onrendered: function (canvas) {
				removeClone(elementId);
				callback.call(scope, canvas);
			}
		};
		html2canvas(clone, Ext.apply(executeOptions, options || {}));
	} else {
		callback.call(scope);
	}
};

/**
 * @member Terrasoft
 * @method convertElementToCanvas
 * short notation for {@link Terrasoft.utils.dom#convertElementToCanvas}
 * @inheritdoc Terrasoft.utils.dom#convertElementToCanvas
 */
Terrasoft.convertElementToCanvas = Terrasoft.utils.dom.convertElementToCanvas;

/**
 * Returns topScroll value.
 * @return {Number} ScrollTop value.
 */
Terrasoft.utils.dom.getTopScroll = function () {
	var body = Ext.getBody();
	return body.getScrollTop();
};

/**
 * @member Terrasoft.
 * @method getTopScroll.
 * Reduction for {@link Terrasoft.utils.dom#getTopScroll}.
 * @inheritdoc Terrasoft.utils.dom#getTopScroll.
 */
Terrasoft.getTopScroll = Terrasoft.utils.dom.getTopScroll;

/**
 * Sets topScroll value.
 * @param {Number} value ScrollTop value.
 */
Terrasoft.utils.dom.setTopScroll = function (value) {
	if (!Ext.isEmpty(value)) {
		var body = Ext.getBody();
		body.setScrollTop(value);
		if (body.dom.scrollTop === 0) {
			document.documentElement.scrollTop = value;
		}
	}
};

/**
 * @member Terrasoft.
 * @method setTopScroll.
 * Reduction for {@link Terrasoft.utils.dom#setTopScroll}.
 * @inheritdoc Terrasoft.utils.dom#setTopScroll.
 */
Terrasoft.setTopScroll = Terrasoft.utils.dom.setTopScroll;

/**
 * Scrolls to element if it is not visible on the screen.
 * @param {Ext.dom.Element} el DOM Element.
 * @param {Ext.dom.Element} [parentEl] DOM parent of Element.
 */
Terrasoft.utils.dom.scrollToEl = function (el, parentEl, scrollParent) {
	if (!Ext.isEmpty(el)) {
		parentEl = parentEl || el.parent();
		var parent = scrollParent ? parentEl : Ext.getBody();
		var parentViewRegion = parentEl.getViewRegion();
		var visibleTop = parentViewRegion.top;
		var visibleBottom = parentViewRegion.bottom;
		if (el.getTop() < visibleTop || el.getBottom() > visibleBottom) {
			var yOfffset = el.getOffsetsTo(parentEl);
			parent.setScrollTop(yOfffset[1]);
		}
	}
};

/**
 * @member Terrasoft.
 * @method scrollToEl.
 * Reduction for {@link Terrasoft.utils.dom#scrollToEl}.
 * @inheritdoc Terrasoft.utils.dom#scrollToEl.
 */
Terrasoft.scrollToEl = Terrasoft.utils.dom.scrollToEl;

/**
 * Removes a style or link tag by id.
 * @param {String} id Style id.
 */
Terrasoft.utils.dom.removeStyleSheet = function (id) {
	Ext.util.CSS.removeStyleSheet(id);
};

/**
 * @member Terrasoft.
 * @method removeStyleSheet.
 * Reduction for {@link Terrasoft.utils.dom#removeStyleSheet}.
 * @inheritdoc Terrasoft.utils.dom#removeStyleSheet.
 */
Terrasoft.removeStyleSheet = Terrasoft.utils.dom.removeStyleSheet;

/**
 * Updates CSS rule.
 * @param {String} cssSelector CSS selector.
 * @param {String} cssProperty Name of CSS property.
 * @param {String} cssValue Value of CSS property.
 */
Terrasoft.utils.dom.updateStyleSheet = function () {
	Ext.util.CSS.updateRule.apply(Ext.util.CSS, arguments);
};

/**
 * @member Terrasoft.
 * @method updateStyleSheet.
 * Reduction for {@link Terrasoft.utils.dom#updateStyleSheet}.
 * @inheritdoc Terrasoft.utils.dom#updateStyleSheet.
 */
Terrasoft.updateStyleSheet = Terrasoft.utils.dom.updateStyleSheet;

/**
 * Refreshes CSS cache.
 */
Terrasoft.utils.dom.refreshStyleSheetCache = function () {
	Ext.util.CSS.refreshCache();
};

/**
 * @member Terrasoft.
 * @method refreshStyleSheetCache.
 * Reduction for {@link Terrasoft.utils.dom#refreshStyleSheetCache}.
 * @inheritdoc Terrasoft.utils.dom#refreshStyleSheetCache.
 */
Terrasoft.refreshStyleSheetCache = Terrasoft.utils.dom.refreshStyleSheetCache;

/**
 * Dynamically creates stylesheets from a text blob of rules.
 * The text will wrapped in a style tag and appended to the HEAD of the document.
 * @param {String} cssText The text containing the css rules.
 * @param {String} id An id to add to the stylesheet for later removal.
 */
Terrasoft.utils.dom.createStyleSheet = function (cssText, id) {
	Ext.util.CSS.createStyleSheet(cssText, id);
};

/**
 * @member Terrasoft.
 * @method createStyleSheet.
 * Reduction for {@link Terrasoft.utils.dom#createStyleSheet}.
 * @inheritdoc Terrasoft.utils.dom#createStyleSheet.
 */
Terrasoft.createStyleSheet = Terrasoft.utils.dom.createStyleSheet;

/**
 * Creates new or replaces existing stylesheet.
 * @param {String} cssSelector Css selector.
 * @param {String} cssProperty Name of CSS property.
 * @param {String} cssValue Value of CSS property.
 * @param {String} id Id for later removal.
 */
Terrasoft.utils.dom.appendStyleSheet = function (cssSelector, cssProperty, cssValue, id) {
	var rule = Ext.util.CSS.getRule(cssSelector, true);
	if (rule) {
		Terrasoft.updateStyleSheet(cssSelector, cssProperty, cssValue);
	} else {
		var cssText = Ext.String.format("{0} {{1}: {2};}", cssSelector, cssProperty, cssValue);
		Terrasoft.createStyleSheet(cssText, id);
	}
};

/**
 * @member Terrasoft.
 * @method appendStyleSheet.
 * Reduction for {@link Terrasoft.utils.dom#appendStyleSheet}.
 * @inheritdoc Terrasoft.utils.dom#appendStyleSheet.
 */
Terrasoft.appendStyleSheet = Terrasoft.utils.dom.appendStyleSheet;

/**
 * Removes stylsheet if exists and recreates it.
 * @param {String} cssSelector Css selector.
 * @param {String} cssProperty Name of CSS property.
 * @param {String} cssValue Value of CSS property.
 * @param {String} id Id for later removal.
 */
Terrasoft.utils.dom.reCreateStyleSheet = function (cssSelector, cssProperty, cssValue, id) {
	Terrasoft.removeStyleSheet(id);
	var cssText = Ext.String.format("{0} {{1}: {2};}", cssSelector, cssProperty, cssValue);
	Terrasoft.createStyleSheet(cssText, id);
};

/**
 * @member Terrasoft.
 * @method reCreateStyleSheet.
 * Reduction for {@link Terrasoft.utils.dom#reCreateStyleSheet}.
 * @inheritdoc Terrasoft.utils.dom#reCreateStyleSheet.
 */
Terrasoft.reCreateStyleSheet = Terrasoft.utils.dom.reCreateStyleSheet;

/**
 * Lightens color if percent value is positive or darkens if percent value is negative.
 * @param {String} color Color in #RRGGBB representation.
 * @param {Number} percent Shading percent from -1 to 1.
 * @return {String} New colot in #RRGGBB representation.
 */
Terrasoft.utils.dom.shadeColor = function (color, percent) {
	var floor = percent < 0 ? 0 : 255;
	percent = percent < 0 ? percent * -1 : percent;
	var hexRed = color.slice(1, 3);
	var hexGreen = color.slice(3, 5);
	var hexBlue = color.slice(5);
	var red = parseInt(hexRed, 16);
	var green = parseInt(hexGreen, 16);
	var blue = parseInt(hexBlue, 16);
	red = Math.round((floor - red) * percent) + red;
	green = Math.round((floor - green) * percent) + green;
	blue = Math.round((floor - blue) * percent) + blue;
	hexRed = red.toString(16);
	hexGreen = green.toString(16);
	hexBlue = blue.toString(16);
	var hexRedPadded = Terrasoft.pad(hexRed, 2, "0");
	var hexGreenPadded = Terrasoft.pad(hexGreen, 2, "0");
	var hexBluePadded = Terrasoft.pad(hexBlue, 2, "0");
	return Ext.String.format("#{0}{1}{2}", hexRedPadded, hexGreenPadded, hexBluePadded);
};

/**
 * @member Terrasoft.
 * @method shadeColor.
 * Reduction for {@link Terrasoft.utils.dom#shadeColor}.
 * @inheritdoc Terrasoft.utils.dom#shadeColor.
 */
Terrasoft.shadeColor = Terrasoft.utils.dom.shadeColor;

/**
 * Downloads data.
 * @param {String} href Data href.
 * @param {String} fileName File name.
 */
Terrasoft.utils.dom.download = function (href, fileName) {
	var hrefEl = document.createElement("a");
	hrefEl.href = href;
	hrefEl.download = fileName;
	document.body.appendChild(hrefEl);
	hrefEl.click();
	document.body.removeChild(hrefEl);
};

/**
 * @member Terrasoft.
 * @method download.
 * Reduction for {@link Terrasoft.utils.dom#download}.
 * @inheritdoc Terrasoft.utils.dom#download.
 */
Terrasoft.download = Terrasoft.utils.dom.download;

/**
 * Convert base64/URLEncoded data component to raw binary data held in a string.
 * @param {String} dataURI Uri of the image.
 * @return {Image} Image.
 */
Terrasoft.utils.dom.getImageFile = function (dataURI, name) {
	var getMimeType = function (uriParts) {
		var firstPart = uriParts[0];
		var data = firstPart.split(":")[1];
		var mimeString = data.split(";")[0];
		return mimeString;
	};
	var getByteArray = function (uriParts) {
		var byteString;
		if (uriParts[0].indexOf("base64") >= 0) {
			byteString = atob(uriParts[1]);
		} else {
			byteString = decodeURIComponent(uriParts[1]);
		}
		var byteArray = new Uint8Array(byteString.length);
		for (var i = byteString.length - 1; i >= 0; i--) {
			byteArray[i] = byteString.charCodeAt(i);
		}
		return byteArray;
	};
	var uriParts = dataURI.split(",");
	var mimeString = getMimeType(uriParts);
	var byteArray = getByteArray(uriParts);
	var newDate = new Date();
	var guid = Terrasoft.generateGUID();
	var blob = new Blob([byteArray], { type: mimeString });
	Ext.apply(blob, {
		lastModified: newDate.valueOf(),
		lastModifiedDate: newDate.toString(),
		name: name || guid.toString(),
		webkitRelativePath: ""
	});
	return blob;
};

/**
 * @member Terrasoft.
 * @method getImageFile.
 * Reduction for {@link Terrasoft.utils.dom#getImageFile}.
 * @inheritdoc Terrasoft.utils.dom#getImageFile
 */
Terrasoft.getImageFile = Terrasoft.utils.dom.getImageFile;

/**
 * Retrieves the viewport size of the document.
 */
Terrasoft.utils.dom.getViewSize = function () {
	return Ext.getBody().getViewSize();
};

/**
 * @member Terrasoft.
 * @method getViewSize.
 * Reduction for {@link Terrasoft.utils.dom#getViewSize}.
 * @inheritdoc Terrasoft.utils.dom#getViewSize.
 */
Terrasoft.getViewSize = Terrasoft.utils.dom.getViewSize;

/**
 * Returns flag that indicates if dom element is body element.
 * @param {Object} element Dom element.
 * @return {Boolean}
 */
Terrasoft.utils.dom.getIsBodyElement = function (element) {
	var nodeName = element.nodeName.toLowerCase();
	return nodeName === "body";
};

/**
 * @member Terrasoft.
 * @method getIsBodyElement.
 * Reduction for {@link Terrasoft.utils.dom#getIsBodyElement}.
 * @inheritdoc Terrasoft.utils.dom#getIsBodyElement.
 */
Terrasoft.getIsBodyElement = Terrasoft.utils.dom.getIsBodyElement;

/**
 * Scrolls the current element into the visible area of the browser window.
 * @param {Object} element Dom element.
 * @param {Object} options Scroll options.
 * @return {Boolean}
 */
Terrasoft.utils.dom.scrollIntoView = function (element, options) {
	if (element.scrollIntoViewIfNeeded) {
		element.scrollIntoViewIfNeeded(options);
	} else {
		element.scrollIntoView(options);
	}
};

/**
 * @member Terrasoft.
 * @method scrollIntoView.
 * Reduction for {@link Terrasoft.utils.dom#scrollIntoView}.
 * @inheritdoc Terrasoft.utils.dom#scrollIntoView.
 */
Terrasoft.scrollIntoView = Terrasoft.utils.dom.scrollIntoView;

/**
 * Applies to dom element full screen css class.
 * @param {String} cssSelector Dom element css selector.
 * @returns {Boolean} Is full screen mode enabled tag.
 */
Terrasoft.utils.dom.toggleFullScreenMode = function (cssSelector) {
	var fullScreenOverlayCssClass = "full-screen-overlay-el";
	var fullScreenOverlayId = "full-screen-overlay-el";
	var fullScreenCssClass = "full-screen-el";
	var domElements = Ext.select(cssSelector);
	var domEl = domElements.first();
	if (!domEl) {
		console.warn("toggleFullScreenMode failed. Not found element by selector " + cssSelector);
		return false;
	}
	var fullScreenOverlayEl = Ext.get(fullScreenOverlayId);
	if (!fullScreenOverlayEl) {
		var overlayDiv = Ext.DomHelper.insertBefore(domEl, {
			id: fullScreenOverlayId,
			tag: "div"
		});
		fullScreenOverlayEl = Ext.get(overlayDiv);
	}
	fullScreenOverlayEl.toggleCls(fullScreenOverlayCssClass);
	domEl.toggleCls(fullScreenCssClass);
	return domEl.hasCls(fullScreenCssClass);
};

/**
 * @member Terrasoft.
 * @method toggleFullScreenMode.
 * Reduction for {@link Terrasoft.utils.dom#toggleFullScreenMode}.
 * @inheritdoc Terrasoft.utils.dom#toggleFullScreenMode.
 */
Terrasoft.toggleFullScreenMode = Terrasoft.utils.dom.toggleFullScreenMode;

/**
 * Calculate scroll position of the element.
 * @param {Ext.Element} el Element in which you need to calculate the position of the scroll.
 * @throws {Terrasoft.UnsupportedTypeException} An exception is thrown when the el is not valid object type.
 * @returns {{top: Number, left: Number}} Left and top scroll position.
 */
Terrasoft.utils.dom.getScrollPosition = function (el) {
	if (!el || !el.getScroll || !el.dom) {
		throw new Terrasoft.UnsupportedTypeException();
	}
	var scroll = el.getScroll();
	var left = Math.abs(scroll.left);
	var scrollType = Terrasoft.getScrollTypeInRtl();
	if (Terrasoft.getIsRtlMode() && scrollType !== Terrasoft.ScrollTypeInRtl.DEFAULT) {
		var width = el.dom.scrollWidth - el.dom.clientWidth;
		left = width - left;
	}
	return {
		left: left,
		top: scroll.top
	};
};

/**
 * @member Terrasoft.
 * @method getScrollPosition.
 * Reduction for {@link Terrasoft.utils.dom#getScrollPosition}.
 * @inheritdoc Terrasoft.utils.dom#getScrollPosition.
 */
Terrasoft.getScrollPosition = Terrasoft.utils.dom.getScrollPosition;

/**
 * Detects scroll type in RTL. By example, mozilla firefox, returns the negative value by el.getScrollLeft()
 * in rtl mode.
 * @returns {Terrasoft.ScrollTypeInRtl} Scroll type in rtl mode.
 */
Terrasoft.utils.dom.getScrollTypeInRtl = function () {
	var reverseScrollType = Terrasoft.utils.dom.getScrollTypeInRtl;
	if (Ext.isDefined(reverseScrollType.cache)) {
		return reverseScrollType.cache;
	}
	var tempEl = Ext.DomHelper.createTemplate({
		tag: "div",
		dir: "rtl",
		style: {
			fontSize: "14px",
			width: "4px",
			height: "1px",
			position: "absolute",
			top: "-10000px",
			overflow: "scroll"
		}
	}).append(document.body);
	tempEl.appendChild(document.createTextNode("ABCD"));
	reverseScrollType = Terrasoft.ScrollTypeInRtl.REVERSE;
	if (tempEl.scrollLeft > 0) {
		reverseScrollType = Terrasoft.ScrollTypeInRtl.DEFAULT;
	} else {
		tempEl.scrollLeft = 1;
		if (tempEl.scrollLeft === 0) {
			reverseScrollType = Terrasoft.ScrollTypeInRtl.NEGATIVE;
		}
	}
	document.body.removeChild(tempEl);
	Terrasoft.utils.dom.getScrollTypeInRtl.cache = reverseScrollType;
	return reverseScrollType;
};

/**
 * @member Terrasoft.
 * @method getScrollTypeInRtl.
 * Reduction for {@link Terrasoft.utils.dom#getScrollTypeInRtl}.
 * @inheritdoc Terrasoft.utils.dom#getScrollTypeInRtl.
 */
Terrasoft.getScrollTypeInRtl = Terrasoft.utils.dom.getScrollTypeInRtl;