/**
 * jquery.utilities.js (Utility functions)
 * @version 2.2
 * @author Andrew Ramsden
 * @see http://irama.org/web/dhtml/utilities/
 * @license Common Public License Version 1.0 <http://www.opensource.org/licenses/cpl1.0.txt>
 */
(function($) {// start closure
	/**
	 * Gets or sets the anchor portion of the URL (after the #)
	 * @param String hash The value to set the anchor portion of the URL.
	 *                    If not set, function will return the current value
	 * @param Boolean jumpToAnchor Whether to allow the browser window
	 *        to scroll to place the anchor specified (targeted by the 
	 *        hash).
	 */
	$.frag = function ( /* optional */ hash, /* optional - default = false */ jumpToAnchor)
	{
		// Initialise variables
			hash = (typeof hash !== 'undefined')?hash:null;
			jumpToAnchor = (typeof(jumpToAnchor) != 'undefined')?(jumpToAnchor)?true:false:false;
		
		if (hash === null) {
			// get
			return window.location.hash.replace('#','');
		} else {
			// set
			if (jumpToAnchor) {
				// Just reset hash, allow browser to move
					window.location.hash = hash;
			} else {
				// If nothing has changed, just quit now
					if (hash == $.frag()) {
						return true;
					}
				
				// get current scroll position
					currentY = $(window).scrollLeft();
					currentX = $(window).scrollTop();
				
				// Reset hash
					window.location.hash = hash;
				
				// Correct the scroll position
					$(window).scrollTop(currentX);
					$(window).scrollLeft(currentY);
			}
			return true;
		}
	};
	
	
	/**
	 * plugins
	 */
	$.fn.extend({
		
		/**
		 * @author Brandon Aaron <brandonaaron.net>
		 * @see http://blog.brandonaaron.net/2007/06/25/where-is-the-hasclass-method/
		 */
		hasClass : function(c) {
			return this.is('.'+c);
		},
		
		/**
		 * Allows complex selectors to be used with jQuery's is() type functionality.
		 * Use jQuery's is() for simple selectors (should give better performance).
		 * @example: <code>$(element).complexIs('.requied input[type=text]')</code>
		 * @author Ariel Flesler (with permission)
		 * @see http://www.nabble.com/Re%3A-.is%28%29-and-complex-expressions-p18083581s27240.html
		 */
		complexIs : function (complexSelector) {
			return $(complexSelector).index(this) != -1 ? true : false ;
		},
		
		/**
		 * Get the the first and biggest heading for the container element
		 * @version 2.0
		 * @author Andrew Ramsden <irama.org>
		 * @return jQueryNode The first and biggest heading within the target element,
		 *         or a blank h2 if no headings found.
		 */
		firstHeading : function() {
			
			heading = $(this).children('h1:lt(1)');
			if (heading.text()!=='') { return heading; }
			
			heading = $(this).children('h2:lt(1)');
			if (heading.text()!=='') { return heading; }
			
			heading = $(this).children('h3:lt(1)');
			if (heading.text()!=='') { return heading; }
			
			heading = $(this).children('h4:lt(1)');
			if (heading.text()!=='') { return heading; }
			
			heading = $(this).children('h5:lt(1)');
			if (heading.text()!=='') { return heading; }
			
			heading = $(this).children('h6:lt(1)');
			if (heading.text()!=='') { return heading; }
			
			// nothing return blank heading
			return $('<h2></h2>');
		},
		
		/**
		 * Trigger an event but return the result, instead of the jQuery object
		 * @version 1.0
		 * @author Andrew Ramsden <irama.org>
		 */
		triggerResult : function (eventType) {
			if (typeof eventType == 'undefined') {
				return false;
			}
			
			// can only capture the result for one element
			el = $(this).get(0);
			
			// browser capabilities check
				if (typeof document.createEvent != 'undefined') {
					// for standards-compliant browsers
					var evt = document.createEvent("MouseEvents");
					evt.initMouseEvent("click", true, true, window,
					0, 0, 0, 0, 0, false, false, false, false, 0, null);
					return el.dispatchEvent(evt);
				} else if (typeof document.createEventObject != 'undefined') {
					// for IE
					var eventObj = document.createEventObject();
					return el.fireEvent("onclick",eventObj);
				} else {
					// Sorry, I haven't catered for you (whoever you might be), email me!
				}
		},
		
		
		
		/**
		 * Can undo the effects of jQuery's wrap() function
		 * @author John Resig
		 * @see http://www.mail-archive.com/discuss@jquery.com/msg01706.html
		 * @example <code class="html">&lt;div id="removeMe">&lt;p id="keepMe"> text &lt;/p>&lt;/div></code><code class="javascript">$("#keepMe").unwrap("div#removeMe");</code>
		 */
		unwrap : function (expr) {
			return this.each(function(){
				$(this).parents(expr).eq(0).after(this).remove();
			});
		},
		
		
		
		/**
		 * Allows a batch of jQuery nodes to be sorted into DOM order (may result in slow performance).
		 * @author Dave Methvin
		 * @see http://groups.google.com/group/jquery-dev/tree/browse_frm/month/2007-11/9a624147721e9301?rnum=231&_done=%2Fgroup%2Fjquery-dev%2Fbrowse_frm%2Fmonth%2F2007-11%3F#a_1d0664f658c155dc
		 */
		sortDOM : function() {
			// W3C DOM3 (Firefox 2+, others?) makes this easy
				if ( document.compareDocumentPosition ) {
					return Array.prototype.sort.call(this, function(a,b){
						return (a.compareDocumentPosition(b)&2)? 1 : -1;
					});
				}
			
			// Otherwise, use manual sort (for IE, etc...)
			// Mark nodes and collect by traversing whole DOM in order
				var $self = this.attr("_sortDOM_", 1);
				jQuery("[@_sortDOM_=1]").each(function(i){
					$self[i] = this;
				});
				return this.removeAttr("_sortDOM_");
		
		}
	});
		
})(jQuery); // end closure
