/*
Title:      jQuery.loadmore
Description:
Developer:  Antenna Praxis (http://theantenna.net)
Date:       January 2010 (From an earlier concept)
Version:    0.0.1
Usage:      
Notes:      
To Do:      
License:    Dual licensed under the MIT and GPL licenses:
            http://www.opensource.org/licenses/mit-license.php,
            http://www.gnu.org/licenses/gpl.html
*/

(function($) {
	
	$.loadmore = function(){}
	
	// defaults
	$.loadmore.defaults = {
		ajaxConfig: {}, // extra params for $.ajax
		getURL: function(data){ return false }, // find the next page url inside of data & return it
		preload: function(){}, // attach a preloader
		timeout: function(){}, // taking a long time
		nomore: function(){} // no extra page found
	};

	$.fn.loadmore = function( options )
	{
		
		var opts = $.extend($.loadmore.defaults, options), // defaults
			
			getURL = opts.getURL,
			preload = opts.preload,
			timeout = opts.timeout,
			callback = opts.callback,
			nomore = opts.nomore,
			
			isLoading = false,
			to, // timeout
			url = getURL(),
			
			$this = this; // instance
		
		var initialize = function()
		{
			// TODO : make func specific to this instance
			
			$(window).unbind('scroll.loadmore').bind('scroll.loadmore',function(e)
			{
				if(!isLoading && !$this.loadmore.disabled )
				{
					if( isAtBottom() )
					{
						if(url)
						{
							isLoading = true;
							
							preload();
							
							// slow loading msg after 10 secs
							to = setTimeout(timeout, 10000);
							
							//log('loading',url);
							$.ajax($.extend({
								url: url,
								cache:false,
								//dataType:'html',
								//data:{},
								type:'GET',
								success: function(data)
								{	
									clearTimeout(to);
									
									//log('ajax.success',data);
									$this.trigger('load.loadmore', data );
									
									isLoading = false; // MUST occur after loadmore trigger due to events order
									
									url = getURL( data );
									//log('next url', url);
									if(!url)
									{
										$(window).unbind('scroll.loadmore');
										nomore();
									}
									//else $(window).trigger('scroll.loadmore');
								},
								error: function (XMLHttpRequest, textStatus, errorThrown) {
									log('loadmore error',arguments);
									isLoading = false; // try again
								},
								xhr: function()
								{
									var xhr = jQuery.ajaxSettings.xhr();
									
									xhr.parent = this;
									//xhr.id = Math.random();
									
									xhr.onprogress = function()
									{
										// hacky way of getting XHR to accept flushed json responses
										
										if(this.readyState>=2 && this.responseText.slice(-1)==="}" && !this.parent.xhrHasFinished )
										{
											try{
												var json = $.parseJSON( this.responseText );
												
												this.parent.success(json);
												this.abort(); // abort early
												this.parent.xhrHasFinished = true; // necessary for Safari?
											}
											catch(e){
												log('response json not well formed yet');
											}
										}
									}
									
									return xhr;
								}
							}, opts.ajaxConfig));
							
						}
						
					}
						
				}
				
			
			});
			
			// call first time - not always desirable
			bump();
			
			return $this;
		};
		
		var isAtBottom = function()
		{
			// doc/win height miscalculates in IE
			return !$.browser.msie?
			 	$(window).scrollTop() == $(document).height() - $(window).height()
				: Math.abs( $(window).scrollTop() - ( $(document).height() - $(window).height() ) ) <10;
		}
		
		// PUBLIC ________________________
		
		$this.loadmore.disabled = false;
		$this.loadmore.isLoading = function(){
			return isLoading;
		}
		
		var bump = $this.loadmore.bump = function(){
			//log('bump!');
			$(window).trigger('scroll.loadmore');
		}
		
		return initialize();
	};
	
})(jQuery);