/**
 * Static utility class containing DOM-specific funtionality.
 * @static
 */
HD.util.Dom = {
	/**
	 * Attaches on page load callback events.
	 * 
	 * @param {Function} callback the function to execute on page load 
	 */
	onDOMReady : function(callback) {
		YAHOO.util.Event.onDOMReady(callback);
	},
	
	/**
	 * Attaches callbacks events to an element when it first becomes available in DOM.
	 * 
	 * @param {String|HTMLElement} element the element
	 * @param {Function} callback the function to execute once the element becomes available
	 */
	onAvailable : function(element, callback) {
		YAHOO.util.Event.onAvailable(element, callback);
	},
	
	/**
	 * Attaches on element load callback events.
	 * 
	 * @param {String|HTMLElement} element the element
	 * @param {Function} callback the function to execute on element's load 
	 */
	onContentReady : function(element, callback) {
		YAHOO.util.Event.onContentReady(element, callback);
	},
	
	/**
	 * Gets an element from DOM by ID, also accepts HTML element references.
	 * 
	 * @param {String|HTMLElement} element the element to retrieve
	 * @return the HTML element with the provided ID or null
	 */
	get : function(identifier) {
		return YAHOO.util.Dom.get(identifier);
	},
	
	/**
	 * Gets elements by CSS class.
	 * 
	 * @param {String} className the CSS class name
	 * @param {String} elementType the HTML element tag name
	 * @param {String|HTMLElement} containerEl (Optional) the root node element to start searching at
	 * @return the list of matching elements
	 */
	getByClass : function(className, elementType, containerEl) {
		return YAHOO.util.Dom.getElementsByClassName(className, elementType, containerEl);
	},
	
	/**
	 * Adds CSS class to the HTML element.
	 * 
	 * @param {String|HTMLELement} element the element to add the class to
	 * @param {String} className the class name
	 */
	addClass : function(element, className) {
		YAHOO.util.Dom.addClass(element, className);
	},
	
	/**
	 * Removes CSS class from the HTML element.
	 * 
	 * @param {String|HTMLELement} element the element to remove the class from
	 * @param {String} className the class name
	 */
	removeClass : function(element, className) {
		YAHOO.util.Dom.removeClass(element, className);
	},
	
	/**
	 * Replaces HTML element's CSS class name with the one provided.  If the element doesn't have the class name, 
	 * the new name is just added.
	 * 
	 * @param {String|HTMLELement} element the element to remove the class from
	 * @param {String} oldClassName the class name to remove
	 * @param {String} className the class name to add
	 */
	replaceClass : function(element, oldClassName, className) {
		YAHOO.util.Dom.replaceClass(element, oldClassName, className);
	},
	
	/**
	 * Determine whether the HTML element has the given CSS class name.
	 * 
	 * @param {String|HTMLELement} element the element to test
	 * @param {String} className the class name
	 */
	hasClass : function(element, className) {
		return YAHOO.util.Dom.hasClass(element, className);
	},
	
	/**
	 * Makes the element visible by removing 'hdHidden' CSS class name.
	 * 
	 * @param {String|HTMLELement} element the element to make visible
	 */
	show : function(element) {
		HD.util.Dom.removeClass(element, HD.CSS_CLASSES.HIDDEN);
	},
	
	/**
	 * Makes the element invisible by adding 'hdHidden' CSS class name.
	 * 
	 * @param {String|HTMLELement} element the element to make invisible
	 */
	hide : function(element) {
		HD.util.Dom.addClass(element, HD.CSS_CLASSES.HIDDEN);
	},
	
	/**
	 * Determines the horizontal position of the element.
	 * 
	 * @param {String|HTMLELement} element the element
	 */
	getX : function(element) {
		return YAHOO.util.Dom.getX(element);
	},
	
	/**
	 * Determines the vertical position of the element.
	 * 
	 * @param {String|HTMLELement} element the element
	 */
	getY : function(element) {
		return YAHOO.util.Dom.getY(element);
	},
	
	/**
	 * Scrolls the window to the specified element.
	 * 
	 * @param {String|HTMLELement} element the element to scroll to
	 */
	scrollTo : function(element){
		element = HD.util.Dom.get(element);
		var posX = 0;
		var posY = 0;
		
		while(element != null){
			posX += element.offsetLeft;
			posY += element.offsetTop;
			element = element.offsetParent;
		}
		
		window.scrollTo(posX,posY);
	},
	
	/**
	 * Scrolls the window to top left.
	 */
	scrollToTop : function() {
		window.scrollTo(0, 0);
	},
	
	/**
	 * Disabled/enables elements.
	 * 
	 * @param {Array} elements the list of elements to disable/enable
	 * @param {boolean} isDisabled indicates whether to disable or enable elements
	 */
	disableElements : function(elements, isDisable) {
		for(var j = 0, len1 = elements.length; j < len1; j++) {
			elements[j].disabled = isDisable;
		}
	},
	
	/**
	 * Checks/unchecks elements.
	 * 
	 * @param {Array} elements the list of elements to check/uncheck
	 * @param {boolean} isChecked indicates whether to check or uncheck elements
	 */
	checkElements : function(elements, isChecked) {
		for(var j = 0, len1 = elements.length; j < len1; j++) {
			elements[j].checked = isChecked;
		}
	},
	
	/**
	 * Gets the form field by name.
	 * 
	 * @param {HTMLForm} the form
	 * @param {String} fieldName the name of the field
	 * @return the field
	 */
	getField : function(form, fieldName) {
		var fieldNames = fieldName.split(",");
		if(fieldNames.length > 1) {
			var fields = [];
			for(var i = 0, len = fieldNames.length; i < len; i++) {
				fields.push(form[fieldNames[i]]);
			}
			return fields;
		} else {
			return form[fieldName];
		}
	},
	
	/**
	 * Gets field value.
	 * 
	 * @param {HTMLElement} field the field
	 * @return field's value
	 */
	getFieldValue : function(field) {
		var fieldValue = "";
		
		if(!!field.tagName) {
			var tagName = field.tagName.toLowerCase();
			if(tagName == "input") {
				fieldValue = field.value;
			} else if(tagName == "select") {
				fieldValue = field.options[field.selectedIndex].value;
			}
		} else {
			for(var i = 0, len = field.length; i < len; i++) {
				var tempField = field[i];
				if(tempField.checked) {
					fieldValue = tempField.value;
				}
			}
		}
		return fieldValue;
	},
	
	getValue : function(formEl, fieldName) {
		return this.getFieldValue(this.getField(formEl, fieldName));
	},
	
	/**
	 * Sets element values.  The function is borrowed from DWR's util.js with some minor adjustments.  
	 * When setting checkbox/radio value, onchange/onclick event listeners are not being fired, added 
	 * calls to click() and onchange() functions to address the issue.
	 * 
	 * @param {Array} ele the list of elements to set values on
	 * @param {Array} val the list of values to set on elements
	 * @param {Object} options (Optional) options objects (preserved from DWR's API but not used locally)
	 */
	setValue : function(ele, val, options) {
	  if (val == null) val = "";
	  if (options == null) options = {};

	  var orig = ele;
	  if (typeof ele == "string") {
	    ele = dwr.util.byId(ele);
	    // We can work with names and need to sometimes for radio buttons, and IE has
	    // an annoying bug where getElementById() returns an element based on name if
	    // it doesn't find it by id. Here we don't want to do that, so:
	    if (ele && ele.id != orig) ele = null;
	  }
	  var nodes = null;
	  if (ele == null) {
	    // Now it is time to look by name
	    nodes = document.getElementsByName(orig);
	    if (nodes.length >= 1) ele = nodes.item(0);
	  }

	  if (ele == null) {
	    dwr.util._debug("setValue() can't find an element with id/name: " + orig + ".");
	    return;
	  }

	  // All paths now lead to some update so we highlight a change
	  dwr.util.highlight(ele, options);

	  if (dwr.util._isHTMLElement(ele, "select")) {
	    if (ele.type == "select-multiple" && dwr.util._isArray(val)) dwr.util._selectListItems(ele, val)
	;
	    else dwr.util._selectListItem(ele, val);
	    return;
	  }

	  if (dwr.util._isHTMLElement(ele, "input")) {
	    if (ele.type == "radio" || ele.type == "checkbox") {
	      if (nodes && nodes.length >= 1) {
	        for (var i = 0; i < nodes.length; i++) {
	          var node = nodes.item(i);
	          if (node.type != ele.type) continue;
	          if (dwr.util._isArray(val)) {
	            node.checked = false;
	            for (var j = 0; j < val.length; j++) {
	              if (val[j] == node.value) {
	            	  node.checked = true;
	            	if(node.onchange != null) {
	            		node.onchange();
	            		node.click();
	            	}
	              }
	            }
	          }
	          else {
	            node.checked = (node.value == val);
	            if(node.checked == true) {
	            	if(node.onchange != null) {
	            		node.onchange();
	            		node.click();
	            	}
	            }
	          }
	        }
	      }
	      else {
	        ele.checked = (val == true);
            if(ele.checked == true) {
              ele.click();
	        }
	      }
	    }
	    else ele.value = val;

	    return;
	  }

	  if (dwr.util._isHTMLElement(ele, "textarea")) {
	    ele.value = val;
	    return;
	  }

	  // If the value to be set is a DOM object then we try importing the node
	  // rather than serializing it out
	  if (val.nodeType) {
	    if (val.nodeType == 9 /*Node.DOCUMENT_NODE*/) val = val.documentElement;
	    val = dwr.util._importNode(ele.ownerDocument, val, true);
	    ele.appendChild(val);
	    return;
	  }

	  // Fall back to innerHTML and friends
	  if (dwr.util._shouldEscapeHtml(options) && typeof(val) == "string") {
	    if (ele.textContent) ele.textContent = val;
	    else if (ele.innerText) ele.innerText = val;
	    else ele.innerHTML = dwr.util.escapeHtml(val);
	  }
	  else {
	    ele.innerHTML = val;
	  }
	}
};
