var _util = new CommonUtilities();

function CommonUtilities()
{
	/**
	 * selectAllCheckboxes() - takes an optional checkbox class (if null, ALL checkboxes on the page are checked/unchecked) and an optional "shouldCheck" indicating whether the checkboxes found should be checked or unchecked (if null, boxes are checked)
	 * so calling this function with no parameters results in exactly the function's title: ALL checkboxes are SELECTED; otherwise you can target a specific group of checkboxes and determine whether they should be checked or unchecked.
	 */
	this.selectAllCheckboxes = function(checkboxClass, shouldCheck)
	{
		if (checkboxClass == null)
		{
			checkboxClass = "input[type=checkbox]";
		}
		
		if (shouldCheck == null)
		{
			shouldCheck = "true";
		}
	
		// just in case 'checkboxClass' is also applied to non-checkboxes, filter the results of the query() to only include checkboxes
		var checkboxes = dojo.query(checkboxClass).filter(function(item){return item.type == "checkbox";});
		
		if (checkboxes.length > 0)
		{
			checkboxes.forEach("item.checked = " + shouldCheck + ";");
		}
	}
	
	
	/**
	 * hasSelection() - takes a "collection" (i.e.: the results of a dojo.query()), determines what type of elements it contains and determines of one or more of them is "selected" - depending on what "selected" means in the context of the collection's elements
	 * (currently, only collections of checkboxes are supported but this can easily be extended to <selects> or <input type="radio">s if needed)
	 */
	this.hasSelection = function(collection)
	{
		if (collection == null || collection.length == null || collection.length == 0)
		{
			return false;
		}
		
		// try to figure out what the collection contains by taking a "sample" - assumes that all items in collection are the same tag/type
		var sample = collection[0];
		var tag = sample.tagName.toString().toLowerCase();
		var type = sample.type.toString().toLowerCase();
		
		if (tag != null)
		{
			if (tag == "input")
			{
				if (type != null && type == "checkbox")
				{
					var checked = dojo.filter(collection, function(item){return (item.checked != null && item.checked == true);});
					return (checked.length > 0);
				}
			}
		}
		
		return false;
	}
	
	
	/**
	 * selectByValue() - takes a <select> element and a string value, looks for that value among the <select>'s <options> and selects it if found.
	 * Note that, if the <select> is a multi-select, this function will ADD to the selection.
	 */
	this.selectByValue = function(selectElement, value)
	{
		if (selectElement == null)
		{
			return;
		}
		var options = selectElement.options;
		for (var i=0; i<options.length; i++)
		{
			if (options[i].value == value)
			{
				options[i].selected = true;
				break;
			}
		}
	}
	
	
	/**
	 * clearSelected() - takes a <select> element and deselects any and all <options>.
	 */
	this.clearSelected = function(selectElement)
	{
		if (selectElement == null)
		{
			return;
		}
		var options = selectElement.options;
		for (var i=0; i<options.length; i++)
		{
			options[i].selected = false;
		}
	}
	
	
	/**
	 * emptySelect() - takes a <select> element and removes any and all <options> 
	 */
	this.emptySelect = function(selectElement)
	{
		if (selectElement != null)
		{
			selectElement.options.length = 0;
		}
	}
	
	
	this.nullOrBlank = function(str)
	{
		if (str == null)
		{
			return true;
		}
		if (typeof(str) != "string")
		{
			return true;
		}
		if (this.trim(str).length < 1)
		{
			return true;
		}
		return false;
	}
	
	
	/**
	 * trim() - Trim leading and trailing whitespace from a string.
	 */
	this.trim = function(str)
	{
		if (str == null)
		{
			return "";
		}
		if (typeof(str) != "string")
		{
			return str;
		}
		str = str.replace(/^[\s]+/, ""); //trim leading spaces
		return str.replace(/[\s]+$/, ""); //trim trailing spaces
	}
	
	this.enableControls = function(collection, enable)
	{
		if (collection == null || collection.length < 1)
		{
			return;
		}
		if (enable == null)
		{
			enable = true;
		}
		
		collection.forEach(
				function(item)
				{
					var tag = item.tagName.toString().toLowerCase(); 
					if (tag == "input" || tag == "select")
					{
						item.disabled = !enable;
					}
				}
		);
	}
	
	this.appendTableRow = function(table, values, rowClass)
	{
		if (table == null || values == null || values.length < 1)
		{
			return;
		}
		var numColumns = values.length;
		if (table.rows.length > 0)
		{
			numColumns = table.rows[0].cells.length;
		}
		
		if (numColumns != values.length)
		{
			console.log("Trying to append table row; invalid number of values for table columns.");
			return;
		}
		var newRow = table.insertRow(table.rows.length);
		if (rowClass != null)
		{
			newRow.className = rowClass.toString();
		}
		for (var i=0; i<values.length; i++)
		{
			var newCell = newRow.insertCell(i);
			var thisValue = values[i];
			if (typeof(thisValue).toLowerCase() == "string")
			{
				newCell.innerHTML = thisValue;
			}
			else if (typeof(thisValue).toLowerCase() == "object")
			{
				newCell.appendChild(thisValue);
			}
		}
	}
	
	// Takes an element ID or element, 1 or more event names, and 1 or more functions and connects the event(s) of the element to the function(s) if the element is available on the page
	//   ID - can be either the string ID of an element or an element itself (e.g.: "SomeButtonID" or document.form.formElement or dojo.byId("SomeID"))
	//   evt - can be either the dojo-compatible string name of an event ("onclick", "onsubmit", etc...) or an array of same
	//   fn - the function(s) to be connected
	// If evt and fn are both arrays, they must have the same number of elements. In this case, the element's evt[0] event is connected to fn[0] and so on. 
	this.connectIfAvailable = function(ID, evt, fn)
	{
		if (ID == null || evt == null || fn == null)
		{
			return false;
		}

		var el = null;
		if (typeof ID == "string")	// if ID is a string, attempt to get the element with said ID 
		{
			el = dojo.byId(ID);
		}
		else						// otherwise, assume it's an element already
		{
			el = ID;
		}
		
		if (el == null)
		{
			return false;
		}

		if (typeof evt == "string")	// if only one event name, "cast" it to an array so we can loop. same for fn
		{
			evt = [evt];
		}

		if (typeof fn == "function")
		{
			fn = [fn];
		}

		if (evt.length != fn.length)	// make sure we have the same number of event names and functions
		{
			return false;
		}
		
		for (var i=0; i<evt.length; i++)	// wire everything up
		{
			dojo.connect(el, evt[i], fn[i]);
		}
	}
	
	
	this.removeNode = function(node)
	{
		if (node == null || node.parentNode == null)
		{
			return;
		}
		
		node.parentNode.removeChild(node);
	}
	
	
	// Depending on the browser the "usual" way of getting the visible top of the page (i.e.: window.pageYOffset) may not work (I'm looking at you, IE)
	// This function runs through several different ways of getting it and, if none work, returns 0
	this.getScrollTop = function()
	{
		if (typeof(window.pageYOffset) == 'number')
		{
			return window.pageYOffset;
		}
		// IE does not provide the pageYOffset attribute
		else if (document.body && document.body.scrollTop)
		{
			return document.body.scrollTop;
		}
		else if (document.documentElement && document.documentElement.scrollTop)
		{
			return document.documentElement.scrollTop;
		}
		return 0;
	}
}
