/*! Copyright (c) 2008 Brandon Aaron (http://brandonaaron.net)

 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 

 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.

 *

 * Version: 1.0.3

 * Requires jQuery 1.1.3+

 * Docs: http://docs.jquery.com/Plugins/livequery

 */



(function($) {

	

$.extend($.fn, {

	livequery: function(type, fn, fn2) {

		var self = this, q;

		

		// Handle different call patterns

		if ($.isFunction(type))

			fn2 = fn, fn = type, type = undefined;

			

		// See if Live Query already exists

		$.each( $.livequery.queries, function(i, query) {

			if ( self.selector == query.selector && self.context == query.context &&

				type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )

					// Found the query, exit the each loop

					return (q = query) && false;

		});

		

		// Create new Live Query if it wasn't found

		q = q || new $.livequery(this.selector, this.context, type, fn, fn2);

		

		// Make sure it is running

		q.stopped = false;

		

		// Run it immediately for the first time

		q.run();

		

		// Contnue the chain

		return this;

	},

	

	expire: function(type, fn, fn2) {

		var self = this;

		

		// Handle different call patterns

		if ($.isFunction(type))

			fn2 = fn, fn = type, type = undefined;

			

		// Find the Live Query based on arguments and stop it

		$.each( $.livequery.queries, function(i, query) {

			if ( self.selector == query.selector && self.context == query.context && 

				(!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped )

					$.livequery.stop(query.id);

		});

		

		// Continue the chain

		return this;

	}

});



$.livequery = function(selector, context, type, fn, fn2) {

	this.selector = selector;

	this.context  = context || document;

	this.type     = type;

	this.fn       = fn;

	this.fn2      = fn2;

	this.elements = [];

	this.stopped  = false;

	

	// The id is the index of the Live Query in $.livequery.queries

	this.id = $.livequery.queries.push(this)-1;

	

	// Mark the functions for matching later on

	fn.$lqguid = fn.$lqguid || $.livequery.guid++;

	if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;

	

	// Return the Live Query

	return this;

};



$.livequery.prototype = {

	stop: function() {

		var query = this;

		

		if ( this.type )

			// Unbind all bound events

			this.elements.unbind(this.type, this.fn);

		else if (this.fn2)

			// Call the second function for all matched elements

			this.elements.each(function(i, el) {

				query.fn2.apply(el);

			});

			

		// Clear out matched elements

		this.elements = [];

		

		// Stop the Live Query from running until restarted

		this.stopped = true;

	},

	

	run: function() {

		// Short-circuit if stopped

		if ( this.stopped ) return;

		var query = this;

		

		var oEls = this.elements,

			els  = $(this.selector, this.context),

			nEls = els.not(oEls);

		

		// Set elements to the latest set of matched elements

		this.elements = els;

		

		if (this.type) {

			// Bind events to newly matched elements

			nEls.bind(this.type, this.fn);

			

			// Unbind events to elements no longer matched

			if (oEls.length > 0)

				$.each(oEls, function(i, el) {

					if ( $.inArray(el, els) < 0 )

						$.event.remove(el, query.type, query.fn);

				});

		}

		else {

			// Call the first function for newly matched elements

			nEls.each(function() {

				query.fn.apply(this);

			});

			

			// Call the second function for elements no longer matched

			if ( this.fn2 && oEls.length > 0 )

				$.each(oEls, function(i, el) {

					if ( $.inArray(el, els) < 0 )

						query.fn2.apply(el);

				});

		}

	}

};



$.extend($.livequery, {

	guid: 0,

	queries: [],

	queue: [],

	running: false,

	timeout: null,

	

	checkQueue: function() {

		if ( $.livequery.running && $.livequery.queue.length ) {

			var length = $.livequery.queue.length;

			// Run each Live Query currently in the queue

			while ( length-- )

				$.livequery.queries[ $.livequery.queue.shift() ].run();

		}

	},

	

	pause: function() {

		// Don't run anymore Live Queries until restarted

		$.livequery.running = false;

	},

	

	play: function() {

		// Restart Live Queries

		$.livequery.running = true;

		// Request a run of the Live Queries

		$.livequery.run();

	},

	

	registerPlugin: function() {

		$.each( arguments, function(i,n) {

			// Short-circuit if the method doesn't exist

			if (!$.fn[n]) return;

			

			// Save a reference to the original method

			var old = $.fn[n];

			

			// Create a new method

			$.fn[n] = function() {

				// Call the original method

				var r = old.apply(this, arguments);

				

				// Request a run of the Live Queries

				$.livequery.run();

				

				// Return the original methods result

				return r;

			}

		});

	},

	

	run: function(id) {

		if (id != undefined) {

			// Put the particular Live Query in the queue if it doesn't already exist

			if ( $.inArray(id, $.livequery.queue) < 0 )

				$.livequery.queue.push( id );

		}

		else

			// Put each Live Query in the queue if it doesn't already exist

			$.each( $.livequery.queries, function(id) {

				if ( $.inArray(id, $.livequery.queue) < 0 )

					$.livequery.queue.push( id );

			});

		

		// Clear timeout if it already exists

		if ($.livequery.timeout) clearTimeout($.livequery.timeout);

		// Create a timeout to check the queue and actually run the Live Queries

		$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);

	},

	

	stop: function(id) {

		if (id != undefined)

			// Stop are particular Live Query

			$.livequery.queries[ id ].stop();

		else

			// Stop all Live Queries

			$.each( $.livequery.queries, function(id) {

				$.livequery.queries[ id ].stop();

			});

	}

});



// Register core DOM manipulation methods

$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');



// Run Live Queries when the Document is ready

$(function() { $.livequery.play(); });





// Save a reference to the original init method

var init = $.prototype.init;



// Create a new init method that exposes two new properties: selector and context

$.prototype.init = function(a,c) {

	// Call the original init and save the result

	var r = init.apply(this, arguments);

	

	// Copy over properties if they exist already

	if (a && a.selector)

		r.context = a.context, r.selector = a.selector;

		

	// Set properties

	if ( typeof a == 'string' )

		r.context = c || document, r.selector = a;

	

	// Return the result

	return r;

};



// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091)

$.prototype.init.prototype = $.prototype;

	

})(jQuery);