define(["wc/dom/textContent",
	"wc/dom/shed",
	"wc/ui/tooltip",
	"wc/ui/label"],
	function (textContent, shed, tooltip, label) {
		"use strict";

		/**
		 * Funny old treewalker filter: we want to get all the nodes we can remove from element so we ACCEPT anything
		 * which is disabled or hidden.
		 *
		 * @function
		 * @private
		 * @param {Element} element The start element
		 * @returns {Number} NodeFilter.FILTER_ACCEPT if the node is hidden (and can therefore be removed).
		 */
		function treeWalkerFilter(element) {
			if (shed.isHidden(element, false, true)) {
				return NodeFilter.FILTER_ACCEPT;
			}

			return NodeFilter.FILTER_SKIP;
		}

		/**
		 * Remove "invisible" descendants from an element. These are element nodes which will not appear in the UI.
		 *
		 * @function
		 * @private
		 * @param {Element} clone the element from which we are removing invisible descendants
		 * @returns {undefined}
		 */
		function removeInvisibles(clone) {
			var tw = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, treeWalkerFilter, false),
				_el;

			tw.currentNode = clone;
			while ((_el = tw.nextNode())) {
				tw.currentNode = _el.parentNode;
				_el.parentNode.removeChild(_el);
			}
		}

		/**
		 * @function module:wc/ui/getVisibleText
		 * @param {Element} element The element for which we want to find the text.
		 * @param {Boolean} [removeHint] If truthy also remove any HINT (applies only to labels).
		 * @param {Boolean} [trim] if truthy then trim the content before returning it
		 * @returns {String?} The text content of the element without HINT or TOOLTIP.
		 */
		function getVisibleText(element, removeHint, trim) {
			var clone = element.cloneNode(true),
				removeableChild,
				content;

			// ToolTip is not necessarily invisible at the time of calling (may have ALT/META key pressed).
			if ((removeableChild = tooltip.getTooltip(clone))) {
				clone.removeChild(removeableChild);
			}

			if (removeHint) { // HINT is never "invisible"
				while ((removeableChild = label.getHint(clone))) {
					removeableChild.parentNode.removeChild(removeableChild);
				}
			}

			removeInvisibles(clone);
			content = textContent.get(clone);
			return trim && content ? content.trim() : content;
		}
		/**
		 * @module
		 * @requires module:wc/dom/Widget
		 * @requires module:wc/dom/textContent
		 * @requires module:wc/dom/shed
		 * @requires module:wc/ui/tooltip
		 * @requires module:wc/ui/label
		 */
		return getVisibleText;
	});

