	
	/**
	 * Include the richarea script
	 */
	NG.include('/admin/includes/richarea.js');
	
	/**
	 * Display/hide object
	 *
	 * Function will either display or hide object
	 *
	 * @access public
	 * @param object obj The object to display/hide.
	 * @param bool forceHide Set to true to force hide this object or set to false to force display. Do not set to use the
	 *                       oppsite of the object's current display
	 * @return void
	 */
	function displayObj(obj) {
		var hide;
		
		if (arguments.length == 2) {
			if (arguments[1]) {
				hide = T;
			} else {
				hide = F;
			}
		} else {
			hide = (obj.style.display != 'none');
		}
		
		if (hide) {
			obj.style.display = 'none';
		} else {
			if (NG.ua.isEng('MSIE') || NG.ua.isEng('MACIE')) {
				obj.style.display = 'block';
			} else {
				var display = '';
				switch (obj.nodeName.toLowerCase()) {
					case 'span':
						display = 'inline';
						break;
					case 'li':
						display = 'list-item';
						break;
					case 'table':
						display = 'table';
						break;
					case 'td':
						display = 'table-cell';
						break;
					case 'tr':
						display = 'table-row';
						break;
					case 'tbody':
						display = 'table-row-group';
						break;
					case 'col':
						display = 'table-column';
						break;
					case 'colgroup':
						display = 'table-column-group';
						break;
					case 'thead':
						display = 'table-header-group';
						break;
					case 'tfoot':
						display = 'table-footer-group';
						break;
					case 'caption':
						display = 'table-caption';
						break;
					default:
						display = 'block';
						break;
				}
				obj.style.display = display;
			}
		}
	}
	
	/**
	 * Position divs within an object
	 *
	 * Function will absolutely positions all the first level divs within the relative object obj.
	 * Divs are placed from left to right then start again from the left. All divs must have their
	 * width and left set
	 *
	 * @access public
	 * @param obj obj The container object containing all the div elements
	 * @return void
	 */
	function positionBlocks(obj) {
		var __Positions = new Array();
		var __Blocks    = new Array();
		var i,top,left,idx,leftExt,maxWidth,maxHeight,blockWidth;
		
		//make the box invisible while changes are being made
		obj.style.visibility = 'hidden';
		
		maxWidth = (isId(obj.offsetWidth) ? obj.offsetWidth : obj.clientWidth);
		
		// Get all the first level div blocks
		for (i=0; i<obj.childNodes.length; i++) {
			if (obj.childNodes[i].nodeName.toLowerCase() == 'div') {
				__Blocks[__Blocks.length] = obj.childNodes[i];
			}
		}
		
		// If any of the divs are wider than our container then exit
		for (i=0; i<__Blocks.length; i++) {
			if (__Blocks[i].offsetWidth > maxWidth) {
				obj.style.visibility = 'visible';
				return;
			}
		}
		
		maxHeight = 0;
		
		for (i=0; i<__Blocks.length; i++) {
			
			// Get the left in pixels
			left = Math.floor(Math.max(0, (parseInt(__Blocks[i].style.left) / 100)) * maxWidth);
			top  = 0;
			
			// Now get the top
			blockWidth = Math.floor((parseInt(__Blocks[i].style.width)/100) * maxWidth);
			leftExt    = blockWidth+left;
			for (var x=0; x < __Positions.length; x++) {
				if ((left >= __Positions[x].left && left <= (__Positions[x].left+__Positions[x].width)) 
				   || (leftExt >= __Positions[x].left && leftExt <= (__Positions[x].left+__Positions[x].width)) 
				   || (left <= __Positions[x].left && leftExt >= (__Positions[x].left+__Positions[x].width))) {
					top = Math.max(top, (__Positions[x].top + __Positions[x].height));
					
				}
			}
			
			// Cache these positions so we can reference them
			__Positions[i] = {'top':top, 'left':left, 'width':blockWidth, 'height':__Blocks[i].offsetHeight};
			
			// Store our maximum height
			maxHeight = Math.max(maxHeight, (__Positions[i].top + __Positions[i].height));
			
			// Now position these babies
			__Blocks[i].style.top  = __Positions[i].top  + 'px';
			__Blocks[i].style.left = __Positions[i].left + 'px';
		}
		
		obj.style.height = maxHeight + 'px';
		
		//make the box visible after changes complete
		obj.style.visibility  = 'visible';
		return;
	}
	
	/**
	 * Switch between steps in front end admin
	 *
	 * Function will hide all steps and display the selected step
	 *
	 * @access public
	 * @param int id The step number to display
	 * @return void
	 */
	function joinSteps(id) {
		if (!isId(id)) {
			return;
		}
		
		document.getElementById('part'+id).style.display = 'block';
		
		for (var i=1; isObj(document.getElementById('part'+i)); i++) {
			if (i == id) {
				continue;
			}
			document.getElementById('part'+i).style.display = 'none';
		}
		return;
	}
	
	/**
	 * Fill in all the cascading filter dropboxes
	 *
	 * Function will handle all the cascade filtering for the associated dropboxes. The 'data' variable is the array
	 * of objects to create the options from. The 'dependencies' variable contains an object of all the associations.
	 *
	 * 'dependencies' example:
	 *
	 * dependencies = {'typeid': type-dropbox-object, 'areaid': area-dropbox-object}
	 *
	 * @access public
	 * @param object box The dropbox object
	 * @param array data The options to select from
	 * @param object dependencies The object dependency objects
	 * @param function preFunc The optional pre function to call before anything (but after reseting the options)
	 * @param function successFunc The optional function to call if all dependencies are met
	 * @param function failureFunc The optional function to call if any dependencies are not met
	 * @return void
	 */
	var g_flag_state = true;
	function cascadeBox(box, data, dependencies) {
		if (!isObj(box) || !isArr(data) || !isObj(dependencies)) {
			return;
		}
		
		box.NGdata         = data;
		box.NGdependencies = dependencies;
		box.NGpreFunc      = (arguments.length > 3 && isFunc(arguments[3]) ? arguments[3] : null);
		box.NGsuccessFunc  = (arguments.length > 4 && isFunc(arguments[4]) ? arguments[4] : null);
		box.NGfailureFunc  = (arguments.length > 5 && isFunc(arguments[5]) ? arguments[5] : null);
		var flag           = (arguments.length > 6 && arguments[6] == true ? arguments[6] : false);
		
		box.NGfilter       =
			function() {
				if (g_flag_state == false && flag == false) return false;
				box.options.length = 0;
				
				if (isFunc(box.NGpreFunc)) {
					box.NGpreFunc();
				}
				
				var passed = T
				for (var attrib in box.NGdependencies) {
					if (attrib == 'clone') continue;
					if (box.NGdependencies[attrib].selectedIndex  <= 0) {
						passed = F;
					}
				}
				
				if (!passed) {
					if (isFunc(box.NGfailureFunc)) {
						box.NGfailureFunc();
					}
					return;
				}
				
				for (var i=0; i<box.NGdata.length; i++) {
					var include = T;
					for (var attrib in box.NGdependencies) {
						if (attrib == 'clone') continue;
						if (isArr(box.NGdata[i][attrib])) {
							if (box.NGdata[i][attrib].search(box.NGdependencies[attrib].options[box.NGdependencies[attrib].selectedIndex].value) == -1) {
								include = F;
							}
						} else {
							if (box.NGdata[i][attrib] != box.NGdependencies[attrib].options[box.NGdependencies[attrib].selectedIndex].value) {
								include = F;
							}
						}
						
						if (!include) {
							break;
						}
					}
					
					if (include) {
						box.options[box.options.length] = new Option(box.NGdata[i].name, box.NGdata[i].id);
					}
				}
				
				if (isFunc(box.NGsuccessFunc)) {
					box.NGsuccessFunc();
				}
				
				return;
			}
		
		for (var attrib in box.NGdependencies) {
			if (attrib == 'clone') continue;
			NG.addTrigger(box.NGdependencies[attrib], 'change', box.NGfilter);
		}
		
		box.NGfilter();
	}
	
	/**
	 * Make <label> work in IE
	 *
	 * Function will loop through each <label> element and add an onclick event to simultate the
	 * <label> onclick event
	 *
	 * @access public
	 * @return void
	 */
	function initLabels() {
		if (!NG.ua.isEng('MSIE') && !NG.ua.isEng('MACIE')) {
			return;
		}
		var labels = document.getElementsByTagName('label');
		for (var i = 0; i < labels.length; i++) {
			if (!labels[i].getAttribute('for')){
				NG.addTrigger(labels[i], 'click', selectLabel);
			}
		}
	}
	
	/**
	 * The event function used in initLabels()
	 *
	 * Function will simulate the onclick event for <label>
	 *
	 * @access private
	 * @param object e The event object
	 * @return void
	 */
	function selectLabel(e) {
		if ((isDef(e) && window.event.srcElement.nodeName == 'INPUT') || (!isDef(e) && e.target.nodeName == 'INPUT')) {
			return;
		}
		var formElements = document.getElementsByTagName('input');
		for (var i = 0; i < formElements.length; i++) {
			if (formElements[i]) {
				if (isDef(formElements[i].checked)) {
					formElements[i].checked = !formElements[i].checked;
					if (typeof formElements[i].onclick == 'function') {
						formElements[i].onclick();
						formElements[i].focus();
					}
				}
			}
		}
	}
	
	/**
	 * Hide/display all elements with class name of className
	 *
	 * Function will look down the document or 3rd argument if is defined and hide/display all elements
	 * within of class name className 
	 *
	 * @access public
	 * @param string className The class name of the elements to hide
	 * @param bool hide TRUE to hide elements else display them. Default is TRUE
	 * @param obj parent The optional parent element to look in. Default is document
	 * @return void
	 */
	function displayClassNodes(className) {
		var hide, parent, children;
		if (arguments.length > 1 && !isNull(arguments[1])) {
			hide = arguments[1];
		} else {
			hide = T;
		}
		
		if (arguments.length > 2 && isObj(arguments[2])) {
			parent = arguments[2];
		} else {
			parent = document;
		}
		
		if (!isStr(className) || !isObj(parent)) {
			return;
		}
		
		var children = getElementsByClassName(parent, className);
		
		for (var i=0; i<children.length; i++) {
			if (children[i].style) {
				displayObj(children[i], hide);
			}
		}
		
		return;
	}
	
	/**
	 * Wrapper function for displayClassNodes()
	 *
	 * Function will look down the document or 4rd argument if is defined and hide/display all elements
	 * within of class name className based on the display attribute of the 1st argument. Will set the
	 * oppsite display to the 1st argument
	 *
	 * @access public
	 * @param obj target Hide/display all elements based on the oppsite of this object's display
	 * @param string className The class name of the elements to hide
	 * @param obj parent The optional parent element to look in. Default is document
	 * @return void
	 */
	function displayAltClassNodes(target, className) {
		var parent, hideAll;
		if (arguments.length > 2 && isObj(arguments[2])) {
			parent = arguments[2];
		} else {
			parent = document;
		}
		
		if (!isObj(target) || !isStr(className) || !isObj(parent)) {
			return;
		}
		
		var hideAll = (target.style.display == '' || target.style.display == 'none')
		
		displayClassNodes(className, hideAll, parent);
		displayObj(target, !hideAll);
	}
	
	/**
	 * Display why bubble
	 *
	 * Wrapper function for displaying the why bubbles
	 *
	 * @access public
	 * @param obj why The why bubble div object
	 * @param int height The offset height of the why object
	 * @param string parentId The parent element
	 * @return void
	 */
	function displayWhyBubble(whyLabel, parentId) {
		if (whyLabel == '' || parentId == '') {
			return;
		}
		
		var whyBubble = document.getElementById('why-'+whyLabel);
		var parent    = document.getElementById(parentId);
		var showMe    = (whyBubble.style.display != 'none');
		
		displayClassNodes('whybubble', T, parent);
		displayObj(whyBubble, showMe);
		return
	}
	
	/**
	 * Display TBX my account tabs
	 *
	 * Wrapper for displaying the TBX my account tabs
	 *
	 * @access public
	 * @param isSellTab bool TRUE if we are to display the sell tab, FALSE otherwise. Default is TRUE
	 * @return void
	 */
	function displayMyAccountTab() {
		var show,hide,isSellTab = T;
		if (arguments.length == 1) {
			isSellTab = arguments[0];
		}
		
		show = (isSellTab ? 'selling' : 'buying');
		hide = (isSellTab ? 'buying' : 'selling');
		
		document.getElementById(show).className = 'tabsel';
		document.getElementById(hide).className = 'tab';
		
		displayObj(document.getElementById(show+'-section'), F);
		displayObj(document.getElementById(hide+'-section'), T);
		
	}
	
	/**
	 * Do unsubscribe counter
	 *
	 * Function will handle the unsubscribe counter
	 *
	 * @access public
	 * @return void
	 */
	function doUnsubscribeCounter() {
		var span = document.getElementById('unsubscribe-counter');
		
		if (span.firstChild.nodeValue <= '1') {
			var frm = document.getElementById('counter-form');
			frm['form_confirmed'].value = 1;
			frm.submit();
		} else {
			span.firstChild.nodeValue = parseInt(span.firstChild.nodeValue) - 1;
		}
	}
	
	/**
	 * Redirect to login auth pahe
	 *
	 * Function will redirect to the auth login page with associated arguments
	 *
	 * @access public
	 * @param string token The login token
	 * @param string redirect The successful redirect url
	 * @param int action The action id
	 * @return void
	 */
	function redirectLogin(token, redirect, action) {
		document.getElementById('sso-login').src='/signon.php?sso-auth[token]='+token+'&sso-auth[success_url]='+redirect+'&sso-auth[sso_action]='+action;
		return;
	}
